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
4ee9ef61
Commit
4ee9ef61
authored
11 years ago
by
Diana Huang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Clean up some old pep8/pylint violations
Also, deletes some unused code.
parent
3ca74c01
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
86 additions
and
105 deletions
+86
-105
common/djangoapps/course_modes/views.py
+22
-5
lms/djangoapps/verify_student/models.py
+18
-15
lms/djangoapps/verify_student/ssencrypt.py
+28
-7
lms/djangoapps/verify_student/urls.py
+0
-7
lms/djangoapps/verify_student/views.py
+18
-71
No files found.
common/djangoapps/course_modes/views.py
View file @
4ee9ef61
"""
Views for the course_mode module
"""
import
decimal
import
decimal
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
from
django.http
import
(
from
django.http
import
(
HttpResponse
,
HttpResponseBadRequest
,
HttpResponseForbidden
,
Http404
HttpResponse
BadRequest
,
Http404
)
)
from
django.shortcuts
import
redirect
from
django.shortcuts
import
redirect
from
django.views.generic.base
import
View
from
django.views.generic.base
import
View
from
django.utils.translation
import
ugettext
as
_
from
django.utils.translation
import
ugettext
as
_
from
django.utils.http
import
urlencode
from
django.contrib.auth.decorators
import
login_required
from
django.contrib.auth.decorators
import
login_required
from
django.utils.decorators
import
method_decorator
from
django.utils.decorators
import
method_decorator
...
@@ -18,10 +21,19 @@ from student.models import CourseEnrollment
...
@@ -18,10 +21,19 @@ from student.models import CourseEnrollment
from
student.views
import
course_from_id
from
student.views
import
course_from_id
from
verify_student.models
import
SoftwareSecurePhotoVerification
from
verify_student.models
import
SoftwareSecurePhotoVerification
class
ChooseModeView
(
View
):
class
ChooseModeView
(
View
):
"""
View used when the user is asked to pick a mode
When a get request is used, shows the selection page.
When a post request is used, assumes that it is a form submission
from the selection page, parses the response, and then sends user
to the next step in the flow
"""
@method_decorator
(
login_required
)
@method_decorator
(
login_required
)
def
get
(
self
,
request
,
course_id
,
error
=
None
):
def
get
(
self
,
request
,
course_id
,
error
=
None
):
""" Displays the course mode choice page """
if
CourseEnrollment
.
enrollment_mode_for_user
(
request
.
user
,
course_id
)
==
'verified'
:
if
CourseEnrollment
.
enrollment_mode_for_user
(
request
.
user
,
course_id
)
==
'verified'
:
return
redirect
(
reverse
(
'dashboard'
))
return
redirect
(
reverse
(
'dashboard'
))
modes
=
CourseMode
.
modes_for_course_dict
(
course_id
)
modes
=
CourseMode
.
modes_for_course_dict
(
course_id
)
...
@@ -34,8 +46,8 @@ class ChooseModeView(View):
...
@@ -34,8 +46,8 @@ class ChooseModeView(View):
"course_id"
:
course_id
,
"course_id"
:
course_id
,
"modes"
:
modes
,
"modes"
:
modes
,
"course_name"
:
course
.
display_name_with_default
,
"course_name"
:
course
.
display_name_with_default
,
"course_org"
:
course
.
display_org_with_default
,
"course_org"
:
course
.
display_org_with_default
,
"course_num"
:
course
.
display_number_with_default
,
"course_num"
:
course
.
display_number_with_default
,
"chosen_price"
:
chosen_price
,
"chosen_price"
:
chosen_price
,
"error"
:
error
,
"error"
:
error
,
}
}
...
@@ -48,6 +60,7 @@ class ChooseModeView(View):
...
@@ -48,6 +60,7 @@ class ChooseModeView(View):
@method_decorator
(
login_required
)
@method_decorator
(
login_required
)
def
post
(
self
,
request
,
course_id
):
def
post
(
self
,
request
,
course_id
):
""" Takes the form submission from the page and parses it """
user
=
request
.
user
user
=
request
.
user
# This is a bit redundant with logic in student.views.change_enrollement,
# This is a bit redundant with logic in student.views.change_enrollement,
...
@@ -102,6 +115,10 @@ class ChooseModeView(View):
...
@@ -102,6 +115,10 @@ class ChooseModeView(View):
)
)
def
get_requested_mode
(
self
,
user_choice
):
def
get_requested_mode
(
self
,
user_choice
):
"""
Given the text of `user_choice`, return the
corresponding course mode slug
"""
choices
=
{
choices
=
{
"Select Audit"
:
"audit"
,
"Select Audit"
:
"audit"
,
"Select Certificate"
:
"verified"
"Select Certificate"
:
"verified"
...
...
This diff is collapsed.
Click to expand it.
lms/djangoapps/verify_student/models.py
View file @
4ee9ef61
...
@@ -26,12 +26,11 @@ from django.conf import settings
...
@@ -26,12 +26,11 @@ from django.conf import settings
from
django.core.urlresolvers
import
reverse
from
django.core.urlresolvers
import
reverse
from
django.db
import
models
from
django.db
import
models
from
django.contrib.auth.models
import
User
from
django.contrib.auth.models
import
User
from
django.core.urlresolvers
import
reverse
from
model_utils.models
import
StatusModel
from
model_utils.models
import
StatusModel
from
model_utils
import
Choices
from
model_utils
import
Choices
from
verify_student.ssencrypt
import
(
from
verify_student.ssencrypt
import
(
random_aes_key
,
decode_and_decrypt
,
encrypt_and_encode
,
random_aes_key
,
encrypt_and_encode
,
generate_signed_message
,
rsa_encrypt
generate_signed_message
,
rsa_encrypt
)
)
...
@@ -57,15 +56,18 @@ def status_before_must_be(*valid_start_statuses):
...
@@ -57,15 +56,18 @@ def status_before_must_be(*valid_start_statuses):
distracting boilerplate when looking at a Model that needs to go through a
distracting boilerplate when looking at a Model that needs to go through a
workflow process.
workflow process.
"""
"""
def
decorator_func
(
fn
):
def
decorator_func
(
func
):
@functools.wraps
(
fn
)
"""
Decorator function that gets returned
"""
@functools.wraps
(
func
)
def
with_status_check
(
obj
,
*
args
,
**
kwargs
):
def
with_status_check
(
obj
,
*
args
,
**
kwargs
):
if
obj
.
status
not
in
valid_start_statuses
:
if
obj
.
status
not
in
valid_start_statuses
:
exception_msg
=
(
exception_msg
=
(
u"Error calling {} {}: status is '{}', must be one of: {}"
u"Error calling {} {}: status is '{}', must be one of: {}"
)
.
format
(
f
n
,
obj
,
obj
.
status
,
valid_start_statuses
)
)
.
format
(
f
unc
,
obj
,
obj
.
status
,
valid_start_statuses
)
raise
VerificationException
(
exception_msg
)
raise
VerificationException
(
exception_msg
)
return
f
n
(
obj
,
*
args
,
**
kwargs
)
return
f
unc
(
obj
,
*
args
,
**
kwargs
)
return
with_status_check
return
with_status_check
...
@@ -367,7 +369,7 @@ class PhotoVerification(StatusModel):
...
@@ -367,7 +369,7 @@ class PhotoVerification(StatusModel):
Status should be moved to `must_retry`.
Status should be moved to `must_retry`.
"""
"""
if
self
.
status
in
[
"approved"
,
"denied"
]:
if
self
.
status
in
[
"approved"
,
"denied"
]:
return
# If we were already approved or denied, just leave it.
return
# If we were already approved or denied, just leave it.
self
.
error_msg
=
error_msg
self
.
error_msg
=
error_msg
self
.
error_code
=
error_code
self
.
error_code
=
error_code
...
@@ -408,7 +410,7 @@ class SoftwareSecurePhotoVerification(PhotoVerification):
...
@@ -408,7 +410,7 @@ class SoftwareSecurePhotoVerification(PhotoVerification):
# encode that. The result is saved here. Actual expected length is 344.
# encode that. The result is saved here. Actual expected length is 344.
photo_id_key
=
models
.
TextField
(
max_length
=
1024
)
photo_id_key
=
models
.
TextField
(
max_length
=
1024
)
IMAGE_LINK_DURATION
=
5
*
60
*
60
*
24
# 5 days in seconds
IMAGE_LINK_DURATION
=
5
*
60
*
60
*
24
# 5 days in seconds
@status_before_must_be
(
"created"
)
@status_before_must_be
(
"created"
)
def
upload_face_image
(
self
,
img_data
):
def
upload_face_image
(
self
,
img_data
):
...
@@ -444,8 +446,8 @@ class SoftwareSecurePhotoVerification(PhotoVerification):
...
@@ -444,8 +446,8 @@ class SoftwareSecurePhotoVerification(PhotoVerification):
self
.
status
=
"must_retry"
self
.
status
=
"must_retry"
self
.
error_msg
=
response
.
text
self
.
error_msg
=
response
.
text
self
.
save
()
self
.
save
()
except
Exception
as
e
:
except
Exception
as
e
rror
:
log
.
exception
(
e
)
log
.
exception
(
e
rror
)
def
image_url
(
self
,
name
):
def
image_url
(
self
,
name
):
"""
"""
...
@@ -466,7 +468,7 @@ class SoftwareSecurePhotoVerification(PhotoVerification):
...
@@ -466,7 +468,7 @@ class SoftwareSecurePhotoVerification(PhotoVerification):
bucket
=
conn
.
get_bucket
(
settings
.
VERIFY_STUDENT
[
"SOFTWARE_SECURE"
][
"S3_BUCKET"
])
bucket
=
conn
.
get_bucket
(
settings
.
VERIFY_STUDENT
[
"SOFTWARE_SECURE"
][
"S3_BUCKET"
])
key
=
Key
(
bucket
)
key
=
Key
(
bucket
)
key
.
key
=
"{}/{}"
.
format
(
prefix
,
self
.
receipt_id
)
;
key
.
key
=
"{}/{}"
.
format
(
prefix
,
self
.
receipt_id
)
return
key
return
key
...
@@ -507,7 +509,7 @@ class SoftwareSecurePhotoVerification(PhotoVerification):
...
@@ -507,7 +509,7 @@ class SoftwareSecurePhotoVerification(PhotoVerification):
"Content-Type"
:
"application/json"
,
"Content-Type"
:
"application/json"
,
"Date"
:
formatdate
(
timeval
=
None
,
localtime
=
False
,
usegmt
=
True
)
"Date"
:
formatdate
(
timeval
=
None
,
localtime
=
False
,
usegmt
=
True
)
}
}
message
,
_
,
authorization
=
generate_signed_message
(
_message
,
_sig
,
authorization
=
generate_signed_message
(
"POST"
,
headers
,
body
,
access_key
,
secret_key
"POST"
,
headers
,
body
,
access_key
,
secret_key
)
)
headers
[
'Authorization'
]
=
authorization
headers
[
'Authorization'
]
=
authorization
...
@@ -515,16 +517,18 @@ class SoftwareSecurePhotoVerification(PhotoVerification):
...
@@ -515,16 +517,18 @@ class SoftwareSecurePhotoVerification(PhotoVerification):
return
headers
,
body
return
headers
,
body
def
request_message_txt
(
self
):
def
request_message_txt
(
self
):
""" This is the body of the request we send across """
headers
,
body
=
self
.
create_request
()
headers
,
body
=
self
.
create_request
()
header_txt
=
"
\n
"
.
join
(
header_txt
=
"
\n
"
.
join
(
"{}: {}"
.
format
(
h
,
v
)
for
h
,
v
in
sorted
(
headers
.
items
())
"{}: {}"
.
format
(
h
,
v
)
for
h
,
v
in
sorted
(
headers
.
items
())
)
)
body_txt
=
json
.
dumps
(
body
,
indent
=
2
,
sort_keys
=
True
,
ensure_ascii
=
False
)
.
encode
(
'utf-8'
)
body_txt
=
json
.
dumps
(
body
,
indent
=
2
,
sort_keys
=
True
,
ensure_ascii
=
False
)
.
encode
(
'utf-8'
)
return
header_txt
+
"
\n\n
"
+
body_txt
return
header_txt
+
"
\n\n
"
+
body_txt
def
send_request
(
self
):
def
send_request
(
self
):
""" sends the request across to the endpoint """
headers
,
body
=
self
.
create_request
()
headers
,
body
=
self
.
create_request
()
response
=
requests
.
post
(
response
=
requests
.
post
(
settings
.
VERIFY_STUDENT
[
"SOFTWARE_SECURE"
][
"API_URL"
],
settings
.
VERIFY_STUDENT
[
"SOFTWARE_SECURE"
][
"API_URL"
],
...
@@ -538,4 +542,4 @@ class SoftwareSecurePhotoVerification(PhotoVerification):
...
@@ -538,4 +542,4 @@ class SoftwareSecurePhotoVerification(PhotoVerification):
log
.
debug
(
"Return code: {}"
.
format
(
response
.
status_code
))
log
.
debug
(
"Return code: {}"
.
format
(
response
.
status_code
))
log
.
debug
(
"Return message:
\n\n
{}
\n\n
"
.
format
(
response
.
text
))
log
.
debug
(
"Return message:
\n\n
{}
\n\n
"
.
format
(
response
.
text
))
return
response
return
response
\ No newline at end of file
This diff is collapsed.
Click to expand it.
lms/djangoapps/verify_student/ssencrypt.py
View file @
4ee9ef61
...
@@ -22,16 +22,11 @@ In case of PEM encoding, the private key can be encrypted with DES or 3TDES
...
@@ -22,16 +22,11 @@ In case of PEM encoding, the private key can be encrypted with DES or 3TDES
according to a certain pass phrase. Only OpenSSL-compatible pass phrases are
according to a certain pass phrase. Only OpenSSL-compatible pass phrases are
supported.
supported.
"""
"""
from
collections
import
OrderedDict
from
email.utils
import
formatdate
from
hashlib
import
md5
,
sha256
from
hashlib
import
md5
,
sha256
from
uuid
import
uuid4
import
base64
import
base64
import
binascii
import
binascii
import
json
import
hmac
import
hmac
import
logging
import
logging
import
sys
from
Crypto
import
Random
from
Crypto
import
Random
from
Crypto.Cipher
import
AES
,
PKCS1_OAEP
from
Crypto.Cipher
import
AES
,
PKCS1_OAEP
...
@@ -39,12 +34,17 @@ from Crypto.PublicKey import RSA
...
@@ -39,12 +34,17 @@ from Crypto.PublicKey import RSA
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
def
encrypt_and_encode
(
data
,
key
):
def
encrypt_and_encode
(
data
,
key
):
""" Encrypts and endcodes `data` using `key' """
return
base64
.
urlsafe_b64encode
(
aes_encrypt
(
data
,
key
))
return
base64
.
urlsafe_b64encode
(
aes_encrypt
(
data
,
key
))
def
decode_and_decrypt
(
encoded_data
,
key
):
def
decode_and_decrypt
(
encoded_data
,
key
):
""" Decrypts and decodes `data` using `key' """
return
aes_decrypt
(
base64
.
urlsafe_b64decode
(
encoded_data
),
key
)
return
aes_decrypt
(
base64
.
urlsafe_b64decode
(
encoded_data
),
key
)
def
aes_encrypt
(
data
,
key
):
def
aes_encrypt
(
data
,
key
):
"""
"""
Return a version of the `data` that has been encrypted to
Return a version of the `data` that has been encrypted to
...
@@ -53,11 +53,16 @@ def aes_encrypt(data, key):
...
@@ -53,11 +53,16 @@ def aes_encrypt(data, key):
padded_data
=
pad
(
data
)
padded_data
=
pad
(
data
)
return
cipher
.
encrypt
(
padded_data
)
return
cipher
.
encrypt
(
padded_data
)
def
aes_decrypt
(
encrypted_data
,
key
):
def
aes_decrypt
(
encrypted_data
,
key
):
"""
Decrypt `encrypted_data` using `key`
"""
cipher
=
aes_cipher_from_key
(
key
)
cipher
=
aes_cipher_from_key
(
key
)
padded_data
=
cipher
.
decrypt
(
encrypted_data
)
padded_data
=
cipher
.
decrypt
(
encrypted_data
)
return
unpad
(
padded_data
)
return
unpad
(
padded_data
)
def
aes_cipher_from_key
(
key
):
def
aes_cipher_from_key
(
key
):
"""
"""
Given an AES key, return a Cipher object that has `encrypt()` and
Given an AES key, return a Cipher object that has `encrypt()` and
...
@@ -66,6 +71,7 @@ def aes_cipher_from_key(key):
...
@@ -66,6 +71,7 @@ def aes_cipher_from_key(key):
"""
"""
return
AES
.
new
(
key
,
AES
.
MODE_CBC
,
generate_aes_iv
(
key
))
return
AES
.
new
(
key
,
AES
.
MODE_CBC
,
generate_aes_iv
(
key
))
def
generate_aes_iv
(
key
):
def
generate_aes_iv
(
key
):
"""
"""
Return the initialization vector Software Secure expects for a given AES
Return the initialization vector Software Secure expects for a given AES
...
@@ -73,17 +79,23 @@ def generate_aes_iv(key):
...
@@ -73,17 +79,23 @@ def generate_aes_iv(key):
"""
"""
return
md5
(
key
+
md5
(
key
)
.
hexdigest
())
.
hexdigest
()[:
AES
.
block_size
]
return
md5
(
key
+
md5
(
key
)
.
hexdigest
())
.
hexdigest
()[:
AES
.
block_size
]
def
random_aes_key
():
def
random_aes_key
():
return
Random
.
new
()
.
read
(
32
)
return
Random
.
new
()
.
read
(
32
)
def
pad
(
data
):
def
pad
(
data
):
""" Pad the given `data` such that it fits into the proper AES block size """
bytes_to_pad
=
AES
.
block_size
-
len
(
data
)
%
AES
.
block_size
bytes_to_pad
=
AES
.
block_size
-
len
(
data
)
%
AES
.
block_size
return
data
+
(
bytes_to_pad
*
chr
(
bytes_to_pad
))
return
data
+
(
bytes_to_pad
*
chr
(
bytes_to_pad
))
def
unpad
(
padded_data
):
def
unpad
(
padded_data
):
""" remove all padding from `padded_data` """
num_padded_bytes
=
ord
(
padded_data
[
-
1
])
num_padded_bytes
=
ord
(
padded_data
[
-
1
])
return
padded_data
[:
-
num_padded_bytes
]
return
padded_data
[:
-
num_padded_bytes
]
def
rsa_encrypt
(
data
,
rsa_pub_key_str
):
def
rsa_encrypt
(
data
,
rsa_pub_key_str
):
"""
"""
`rsa_pub_key` is a string with the public key
`rsa_pub_key` is a string with the public key
...
@@ -93,11 +105,16 @@ def rsa_encrypt(data, rsa_pub_key_str):
...
@@ -93,11 +105,16 @@ def rsa_encrypt(data, rsa_pub_key_str):
encrypted_data
=
cipher
.
encrypt
(
data
)
encrypted_data
=
cipher
.
encrypt
(
data
)
return
encrypted_data
return
encrypted_data
def
rsa_decrypt
(
data
,
rsa_priv_key_str
):
def
rsa_decrypt
(
data
,
rsa_priv_key_str
):
"""
When given some `data` and an RSA private key, decrypt the data
"""
key
=
RSA
.
importKey
(
rsa_priv_key_str
)
key
=
RSA
.
importKey
(
rsa_priv_key_str
)
cipher
=
PKCS1_OAEP
.
new
(
key
)
cipher
=
PKCS1_OAEP
.
new
(
key
)
return
cipher
.
decrypt
(
data
)
return
cipher
.
decrypt
(
data
)
def
has_valid_signature
(
method
,
headers_dict
,
body_dict
,
access_key
,
secret_key
):
def
has_valid_signature
(
method
,
headers_dict
,
body_dict
,
access_key
,
secret_key
):
"""
"""
Given a message (either request or response), say whether it has a valid
Given a message (either request or response), say whether it has a valid
...
@@ -123,6 +140,7 @@ def has_valid_signature(method, headers_dict, body_dict, access_key, secret_key)
...
@@ -123,6 +140,7 @@ def has_valid_signature(method, headers_dict, body_dict, access_key, secret_key)
return
True
return
True
def
generate_signed_message
(
method
,
headers_dict
,
body_dict
,
access_key
,
secret_key
):
def
generate_signed_message
(
method
,
headers_dict
,
body_dict
,
access_key
,
secret_key
):
"""
"""
Returns a (message, signature) pair.
Returns a (message, signature) pair.
...
@@ -137,6 +155,7 @@ def generate_signed_message(method, headers_dict, body_dict, access_key, secret_
...
@@ -137,6 +155,7 @@ def generate_signed_message(method, headers_dict, body_dict, access_key, secret_
message
+=
'
\n
'
message
+=
'
\n
'
return
message
,
signature
,
authorization_header
return
message
,
signature
,
authorization_header
def
signing_format_message
(
method
,
headers_dict
,
body_dict
):
def
signing_format_message
(
method
,
headers_dict
,
body_dict
):
"""
"""
Given a dictionary of headers and a dictionary of the JSON for the body,
Given a dictionary of headers and a dictionary of the JSON for the body,
...
@@ -149,6 +168,7 @@ def signing_format_message(method, headers_dict, body_dict):
...
@@ -149,6 +168,7 @@ def signing_format_message(method, headers_dict, body_dict):
return
message
return
message
def
header_string
(
headers_dict
):
def
header_string
(
headers_dict
):
"""Given a dictionary of headers, return a canonical string representation."""
"""Given a dictionary of headers, return a canonical string representation."""
header_list
=
[]
header_list
=
[]
...
@@ -160,7 +180,8 @@ def header_string(headers_dict):
...
@@ -160,7 +180,8 @@ def header_string(headers_dict):
if
'Content-MD5'
in
headers_dict
:
if
'Content-MD5'
in
headers_dict
:
header_list
.
append
(
headers_dict
[
'Content-MD5'
]
+
"
\n
"
)
header_list
.
append
(
headers_dict
[
'Content-MD5'
]
+
"
\n
"
)
return
""
.
join
(
header_list
)
# Note that trailing \n's are important
return
""
.
join
(
header_list
)
# Note that trailing \n's are important
def
body_string
(
body_dict
,
prefix
=
""
):
def
body_string
(
body_dict
,
prefix
=
""
):
"""
"""
...
@@ -183,5 +204,5 @@ def body_string(body_dict, prefix=""):
...
@@ -183,5 +204,5 @@ def body_string(body_dict, prefix=""):
value
=
"null"
value
=
"null"
body_list
.
append
(
u"{}{}:{}
\n
"
.
format
(
prefix
,
key
,
value
)
.
encode
(
'utf-8'
))
body_list
.
append
(
u"{}{}:{}
\n
"
.
format
(
prefix
,
key
,
value
)
.
encode
(
'utf-8'
))
return
""
.
join
(
body_list
)
# Note that trailing \n's are important
return
""
.
join
(
body_list
)
# Note that trailing \n's are important
This diff is collapsed.
Click to expand it.
lms/djangoapps/verify_student/urls.py
View file @
4ee9ef61
...
@@ -35,11 +35,4 @@ urlpatterns = patterns(
...
@@ -35,11 +35,4 @@ urlpatterns = patterns(
name
=
"verify_student_results_callback"
,
name
=
"verify_student_results_callback"
,
),
),
url
(
r'^show_verification_page/(?P<course_id>[^/]+/[^/]+/[^/]+)$'
,
views
.
show_verification_page
,
name
=
"verify_student/show_verification_page"
),
)
)
This diff is collapsed.
Click to expand it.
lms/djangoapps/verify_student/views.py
View file @
4ee9ef61
"""
"""
Views for the verification flow
"""
"""
import
json
import
json
...
@@ -37,6 +37,12 @@ class VerifyView(View):
...
@@ -37,6 +37,12 @@ class VerifyView(View):
@method_decorator
(
login_required
)
@method_decorator
(
login_required
)
def
get
(
self
,
request
,
course_id
):
def
get
(
self
,
request
,
course_id
):
"""
"""
Displays the main verification view, which contains three separate steps:
- Taking the standard face photo
- Taking the id photo
- Confirming that the photos and payment price are correct
before proceeding to payment
"""
"""
# If the user has already been verified within the given time period,
# If the user has already been verified within the given time period,
# redirect straight to the payment -- no need to verify again.
# redirect straight to the payment -- no need to verify again.
...
@@ -69,8 +75,8 @@ class VerifyView(View):
...
@@ -69,8 +75,8 @@ class VerifyView(View):
"user_full_name"
:
request
.
user
.
profile
.
name
,
"user_full_name"
:
request
.
user
.
profile
.
name
,
"course_id"
:
course_id
,
"course_id"
:
course_id
,
"course_name"
:
course
.
display_name_with_default
,
"course_name"
:
course
.
display_name_with_default
,
"course_org"
:
course
.
display_org_with_default
,
"course_org"
:
course
.
display_org_with_default
,
"course_num"
:
course
.
display_number_with_default
,
"course_num"
:
course
.
display_number_with_default
,
"purchase_endpoint"
:
get_purchase_endpoint
(),
"purchase_endpoint"
:
get_purchase_endpoint
(),
"suggested_prices"
:
[
"suggested_prices"
:
[
decimal
.
Decimal
(
price
)
decimal
.
Decimal
(
price
)
...
@@ -106,8 +112,8 @@ class VerifiedView(View):
...
@@ -106,8 +112,8 @@ class VerifiedView(View):
context
=
{
context
=
{
"course_id"
:
course_id
,
"course_id"
:
course_id
,
"course_name"
:
course
.
display_name_with_default
,
"course_name"
:
course
.
display_name_with_default
,
"course_org"
:
course
.
display_org_with_default
,
"course_org"
:
course
.
display_org_with_default
,
"course_num"
:
course
.
display_number_with_default
,
"course_num"
:
course
.
display_number_with_default
,
"purchase_endpoint"
:
get_purchase_endpoint
(),
"purchase_endpoint"
:
get_purchase_endpoint
(),
"currency"
:
verify_mode
.
currency
.
upper
(),
"currency"
:
verify_mode
.
currency
.
upper
(),
"chosen_price"
:
chosen_price
,
"chosen_price"
:
chosen_price
,
...
@@ -162,8 +168,9 @@ def create_order(request):
...
@@ -162,8 +168,9 @@ def create_order(request):
return
HttpResponse
(
json
.
dumps
(
params
),
content_type
=
"text/json"
)
return
HttpResponse
(
json
.
dumps
(
params
),
content_type
=
"text/json"
)
@require_POST
@require_POST
@csrf_exempt
# SS does its own message signing, and their API won't have a cookie value
@csrf_exempt
# SS does its own message signing, and their API won't have a cookie value
def
results_callback
(
request
):
def
results_callback
(
request
):
"""
"""
Software Secure will call this callback to tell us whether a user is
Software Secure will call this callback to tell us whether a user is
...
@@ -194,7 +201,7 @@ def results_callback(request):
...
@@ -194,7 +201,7 @@ def results_callback(request):
settings
.
VERIFY_STUDENT
[
"SOFTWARE_SECURE"
][
"API_SECRET_KEY"
]
settings
.
VERIFY_STUDENT
[
"SOFTWARE_SECURE"
][
"API_SECRET_KEY"
]
)
)
_
,
access_key_and_sig
=
headers
[
"Authorization"
]
.
split
(
" "
)
_
response
,
access_key_and_sig
=
headers
[
"Authorization"
]
.
split
(
" "
)
access_key
=
access_key_and_sig
.
split
(
":"
)[
0
]
access_key
=
access_key_and_sig
.
split
(
":"
)[
0
]
# This is what we should be doing...
# This is what we should be doing...
...
@@ -234,10 +241,11 @@ def results_callback(request):
...
@@ -234,10 +241,11 @@ def results_callback(request):
return
HttpResponse
(
"OK!"
)
return
HttpResponse
(
"OK!"
)
@login_required
@login_required
def
show_requirements
(
request
,
course_id
):
def
show_requirements
(
request
,
course_id
):
"""
"""
Show the requirements necessary for
Show the requirements necessary for
the verification flow.
"""
"""
if
CourseEnrollment
.
enrollment_mode_for_user
(
request
.
user
,
course_id
)
==
'verified'
:
if
CourseEnrollment
.
enrollment_mode_for_user
(
request
.
user
,
course_id
)
==
'verified'
:
return
redirect
(
reverse
(
'dashboard'
))
return
redirect
(
reverse
(
'dashboard'
))
...
@@ -246,69 +254,8 @@ def show_requirements(request, course_id):
...
@@ -246,69 +254,8 @@ def show_requirements(request, course_id):
context
=
{
context
=
{
"course_id"
:
course_id
,
"course_id"
:
course_id
,
"course_name"
:
course
.
display_name_with_default
,
"course_name"
:
course
.
display_name_with_default
,
"course_org"
:
course
.
display_org_with_default
,
"course_org"
:
course
.
display_org_with_default
,
"course_num"
:
course
.
display_number_with_default
,
"course_num"
:
course
.
display_number_with_default
,
"is_not_active"
:
not
request
.
user
.
is_active
,
"is_not_active"
:
not
request
.
user
.
is_active
,
}
}
return
render_to_response
(
"verify_student/show_requirements.html"
,
context
)
return
render_to_response
(
"verify_student/show_requirements.html"
,
context
)
def
show_verification_page
(
request
):
pass
def
enroll
(
user
,
course_id
,
mode_slug
):
"""
Enroll the user in a course for a certain mode.
This is the view you send folks to when they click on the enroll button.
This does NOT cover changing enrollment modes -- it's intended for new
enrollments only, and will just redirect to the dashboard if it detects
that an enrollment already exists.
"""
# If the user is already enrolled, jump to the dashboard. Yeah, we could
# do upgrades here, but this method is complicated enough.
if
CourseEnrollment
.
is_enrolled
(
user
,
course_id
):
return
HttpResponseRedirect
(
reverse
(
'dashboard'
))
available_modes
=
CourseModes
.
modes_for_course
(
course_id
)
# If they haven't chosen a mode...
if
not
mode_slug
:
# Does this course support multiple modes of Enrollment? If so, redirect
# to a page that lets them choose which mode they want.
if
len
(
available_modes
)
>
1
:
return
HttpResponseRedirect
(
reverse
(
'choose_enroll_mode'
,
kwargs
=
{
'course_id'
:
course_id
})
)
# Otherwise, we use the only mode that's supported...
else
:
mode_slug
=
available_modes
[
0
]
.
slug
# If the mode is one of the simple, non-payment ones, do the enrollment and
# send them to their dashboard.
if
mode_slug
in
(
"honor"
,
"audit"
):
CourseEnrollment
.
enroll
(
user
,
course_id
,
mode
=
mode_slug
)
return
HttpResponseRedirect
(
reverse
(
'dashboard'
))
if
mode_slug
==
"verify"
:
if
SoftwareSecurePhotoVerification
.
has_submitted_recent_request
(
user
):
# Capture payment info
# Create an order
# Create a VerifiedCertificate order item
return
HttpResponse
.
Redirect
(
reverse
(
'verified'
))
# There's always at least one mode available (default is "honor"). If they
# haven't specified a mode, we just assume it's
if
not
mode
:
mode
=
available_modes
[
0
]
elif
len
(
available_modes
)
==
1
:
if
mode
!=
available_modes
[
0
]:
raise
Exception
()
mode
=
available_modes
[
0
]
if
mode
==
"honor"
:
CourseEnrollment
.
enroll
(
user
,
course_id
)
return
HttpResponseRedirect
(
reverse
(
'dashboard'
))
This diff is collapsed.
Click to expand it.
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