diff --git a/api/api/admin/media_report.py b/api/api/admin/media_report.py index 09e8bf3ab03..f441e6665c6 100644 --- a/api/api/admin/media_report.py +++ b/api/api/admin/media_report.py @@ -16,6 +16,7 @@ from elasticsearch import NotFoundError from elasticsearch_dsl import Search +from api.constants.moderation import DecisionAction from api.models import ( Audio, AudioDecision, @@ -377,6 +378,9 @@ def change_view(self, request, object_id, form_url="", extra_context=None): media_obj = self.get_object(request, object_id) if media_obj: extra_context["media_obj"] = media_obj + else: + messages.warning(request, f"No media object found with ID {object_id}.") + return redirect(f"admin:api_{self.media_type}_changelist") tags_by_provider = {} if tags := media_obj.tags: @@ -440,6 +444,10 @@ def decision_create_view(self, request, object_id): if request.method == "POST": media_obj = self.get_object(request, object_id) + through_model = { + "image": ImageDecisionThrough, + "audio": AudioDecisionThrough, + }[self.media_type] form = get_decision_form(self.media_type)(request.POST) if form.is_valid(): decision = form.save(commit=False) @@ -454,9 +462,13 @@ def decision_create_view(self, request, object_id): moderator=request.user.get_username(), ) - decision.media_objs.add(media_obj) + through = through_model.objects.create( + decision=decision, + media_obj=media_obj, + ) logger.info( - "Media linked to decision", + "Through model created", + through=through.id, decision=decision.id, media_obj=media_obj.id, ) @@ -468,6 +480,22 @@ def decision_create_view(self, request, object_id): report_count=count, decision=decision.id, ) + + if decision.action in { + DecisionAction.DEINDEXED_COPYRIGHT, + DecisionAction.DEINDEXED_SENSITIVE, + }: + messages.info( + request, + "The media object has been deindexed from ES and deleted from DB.", + ) + return redirect(f"admin:api_{self.media_type}_changelist") + + if decision.action == DecisionAction.MARKED_SENSITIVE: + messages.info( + request, + "The media object has been marked as sensitive.", + ) else: logger.warning( "Form is invalid", diff --git a/api/api/models/audio.py b/api/api/models/audio.py index 3f7a4637b08..c5f7cc1e9dd 100644 --- a/api/api/models/audio.py +++ b/api/api/models/audio.py @@ -363,6 +363,10 @@ class AudioDecisionThrough(AbstractMediaDecisionThrough): be referenced by `identifier` rather than an arbitrary `id`. """ + media_class = Audio + sensitive_media_class = SensitiveAudio + deleted_media_class = DeletedAudio + media_obj = models.ForeignKey( Audio, to_field="identifier", diff --git a/api/api/models/image.py b/api/api/models/image.py index 873f7ad3a69..b107b41caed 100644 --- a/api/api/models/image.py +++ b/api/api/models/image.py @@ -166,6 +166,10 @@ class ImageDecisionThrough(AbstractMediaDecisionThrough): be referenced by `identifier` rather than an arbitrary `id`. """ + media_class = Image + sensitive_media_class = SensitiveImage + deleted_media_class = DeletedImage + media_obj = models.ForeignKey( Image, to_field="identifier", diff --git a/api/api/models/media.py b/api/api/models/media.py index 2bccfea1124..fc5c290b09d 100644 --- a/api/api/models/media.py +++ b/api/api/models/media.py @@ -335,8 +335,6 @@ class AbstractMediaDecision(OpenLedgerModel): class Meta: abstract = True - # TODO: Implement ``clean`` and ``save``, if needed. - class AbstractMediaDecisionThrough(models.Model): """ @@ -348,6 +346,10 @@ class AbstractMediaDecisionThrough(models.Model): media_class: type[models.Model] = None """the model class associated with this media type e.g. ``Image`` or ``Audio``""" + sensitive_media_class: type[models.Model] = None + """the model class associated with this media type e.g. ``SensitiveImage`` or ``SensitiveAudio``""" + deleted_media_class: type[models.Model] = None + """the model class associated with this media type e.g. ``DeletedImage`` or ``DeletedAudio``""" media_obj = models.ForeignKey( AbstractMedia, @@ -361,6 +363,24 @@ class AbstractMediaDecisionThrough(models.Model): class Meta: abstract = True + def perform_action(self, action=None): + """Perform the action specified in the decision.""" + + action = self.decision.action if action is None else action + + if action in { + DecisionAction.DEINDEXED_SENSITIVE, + DecisionAction.DEINDEXED_COPYRIGHT, + }: + self.deleted_media_class.objects.create(media_obj_id=self.media_obj_id) + + if action == DecisionAction.MARKED_SENSITIVE: + self.sensitive_media_class.objects.create(media_obj_id=self.media_obj_id) + + def save(self, *args, **kwargs): + super().save(*args, **kwargs) + self.perform_action() + class PerformIndexUpdateMixin: @property