Skip to content

Commit

Permalink
Update media moderation view
Browse files Browse the repository at this point in the history
Signed-off-by: Olga Bulat <obulat@gmail.com>
  • Loading branch information
obulat committed Apr 22, 2024
1 parent 0ed4071 commit aab8c29
Show file tree
Hide file tree
Showing 3 changed files with 223 additions and 4 deletions.
164 changes: 161 additions & 3 deletions api/api/admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from django.contrib.auth.models import Group, User
from django.http.response import HttpResponseRedirect
from django.urls import reverse
from django.utils.safestring import mark_safe

from oauth2_provider.models import AccessToken

Expand Down Expand Up @@ -30,6 +31,10 @@
admin.site.register(Group, GroupAdmin)


def create_link(url: str, text: str):
return mark_safe(f'<a href="{url}">{text}</a>')


@admin.register(Image)
class ImageAdmin(admin.ModelAdmin):
search_fields = ("identifier",)
Expand All @@ -47,32 +52,185 @@ class MediaReportAdmin(admin.ModelAdmin):
"reason",
)
list_display_links = ("id",)
list_select_related = ("media_obj",)
search_fields = ("description", "media_obj__identifier")
autocomplete_fields = ("media_obj",)
actions = None
media_type = None

@admin.display(description="Title and creator")
def title(self, obj):
title = obj.media_obj.title or "Unnamed media"

if not (obj.media_obj.creator or obj.media_obj.creator_url):
return title

if obj.media_obj.creator and obj.media_obj.creator_url:
return mark_safe(
f"{title} by {create_link(obj.media_obj.creator_url, obj.media_obj.creator)}"
)
else:
creator = obj.media_obj.creator or obj.media_obj.creator_url
creator_string = f" by {creator}" if creator else ""
return f"{title}{creator_string}"

def media_display(self, obj):
pass

@admin.display(description="Media description")
def media_description(self, obj):
return obj.media_obj.meta_data.get("description")

@admin.display(description="Tags")
def tags(self, obj):
"""Display tag names grouped by provider."""
if not obj.media_obj.tags:
return ""
tags_by_provider = {}
for tag in obj.media_obj.tags:
tags_by_provider.setdefault(tag["provider"], []).append(tag["name"])
return mark_safe(
"".join(
f"<p><strong>{provider}</strong>: {', '.join(names)}</p>"
for provider, names in tags_by_provider.items()
)
)

@admin.display(description="From")
def from_field(self, obj):
return f"provider: {obj.media_obj.provider}, source: {obj.media_obj.source}"

@admin.display(description="URLs")
def landing_urls(self, obj):
if not self.media_type or not obj:
return "N/A"
openverse_url = (
f"https://openverse.org/{self.media_type}/{obj.media_obj.identifier}"
)
return mark_safe(
f"<p>{create_link(obj.media_obj.foreign_landing_url, obj.media_obj.provider)}, "
f'{create_link(openverse_url, "openverse.org")}'
)

@admin.display(description="Other reports")
def other_reports(self, obj):
"""
Display a table of other reports for the same media object.
Cannot use the ``TabularInline`` class because it requires a Parent -> Child relationship.
"""
if not self.media_type or not obj:
return ""
reports = (
self.model.objects.filter(media_obj__identifier=obj.media_obj.identifier)
.exclude(id=obj.id)
.order_by("created_at")
)
if not reports:
return ""
result = "<table><thead><tr><th>Date</th><th>Report reason</th><th>Status</th><th>Report link</th></tr></thead><tbody>"
for report in reports:
report_link_html = f'<a href="{reverse("admin:api_imagereport_change", args=[report.id])}">{report.id}</a>'
created_at = report.created_at.strftime("%Y-%m-%d %H:%M:%S")
report_row = f"<tr><td>{created_at}</td><td>{report.reason}</td><td>{report.status}</td><td>{report_link_html}</td></tr>"
result += report_row
result += "</tbody></table>"
return mark_safe(result)

def get_exclude(self, request, obj=None):
# ``identifier`` cannot be edited on an existing report.
if request.path.endswith("/change/"):
return ["media_obj"]

