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
01814c39
Commit
01814c39
authored
Dec 31, 2014
by
Will Daly
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Hide verification messaging if the user has an active verification
parent
7011e2c2
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
71 additions
and
12 deletions
+71
-12
common/djangoapps/student/helpers.py
+14
-2
common/djangoapps/student/tests/test_verification_status.py
+46
-5
lms/djangoapps/verify_student/models.py
+11
-5
No files found.
common/djangoapps/student/helpers.py
View file @
01814c39
...
@@ -163,14 +163,20 @@ def check_verify_status_by_course(user, course_enrollment_pairs, all_course_mode
...
@@ -163,14 +163,20 @@ def check_verify_status_by_course(user, course_enrollment_pairs, all_course_mode
* status (str): One of the enumerated status codes.
* status (str): One of the enumerated status codes.
* days_until_deadline (int): Number of days until the verification deadline.
* days_until_deadline (int): Number of days until the verification deadline.
* verification_good_until (str): Date string for the verification expiration date.
* verification_good_until (str): Date string for the verification expiration date.
"""
"""
status_by_course
=
{}
status_by_course
=
{}
# Retrieve all verifications for the user, sorted in descending
# Retrieve all verifications for the user, sorted in descending
# order by submission datetime
# order by submission datetime
verifications
=
SoftwareSecurePhotoVerification
.
objects
.
filter
(
user
=
user
)
verifications
=
SoftwareSecurePhotoVerification
.
objects
.
filter
(
user
=
user
)
# Check whether the user has an active or pending verification attempt
# To avoid another database hit, we re-use the queryset we have already retrieved.
has_active_or_pending
=
SoftwareSecurePhotoVerification
.
user_has_valid_or_pending
(
user
,
queryset
=
verifications
)
for
course
,
enrollment
in
course_enrollment_pairs
:
for
course
,
enrollment
in
course_enrollment_pairs
:
# Get the verified mode (if any) for this course
# Get the verified mode (if any) for this course
...
@@ -210,7 +216,13 @@ def check_verify_status_by_course(user, course_enrollment_pairs, all_course_mode
...
@@ -210,7 +216,13 @@ def check_verify_status_by_course(user, course_enrollment_pairs, all_course_mode
)
)
if
status
is
None
and
not
submitted
:
if
status
is
None
and
not
submitted
:
if
deadline
is
None
or
deadline
>
datetime
.
now
(
UTC
):
if
deadline
is
None
or
deadline
>
datetime
.
now
(
UTC
):
status
=
VERIFY_STATUS_NEED_TO_VERIFY
# If a user already has an active or pending verification,
# but it will expire by the deadline, the we do NOT show the
# verification message. This is because we don't currently
# allow users to resubmit an attempt before their current
# attempt expires.
if
not
has_active_or_pending
:
status
=
VERIFY_STATUS_NEED_TO_VERIFY
else
:
else
:
status
=
VERIFY_STATUS_MISSED_DEADLINE
status
=
VERIFY_STATUS_MISSED_DEADLINE
...
...
common/djangoapps/student/tests/test_verification_status.py
View file @
01814c39
...
@@ -193,6 +193,26 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
...
@@ -193,6 +193,26 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
# messaging relating to verification
# messaging relating to verification
self
.
_assert_course_verification_status
(
None
)
self
.
_assert_course_verification_status
(
None
)
def
test_verification_will_expire_by_deadline
(
self
):
# Expiration date in the future
self
.
_setup_mode_and_enrollment
(
self
.
FUTURE
,
"verified"
)
# Create a verification attempt that:
# 1) Is current (submitted in the last year)
# 2) Will expire by the deadline for the course
attempt
=
SoftwareSecurePhotoVerification
.
objects
.
create
(
user
=
self
.
user
)
attempt
.
mark_ready
()
attempt
.
submit
()
# This attempt will expire tomorrow, before the course deadline
attempt
.
created_at
=
attempt
.
created_at
-
timedelta
(
days
=
364
)
attempt
.
save
()
# Expect that the "verify now" message is hidden
# (since the user isn't allowed to submit another attempt while
# a verification is active).
self
.
_assert_course_verification_status
(
None
)
def
_setup_mode_and_enrollment
(
self
,
deadline
,
enrollment_mode
):
def
_setup_mode_and_enrollment
(
self
,
deadline
,
enrollment_mode
):
"""Create a course mode and enrollment.
"""Create a course mode and enrollment.
...
@@ -221,9 +241,12 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
...
@@ -221,9 +241,12 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
}
}
NOTIFICATION_MESSAGES
=
{
NOTIFICATION_MESSAGES
=
{
VERIFY_STATUS_NEED_TO_VERIFY
:
"You still need to verify for this course."
,
VERIFY_STATUS_NEED_TO_VERIFY
:
[
VERIFY_STATUS_SUBMITTED
:
"Thanks for your patience as we process your request."
,
"You still need to verify for this course."
,
VERIFY_STATUS_APPROVED
:
"You have already verified your ID!"
,
"Verification not yet complete"
],
VERIFY_STATUS_SUBMITTED
:
[
"Thanks for your patience as we process your request."
],
VERIFY_STATUS_APPROVED
:
[
"You have already verified your ID!"
],
}
}
def
_assert_course_verification_status
(
self
,
status
):
def
_assert_course_verification_status
(
self
,
status
):
...
@@ -248,7 +271,25 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
...
@@ -248,7 +271,25 @@ class TestCourseVerificationStatus(UrlResetMixin, ModuleStoreTestCase):
# Verify that the correct copy is rendered on the dashboard
# Verify that the correct copy is rendered on the dashboard
if
status
is
not
None
:
if
status
is
not
None
:
if
status
in
self
.
NOTIFICATION_MESSAGES
:
if
status
in
self
.
NOTIFICATION_MESSAGES
:
self
.
assertContains
(
response
,
self
.
NOTIFICATION_MESSAGES
[
status
])
# Different states might have different messaging
# so in some cases we check several possibilities
# and fail if none of these are found.
found_msg
=
False
for
message
in
self
.
NOTIFICATION_MESSAGES
[
status
]:
if
message
in
response
.
content
:
found_msg
=
True
break
fail_msg
=
"Could not find any of these messages: {expected}"
.
format
(
expected
=
self
.
NOTIFICATION_MESSAGES
[
status
]
)
self
.
assertTrue
(
found_msg
,
msg
=
fail_msg
)
else
:
else
:
for
msg
in
self
.
NOTIFICATION_MESSAGES
.
values
():
# Combine all possible messages into a single list
all_messages
=
[]
for
msg_group
in
self
.
NOTIFICATION_MESSAGES
.
values
():
all_messages
.
extend
(
msg_group
)
# Verify that none of the messages are displayed
for
msg
in
all_messages
:
self
.
assertNotContains
(
response
,
msg
)
self
.
assertNotContains
(
response
,
msg
)
lms/djangoapps/verify_student/models.py
View file @
01814c39
...
@@ -211,7 +211,7 @@ class PhotoVerification(StatusModel):
...
@@ -211,7 +211,7 @@ class PhotoVerification(StatusModel):
)
.
exists
()
)
.
exists
()
@classmethod
@classmethod
def
user_has_valid_or_pending
(
cls
,
user
,
earliest_allowed_date
=
None
,
window
=
None
):
def
user_has_valid_or_pending
(
cls
,
user
,
earliest_allowed_date
=
None
,
window
=
None
,
queryset
=
None
):
"""
"""
Return whether the user has a complete verification attempt that is or
Return whether the user has a complete verification attempt that is or
*might* be good. This means that it's approved, been submitted, or would
*might* be good. This means that it's approved, been submitted, or would
...
@@ -222,15 +222,21 @@ class PhotoVerification(StatusModel):
...
@@ -222,15 +222,21 @@ class PhotoVerification(StatusModel):
If window=None, this will check for the user's *initial* verification. If
If window=None, this will check for the user's *initial* verification. If
window is anything else, this will check for the reverification associated
window is anything else, this will check for the reverification associated
with that window.
with that window.
If a queryset is provided, that will be used instead of hitting the database.
"""
"""
valid_statuses
=
[
'submitted'
,
'approved'
]
valid_statuses
=
[
'submitted'
,
'approved'
]
if
not
window
:
if
not
window
:
valid_statuses
.
append
(
'must_retry'
)
valid_statuses
.
append
(
'must_retry'
)
return
cls
.
objects
.
filter
(
if
queryset
is
None
:
user
=
user
,
queryset
=
cls
.
objects
.
filter
(
user
=
user
)
return
queryset
.
filter
(
status__in
=
valid_statuses
,
status__in
=
valid_statuses
,
created_at__gte
=
(
earliest_allowed_date
created_at__gte
=
(
or
cls
.
_earliest_allowed_date
()),
earliest_allowed_date
or
cls
.
_earliest_allowed_date
()
),
window
=
window
,
window
=
window
,
)
.
exists
()
)
.
exists
()
...
...
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