124 lines
4.2 KiB
Python
124 lines
4.2 KiB
Python
"""
|
|
Views served by the Agreements app
|
|
"""
|
|
|
|
from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication
|
|
from rest_framework import status
|
|
from rest_framework.views import APIView
|
|
from rest_framework.response import Response
|
|
from rest_framework.authentication import SessionAuthentication
|
|
from rest_framework.permissions import IsAuthenticated
|
|
from opaque_keys.edx.keys import CourseKey
|
|
|
|
from common.djangoapps.student import auth
|
|
from common.djangoapps.student.roles import CourseStaffRole
|
|
from openedx.core.djangoapps.agreements.api import (
|
|
create_integrity_signature,
|
|
get_integrity_signature,
|
|
)
|
|
from openedx.core.djangoapps.agreements.serializers import IntegritySignatureSerializer
|
|
from openedx.core.djangoapps.agreements.toggles import is_integrity_signature_enabled
|
|
|
|
|
|
def is_user_course_or_global_staff(user, course_id):
|
|
"""
|
|
Return whether a user is course staff for a given course, described by the course_id,
|
|
or is global staff.
|
|
"""
|
|
|
|
return user.is_staff or auth.user_has_role(user, CourseStaffRole(CourseKey.from_string(course_id)))
|
|
|
|
|
|
class AuthenticatedAPIView(APIView):
|
|
"""
|
|
Authenticated API View.
|
|
"""
|
|
authentication_classes = (SessionAuthentication, JwtAuthentication)
|
|
permission_classes = (IsAuthenticated,)
|
|
|
|
|
|
class IntegritySignatureView(AuthenticatedAPIView):
|
|
"""
|
|
Endpoint for an Integrity Signature
|
|
/integrity_signature/{course_id}
|
|
|
|
Supports:
|
|
HTTP GET: Returns an existing signed integrity agreement (by course id and user)
|
|
|
|
HTTP GET
|
|
** Scenarios **
|
|
?username=xyz
|
|
returns an existing signed integrity agreement for the given user and course
|
|
|
|
HTTP POST
|
|
* If an integrity signature does not exist for the user + course, creates one and
|
|
returns it. If one does exist, returns the existing signature.
|
|
"""
|
|
|
|
def get(self, request, course_id):
|
|
"""
|
|
In order to check whether the user has signed the integrity agreement for a given course.
|
|
|
|
Should return the following:
|
|
username (str)
|
|
course_id (str)
|
|
created_at (str)
|
|
|
|
If a username is not given, it should default to the requesting user (or masqueraded user).
|
|
Only staff should be able to access this endpoint for other users.
|
|
"""
|
|
# check that waffle flag is enabled
|
|
if not is_integrity_signature_enabled(CourseKey.from_string(course_id)):
|
|
return Response(
|
|
status=status.HTTP_404_NOT_FOUND,
|
|
)
|
|
|
|
# check that user can make request
|
|
user = request.user.username
|
|
requested_user = request.GET.get('username')
|
|
is_staff = is_user_course_or_global_staff(request.user, course_id)
|
|
|
|
if not is_staff and requested_user and (user != requested_user):
|
|
return Response(
|
|
status=status.HTTP_403_FORBIDDEN,
|
|
data={
|
|
"message": "User does not have permission to view integrity agreement."
|
|
}
|
|
)
|
|
|
|
username = requested_user if requested_user else user
|
|
signature = get_integrity_signature(username, course_id)
|
|
|
|
if signature is None:
|
|
return Response(
|
|
status=status.HTTP_404_NOT_FOUND,
|
|
)
|
|
|
|
serializer = IntegritySignatureSerializer(signature)
|
|
return Response(serializer.data)
|
|
|
|
def post(self, request, course_id):
|
|
"""
|
|
Create an integrity signature for the requesting user and course. If a signature
|
|
already exists, returns the existing signature instead of creating a new one.
|
|
|
|
/api/agreements/v1/integrity_signature/{course_id}
|
|
|
|
Example response:
|
|
{
|
|
username: "janedoe",
|
|
course_id: "org.2/course_2/Run_2",
|
|
created_at: "2021-04-23T18:25:43.511Z"
|
|
}
|
|
"""
|
|
# check that waffle flag is enabled
|
|
if not is_integrity_signature_enabled(CourseKey.from_string(course_id)):
|
|
return Response(
|
|
status=status.HTTP_404_NOT_FOUND,
|
|
)
|
|
|
|
username = request.user.username
|
|
signature = create_integrity_signature(username, course_id)
|
|
serializer = IntegritySignatureSerializer(signature)
|
|
return Response(serializer.data)
|