def get_fieldsets(self, request, obj=None):
if obj is None:
return [
(
"Report details",
{"fields": ["status", "decision", "reason", "description"]},
),
("Media details", {"fields": ["media_obj"]}),
]
return [
(
"Report details",
{
"fields": [
"created_at",
"status",
"decision",
"reason",
"description",
],
},
),
(
"Media details",
{
"fields": [
"media_display",
"title",
"tags",
"media_description",
"from_field",
"landing_urls",
"media_obj_id",
]
},
),
("Other reports", {"fields": ["other_reports"]}),
]

def get_readonly_fields(self, request, obj=None):
if obj is None:
return []
readonly_fields = [
"created_at",
"reason",
"description",
"media_display",
"title",
"tags",
"media_description",
"from_field",
"landing_urls",
"media_obj_id",
"created_at",
"other_reports",
]
# ``status`` cannot be changed on a finalised report.
if obj.status != PENDING:
readonly_fields.append("status")
return readonly_fields


admin.site.register(AudioReport, MediaReportAdmin)
admin.site.register(ImageReport, MediaReportAdmin)
@admin.register(ImageReport)
class ImageReportAdmin(MediaReportAdmin):
change_form_template = "admin/api/imagereport/change_form.html"
media_type = "image"

@admin.display(description="Media Image", ordering="media_obj__url")
def media_display(self, obj):
# Check if there's a URL and it's an image
if obj.media_obj.url:
thumb_url = f"https://api.openverse.engineering{obj.media_url()}thumb/"
return mark_safe(
f'<div class="container"><img src="{thumb_url}" alt="Media Image" class="blur-image" height="300" '
f'onclick="toggleBlur(this)" onerror="replace(this, \'{obj.media_obj.url}\')" style="cursor: pointer;" />'
f"<p> Show content </p></div>"
)
return "No Image Available"


@admin.register(AudioReport)
class AudioReportAdmin(MediaReportAdmin):
media_type = "audio"

@admin.display(description="Media Audio")
def media_display(self, obj):
if obj.media_obj.url:
return mark_safe(
f'<audio controls><source src="{obj.media_obj.url}" type="audio/mpeg">Your browser does not support the audio element.</audio>'
)
return "No Audio Available"


class MediaSubreportAdmin(admin.ModelAdmin):
Expand Down
6 changes: 5 additions & 1 deletion api/api/models/media.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ def clean(self):
f"with identifier '{self.media_obj_id}'."
)

def url(self, request=None) -> str:
def media_url(self, request=None) -> str:
"""
Build the URL of the media item. This uses ``reverse`` and
``request.build_absolute_uri`` to build the URL without having to worry
Expand All @@ -227,6 +227,10 @@ def url(self, request=None) -> str:
)
if request is not None:
url = request.build_absolute_uri(url)
return url

def url(self, request=None) -> str:
url = self.media_url(request)
return format_html(f"<a href={url}>{url}</a>")

@property
Expand Down
57 changes: 57 additions & 0 deletions api/api/templates/admin/api/imagereport/change_form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{% extends "admin/change_form.html" %}
{% load static %}

{% block extrahead %}
{{ block.super }}
<style>
.container {
display: grid;
justify-content: center;
align-items: center;
}
.container img {
grid-column: 1 / -1;
grid-row: 1 / -1;
}
.container p {
grid-column: 1 / -1;
grid-row: 1 / -1;
border-radius: 4px;
padding: 10px;
z-index:1;
pointer-events: none;
color: black;
background: rgba(255, 255, 255, 0.5);
text-align: center;
font-weight: bold;
}
.blur-image {
transition: filter 0.3s;
filter: blur(60px);
}
.no-blur {
filter: none;
}
.no-blur ~ p {
display: none;
}
</style>
{% endblock %}

{% block admin_change_form_document_ready %}
{{ block.super }}
<script>
function toggleBlur(img) {
if (img.classList.contains('no-blur')) {
img.classList.remove('no-blur');
img.classList.add('blur-image');
} else {
img.classList.remove('blur-image');
img.classList.add('no-blur');
}
}
function replace(img, url) {
img.src = url;
}
</script>
{% endblock %}

0 comments on commit aab8c29

Please sign in to comment.