Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add has_dismissed field #366

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion enterprise_access/apps/api/serializers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
from .content_assignments.assignment import (
ContentMetadataForAssignmentSerializer,
LearnerContentAssignmentAdminResponseSerializer,
LearnerContentAssignmentResponseSerializer
LearnerContentAssignmentResponseSerializer,
LearnerContentAssignmentUpdateRequestSerializer,
)
from .content_assignments.assignment_configuration import (
AssignmentConfigurationCreateRequestSerializer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class Meta:
'transaction_uuid',
'last_notification_at',
'actions',
'has_dismissed',
]
read_only_fields = fields

Expand Down Expand Up @@ -258,3 +259,33 @@ def get_content_metadata(self, obj):
if metadata_lookup and (assignment_content_metadata := metadata_lookup.get(obj.content_key)):
return ContentMetadataForAssignmentSerializer(assignment_content_metadata).data
return None

class LearnerContentAssignmentUpdateRequestSerializer(serializers.ModelSerializer):
"""
Request Serializer for PUT or PATCH requests to update a LearnerContentAssignment.

For views: LearnerContentAssignmentAdminViewSet.update and LearnerContentAssignmentAdminViewSet.partial_update.
"""
class Meta:
model = LearnerContentAssignment
fields = (
'has_dismissed',
)

def validate(self, attrs):
"""
Raises a ValidationError if any field not explicitly declared as a field in this serializer definition is
provided as input.
"""
unknown = sorted(set(self.initial_data) - set(self.fields))
if unknown:
raise serializers.ValidationError("Field(s) are not updatable: {}".format(", ".join(unknown)))
return attrs

def to_representation(self, instance):
"""
Once an LearnerContentAssignment has been updated, we want to serialize more fields from the instance than are
required in this, the input serializer.
"""
read_serializer = LearnerContentAssignmentResponseSerializer(instance)
return read_serializer.data
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,9 @@ def get_assignments_serializer(self, obj):
return []

assignments = obj.assignment_configuration.assignments.prefetch_related('actions').filter(
lms_user_id=self.context.get('lms_user_id')
lms_user_id=self.context.get('lms_user_id'),
# only return assignments that have not been dismissed
has_dismissed=False
)
content_metadata_lookup = get_content_metadata_for_assignments(obj.catalog_uuid, assignments)
context = {'content_metadata': content_metadata_lookup}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from enterprise_access.apps.api import filters, serializers, utils
from enterprise_access.apps.api.v1.views.utils import PaginationWithPageCount
from enterprise_access.apps.content_assignments.models import LearnerContentAssignment
from enterprise_access.apps.core.constants import CONTENT_ASSIGNMENT_LEARNER_READ_PERMISSION
from enterprise_access.apps.core.constants import (CONTENT_ASSIGNMENT_LEARNER_READ_PERMISSION, CONTENT_ASSIGNMENT_LEARNER_WRITE_PERMISSION)

logger = logging.getLogger(__name__)

Expand All @@ -32,6 +32,7 @@ class LearnerContentAssignmentViewSet(
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
viewsets.GenericViewSet,
mixins.UpdateModelMixin,
):
"""
Viewset supporting all learner-facing CRUD operations on ``LearnerContentAssignment`` records.
Expand All @@ -43,6 +44,16 @@ class LearnerContentAssignmentViewSet(
pagination_class = PaginationWithPageCount
lookup_field = 'uuid'

def get_serializer_class(self):
"""
Overrides the default behavior to return different serializers depending on the request action.
"""

if self.action in ('update', 'partial_update'):
return serializers.LearnerContentAssignmentUpdateRequestSerializer
# list and retrieve use the default serializer.
return self.serializer_class

@property
def requesting_user_email(self):
"""
Expand Down Expand Up @@ -98,3 +109,20 @@ def list(self, request, *args, **kwargs):
configuration.
"""
return super().list(request, *args, **kwargs)

@extend_schema(
tags=[CONTENT_ASSIGNMENT_CRUD_API_TAG],
summary='Partially update (with a PATCH) a learner assignment by UUID.',
request=serializers.LearnerContentAssignmentUpdateRequestSerializer,
responses={
status.HTTP_200_OK: None,
status.HTTP_404_NOT_FOUND: None,
status.HTTP_422_UNPROCESSABLE_ENTITY: None,
},
)
@permission_required(CONTENT_ASSIGNMENT_LEARNER_WRITE_PERMISSION, fn=assignment_permission_fn)
def partial_update(self, request, *args, uuid=None, **kwargs):
"""
Updates a single ``LearnerContentAssignment`` record by uuid. All fields for the update are optional.
"""
return super().partial_update(request, *args, uuid=uuid, **kwargs)
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 4.2.6 on 2023-12-13 08:26

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('content_assignments', '0012_assignmentaction_add_automatic_cancellation_option'),
]

operations = [
migrations.AddField(
model_name='historicallearnercontentassignment',
name='has_dismissed',
field=models.BooleanField(default=False, help_text='True if the learner dismissed alert for cancelled or expired assignments. Default to false'),
),
migrations.AddField(
model_name='learnercontentassignment',
name='has_dismissed',
field=models.BooleanField(default=False, help_text='True if the learner dismissed alert for cancelled or expired assignments. Default to false'),
),
]
4 changes: 4 additions & 0 deletions enterprise_access/apps/content_assignments/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ class Meta:
"been notified."
),
)
has_dismissed = models.BooleanField(
default=False,
help_text='True if the learner dismissed alert for cancelled or expired assignments. Default to false',
)
history = HistoricalRecords()

def __str__(self):
Expand Down
1 change: 1 addition & 0 deletions enterprise_access/apps/core/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
CONTENT_ASSIGNMENT_ADMIN_READ_PERMISSION = 'content_assignment.has_admin_read_access'
CONTENT_ASSIGNMENT_ADMIN_WRITE_PERMISSION = 'content_assignment.has_admin_write_access'
CONTENT_ASSIGNMENT_LEARNER_READ_PERMISSION = 'content_assignment.has_learner_read_access'
CONTENT_ASSIGNMENT_LEARNER_WRITE_PERMISSION = 'content_assignment.has_learner_write_access'

ALL_ACCESS_CONTEXT = '*'

Expand Down
9 changes: 9 additions & 0 deletions enterprise_access/apps/core/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,15 @@ def has_explicit_access_to_content_assignments_learner(user, enterprise_customer
),
)

rules.add_perm(
constants.CONTENT_ASSIGNMENT_LEARNER_WRITE_PERMISSION,
(
has_content_assignments_operator_access |
has_content_assignments_admin_access |
has_content_assignments_learner_access
),
)


# Grants permission to allocate assignments from a policy if the user is a content assignment configuration admin.
rules.add_perm(
Expand Down
Loading