* fix: add placeholder should_display_status_to_user * fix: have VerificationAttempt inherit StatusModel - should_display_status_to_user now returns False * chore: makemigrations * feat: status_changed field added * temp: idea to add should_display_status_to_user * feat: add should_display_status_to_user * fix: correct call in helpers+services * chore: lint+test fix * fix: default hide_status_user as False * chore: rename field call to STATUS * chore: remove extra status field - comment cleanup * temp: lint + comment out created status for now * fix: revamp status_changed for back-compat * fix: override save for status_changed * fix: replace created/updated instead of status - also made migrations * fix: squash commits - also remove extra updated_at property * chore: nits
175 lines
5.8 KiB
Python
175 lines
5.8 KiB
Python
"""
|
|
API module.
|
|
"""
|
|
import logging
|
|
|
|
from django.conf import settings
|
|
from django.contrib.auth import get_user_model
|
|
from django.utils.translation import gettext as _
|
|
|
|
from datetime import datetime
|
|
from typing import Optional
|
|
|
|
from lms.djangoapps.verify_student.emails import send_verification_approved_email
|
|
from lms.djangoapps.verify_student.exceptions import VerificationAttemptInvalidStatus
|
|
from lms.djangoapps.verify_student.models import VerificationAttempt
|
|
from lms.djangoapps.verify_student.signals.signals import (
|
|
emit_idv_attempt_approved_event,
|
|
emit_idv_attempt_created_event,
|
|
emit_idv_attempt_denied_event,
|
|
emit_idv_attempt_pending_event,
|
|
)
|
|
from lms.djangoapps.verify_student.statuses import VerificationAttemptStatus
|
|
from lms.djangoapps.verify_student.tasks import send_verification_status_email
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
User = get_user_model()
|
|
|
|
|
|
def send_approval_email(attempt):
|
|
"""
|
|
Send an approval email to the learner associated with the IDV attempt.
|
|
"""
|
|
verification_status_email_vars = {
|
|
'platform_name': settings.PLATFORM_NAME,
|
|
}
|
|
|
|
expiration_datetime = attempt.expiration_datetime.date()
|
|
if settings.VERIFY_STUDENT.get('USE_DJANGO_MAIL'):
|
|
verification_status_email_vars['expiration_datetime'] = expiration_datetime.strftime("%m/%d/%Y")
|
|
verification_status_email_vars['full_name'] = attempt.user.profile.name
|
|
subject = _("Your {platform_name} ID verification was approved!").format(
|
|
platform_name=settings.PLATFORM_NAME
|
|
)
|
|
context = {
|
|
'subject': subject,
|
|
'template': 'emails/passed_verification_email.txt',
|
|
'email': attempt.user.email,
|
|
'email_vars': verification_status_email_vars
|
|
}
|
|
send_verification_status_email.delay(context)
|
|
else:
|
|
email_context = {'user': attempt.user, 'expiration_datetime': expiration_datetime.strftime("%m/%d/%Y")}
|
|
send_verification_approved_email(context=email_context)
|
|
|
|
|
|
def create_verification_attempt(
|
|
user: User,
|
|
name: str,
|
|
status: str,
|
|
expiration_datetime: Optional[datetime] = None,
|
|
hide_status_from_user: Optional[bool] = False,
|
|
):
|
|
"""
|
|
Create a verification attempt.
|
|
|
|
This method is intended to be used by IDV implementation plugins to create VerificationAttempt instances.
|
|
|
|
Args:
|
|
user (User): the user (usually a learner) performing the verification attempt
|
|
name (string): the name being ID verified
|
|
status (string): the initial status of the verification attempt
|
|
expiration_datetime (datetime, optional): When the verification attempt expires. Defaults to None.
|
|
|
|
Returns:
|
|
id (int): The id of the created VerificationAttempt instance
|
|
"""
|
|
verification_attempt = VerificationAttempt.objects.create(
|
|
user=user,
|
|
name=name,
|
|
status=status,
|
|
expiration_datetime=expiration_datetime,
|
|
hide_status_from_user=hide_status_from_user,
|
|
)
|
|
|
|
emit_idv_attempt_created_event(
|
|
attempt_id=verification_attempt.id,
|
|
user=user,
|
|
status=status,
|
|
name=name,
|
|
expiration_date=expiration_datetime,
|
|
)
|
|
|
|
return verification_attempt.id
|
|
|
|
|
|
def update_verification_attempt(
|
|
attempt_id: int,
|
|
name: Optional[str] = None,
|
|
status: Optional[str] = None,
|
|
expiration_datetime: Optional[datetime] = None,
|
|
):
|
|
"""
|
|
Update a verification attempt.
|
|
|
|
This method is intended to be used by IDV implementation plugins to update VerificationAttempt instances.
|
|
|
|
Arguments:
|
|
* attempt_id (int): the verification attempt id of the attempt to update
|
|
* name (string, optional): the new name being ID verified
|
|
* status (string, optional): the new status of the verification attempt
|
|
* expiration_datetime (datetime, optional): The new expiration date and time
|
|
|
|
Returns:
|
|
* None
|
|
"""
|
|
try:
|
|
attempt = VerificationAttempt.objects.get(id=attempt_id)
|
|
except VerificationAttempt.DoesNotExist:
|
|
log.error(
|
|
f'VerificationAttempt with id {attempt_id} was not found '
|
|
f'when updating the attempt to status={status}',
|
|
)
|
|
raise
|
|
|
|
if name is not None:
|
|
attempt.name = name
|
|
|
|
if status is not None:
|
|
attempt.status = status
|
|
|
|
status_list = list(VerificationAttemptStatus)
|
|
if status not in status_list:
|
|
log.error(
|
|
'Attempted to call update_verification_attempt called with invalid status: %(status)s. '
|
|
'Status must be one of: %(status_list)s',
|
|
{
|
|
'status': status,
|
|
'status_list': VerificationAttempt.STATUS,
|
|
},
|
|
)
|
|
raise VerificationAttemptInvalidStatus
|
|
|
|
# NOTE: Generally, we only set the expiration date from the time that an IDV attempt is marked approved,
|
|
# so we allow expiration_datetime to = None for other status updates (e.g. pending).
|
|
attempt.expiration_datetime = expiration_datetime
|
|
|
|
attempt.save()
|
|
|
|
user = attempt.user
|
|
if status == VerificationAttemptStatus.PENDING:
|
|
emit_idv_attempt_pending_event(
|
|
attempt_id=attempt_id,
|
|
user=user,
|
|
status=status,
|
|
name=name,
|
|
expiration_date=expiration_datetime,
|
|
)
|
|
elif status == VerificationAttemptStatus.APPROVED:
|
|
emit_idv_attempt_approved_event(
|
|
attempt_id=attempt_id,
|
|
user=user,
|
|
status=status,
|
|
name=name,
|
|
expiration_date=expiration_datetime,
|
|
)
|
|
elif status == VerificationAttemptStatus.DENIED:
|
|
emit_idv_attempt_denied_event(
|
|
attempt_id=attempt_id,
|
|
user=user,
|
|
status=status,
|
|
name=name,
|
|
expiration_date=expiration_datetime,
|
|
)
|