Skip to content

Commit

Permalink
feat: integrate platform verification attempt
Browse files Browse the repository at this point in the history
  • Loading branch information
alangsto committed Sep 23, 2024
1 parent d919950 commit b1e2cb8
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 137 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Change Log
Unreleased
~~~~~~~~~~
* Add platform verification id field to the VerifiedName model
* Integrate platform verification id into app

[2.4.0] - 2024-04-23
~~~~~~~~~~~~~~~~~~~~
Expand Down
7 changes: 5 additions & 2 deletions edx_name_affirmation/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@ class VerifiedNameAdmin(admin.ModelAdmin):
"""
list_display = (
'id', 'user', 'verified_name', 'verification_attempt_id', 'proctored_exam_attempt_id',
'status', 'created', 'modified',
'platform_verification_attempt_id', 'status', 'created', 'modified',
)
readonly_fields = ('id',)
search_fields = ('user__username', 'verification_attempt_id', 'proctored_exam_attempt_id',)
search_fields = (
'user__username', 'verification_attempt_id', 'proctored_exam_attempt_id',
'platform_verification_attempt_id'
)
raw_id_fields = ('user', )


Expand Down
94 changes: 26 additions & 68 deletions edx_name_affirmation/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@

def create_verified_name(
user, verified_name, profile_name, verification_attempt_id=None,
proctored_exam_attempt_id=None, status=VerifiedNameStatus.PENDING,
proctored_exam_attempt_id=None, platform_verification_attempt_id=None,
status=VerifiedNameStatus.PENDING,
):
"""
Create a new `VerifiedName` for the given user.
Expand All @@ -34,6 +35,8 @@ def create_verified_name(
attempt.
* `proctored_exam_attempt_id` (int): Optional reference to an external proctored exam
attempt.
* `platform_verification_attempt_id` (int): Optional reference to a platform defined
verification attempt.
* `is_verified` (bool): Optional, defaults False. This should determine whether the
verified_name is valid for use with ID verification, exams, etc.
"""
Expand All @@ -44,15 +47,17 @@ def create_verified_name(
raise VerifiedNameEmptyString('profile_name', user.id)

# Only link to one attempt
if verification_attempt_id and proctored_exam_attempt_id:
if sum(map(bool, [proctored_exam_attempt_id, verification_attempt_id, platform_verification_attempt_id])) > 1:
err_msg = (
'Attempted to create VerifiedName for user_id={user_id}, but two different '
'Attempted to create VerifiedName for user_id={user_id}, but at least two different '
'external attempt IDs were given. Only one may be used. '
'verification_attempt_id={verification_attempt_id}, '
'proctored_exam_attempt_id={proctored_exam_attempt_id}, '
'platform_verification_attempt_id={platform_verification_attempt_id}, '
'status={status}'.format(
user_id=user.id, verification_attempt_id=verification_attempt_id,
proctored_exam_attempt_id=proctored_exam_attempt_id, status=status,
platform_verification_attempt_id=platform_verification_attempt_id,
)
)
raise VerifiedNameMultipleAttemptIds(err_msg)
Expand All @@ -63,6 +68,7 @@ def create_verified_name(
profile_name=profile_name,
verification_attempt_id=verification_attempt_id,
proctored_exam_attempt_id=proctored_exam_attempt_id,
platform_verification_attempt_id=platform_verification_attempt_id,
status=status,
)

Expand Down Expand Up @@ -128,62 +134,8 @@ def get_verified_name_history(user):
return VerifiedName.objects.filter(user=user).order_by('-created')


def update_verification_attempt_id(user, verification_attempt_id):
"""
Update the `verification_attempt_id` for the user's most recent VerifiedName.
If the VerifiedName already has a linked verification or proctored exam attempt, create a new
VerifiedName instead, using the same `verified_name` and `profile_name`.
This will raise an exception if the user does not have an existing VerifiedName.
Arguments:
* `user` (User object)
* `verification_attempt_id` (int)
"""
verified_name_obj = get_verified_name(user)

if not verified_name_obj:
err_msg = (
'Attempted to update most recent VerifiedName for user_id={user_id} with '
'verification_attempt_id={verification_attempt_id}, but this user does not have '
'an existing VerifiedName.'.format(
user_id=user.id, verification_attempt_id=verification_attempt_id
)
)
raise VerifiedNameDoesNotExist(err_msg)

if verified_name_obj.verification_attempt_id or verified_name_obj.proctored_exam_attempt_id:
log_msg = (
'Attempted to update VerifiedName id={id} with '
'verification_attempt_id={verification_attempt_id}, but it already has a linked attempt. '
'Creating a new VerifiedName for user_id={user_id}'.format(
id=verified_name_obj.id, verification_attempt_id=verification_attempt_id, user_id=user.id,
)
)
log.warning(log_msg)

create_verified_name(
user=user,
verified_name=verified_name_obj.verified_name,
profile_name=verified_name_obj.profile_name,
verification_attempt_id=verification_attempt_id,
)

verified_name_obj.verification_attempt_id = verification_attempt_id
verified_name_obj.save()

log_msg = (
'Updated VerifiedName id={id} with verification_attempt_id={verification_attempt_id} '
'for user_id={user_id}'.format(
id=verified_name_obj.id, verification_attempt_id=verification_attempt_id, user_id=user.id,
)
)
log.info(log_msg)


def update_verified_name_status(
user, status, verification_attempt_id=None, proctored_exam_attempt_id=None
user, status, verification_attempt_id=None, proctored_exam_attempt_id=None, platform_verification_attempt_id=None,
):
"""
Update the status of a VerifiedName using the linked ID verification or exam attempt ID. Only one
Expand All @@ -194,23 +146,29 @@ def update_verified_name_status(
* status (Verified Name Status)
* verification_attempt_id (int)
* proctored_exam_attempt_id (int)
* platform_verification_attempt_id (int)
"""
filters = {'user': user}

if verification_attempt_id:
if proctored_exam_attempt_id:
err_msg = (
'Attempted to update the status for a VerifiedName, but two different '
'attempt IDs were given. verification_attempt_id={verification_attempt_id}, '
'proctored_exam_attempt_id={proctored_exam_attempt_id}'.format(
verification_attempt_id=verification_attempt_id,
proctored_exam_attempt_id=proctored_exam_attempt_id,
)
if sum(map(bool, [proctored_exam_attempt_id, verification_attempt_id, platform_verification_attempt_id])) > 1:
err_msg = (
'Attempted to update the status for a VerifiedName, but at least two different '
'attempt IDs were given. verification_attempt_id={verification_attempt_id}, '
'proctored_exam_attempt_id={proctored_exam_attempt_id},'
'platform_verification_attempt_id={platform_verification_attempt_id}'.format(
verification_attempt_id=verification_attempt_id,
proctored_exam_attempt_id=proctored_exam_attempt_id,
platform_verification_attempt_id=platform_verification_attempt_id,
)
raise VerifiedNameMultipleAttemptIds(err_msg)
)
raise VerifiedNameMultipleAttemptIds(err_msg)

if verification_attempt_id:
filters['verification_attempt_id'] = verification_attempt_id
elif proctored_exam_attempt_id:
filters['proctored_exam_attempt_id'] = proctored_exam_attempt_id
elif platform_verification_attempt_id:
filters['platform_verification_attempt_id'] = platform_verification_attempt_id
else:
err_msg = (
'Attempted to update the status for a VerifiedName, but no '
Expand Down
17 changes: 17 additions & 0 deletions edx_name_affirmation/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@

try:
from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification
from lms.djangoapps.verify_studnet.models import VerificationAttempt as PlatformVerificationAttempt

Check failure on line 17 in edx_name_affirmation/models.py

View workflow job for this annotation

GitHub Actions / Tests (ubuntu-20.04, 3.11, 10, django42)

Missing coverage

Missing coverage on line 17
except ImportError:
SoftwareSecurePhotoVerification = None
PlatformVerificationAttempt = None

User = get_user_model()

Expand Down Expand Up @@ -77,6 +79,21 @@ def verification_attempt_status(self):
except ObjectDoesNotExist:
return None

@property
def platform_verification_attempt_status(self):
"""
Returns the status associated with its platform VerificationAttempt
"""
if not self.platform_verification_attempt_id or not PlatformVerificationAttempt:
return None

try:
verification = PlatformVerificationAttempt.objects.get(id=self.platform_verification_attempt_id)
return verification.status

except ObjectDoesNotExist:
return None

def save(self, *args, **kwargs):
"""
Validate only one of `verification_attempt_id` or `platform_verification_attempt_id`
Expand Down
5 changes: 4 additions & 1 deletion edx_name_affirmation/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class VerifiedNameSerializer(serializers.ModelSerializer):
verification_attempt_status = serializers.CharField(required=False, allow_null=True)
proctored_exam_attempt_id = serializers.IntegerField(required=False, allow_null=True)
status = serializers.CharField(required=False, allow_null=True)
platform_verification_attempt_id = serializers.IntegerField(required=False, allow_null=True)
platform_verification_attempt_status = serializers.CharField(required=False, allow_null=True)

class Meta:
"""
Expand All @@ -31,7 +33,8 @@ class Meta:

fields = (
"id", "created", "username", "verified_name", "profile_name", "verification_attempt_id",
"verification_attempt_status", "proctored_exam_attempt_id", "status"
"verification_attempt_status", "proctored_exam_attempt_id", "platform_verification_attempt_id",
"platform_verification_attempt_status", "status"
)

def validate_verified_name(self, verified_name):
Expand Down
Loading

0 comments on commit b1e2cb8

Please sign in to comment.