Skip to content

Commit

Permalink
Merge pull request #6380 from akatsoulas/moderation-product-filter
Browse files Browse the repository at this point in the history
Filter moderation queue per product
  • Loading branch information
akatsoulas authored Nov 28, 2024
2 parents c7260c7 + 0678603 commit 65cc113
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 45 deletions.
12 changes: 12 additions & 0 deletions kitsune/flagit/jinja2/flagit/content_moderation.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{% extends "flagit/flagit_base.html" %}
{% from "flagit/includes/macros.html" import filter_dropdown %}

{% block flagged_items %}
{% for object in objects %}
Expand Down Expand Up @@ -39,6 +40,17 @@ <h3 class="sumo-card-heading"><br>{{ _('Update Status:') }}</h3>
{% endfor %}
{% endblock %}

{% block filter_dropdown %}
{{ filter_dropdown(
form_id='product-filter-form',
select_id='flagit-product-filter',
label='Filter by product:',
name='product',
default_option='All products',
options=products,
selected_filter=selected_product
) }}
{% endblock %}
{# Hide the deactivation log on content moderation #}
{% block deactivation_log %}
{% endblock %}
6 changes: 3 additions & 3 deletions kitsune/flagit/jinja2/flagit/flagit_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

{% block content %}
<div id="flagged-queue" class="sumo-page-section">
<h1 class="sumo-page-heading">{{ _('Content Pending Moderation') }}</h1>

<h1 class="sumo-page-heading">{{ _('Content Pending Moderation') }}</h1>
<ul class="flagged-items">
{% block flagged_items %}
{% endblock %}
Expand All @@ -26,7 +26,7 @@ <h1 class="sumo-page-heading">{{ _('Content Pending Moderation') }}</h1>
{{ for_contributors_sidebar(user, settings.WIKI_DEFAULT_LANGUAGE, active="flagit.flagged_queue", menu="contributor-tools", locale=locale) }}
</ul>

{% block side_top_reason %}
{% block filter_dropdown %}
{% endblock %}
</nav>
{% endblock %}
16 changes: 16 additions & 0 deletions kitsune/flagit/jinja2/flagit/includes/macros.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,19 @@
{{date}} by <a rel="nofollow" href="{{url}}">{{user}}</a>
{% endtrans %}
{%- endmacro %}

{% macro filter_dropdown(form_id, select_id, label, name, default_option, options, selected_filter) %}
<div class="filter-dropdown">
<form id="{{ form_id }}" method="get" action="">
<label for="{{ name }}">{{ label }}</label>
<select name="{{ name }}" id="{{ select_id }}">
<option value="">{{ default_option }}</option>
{% for value, display in options %}
<option value="{{ value }}" {% if selected_filter == value %}selected{% endif %}>
{{ display }}
</option>
{% endfor %}
</select>
</form>
</div>
{% endmacro %}
16 changes: 3 additions & 13 deletions kitsune/flagit/jinja2/flagit/queue.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{% extends "flagit/flagit_base.html" %}
{% from "flagit/includes/macros.html" import filter_dropdown %}

{% block flagged_items %}
{% for object in objects %}
Expand Down Expand Up @@ -49,17 +50,6 @@ <h3 class="sumo-card-heading"><br>{{ _('Update Status:') }}</h3>
{% endfor %}
{% endblock %}

{% block side_top_reason %}
<!-- Dropdown filter for reasons -->
<div class="filter-reasons">
<form id="reason-filter-form" method="get" action="">
<label for="reason">{{ _('Filter by reason:') }}</label>
<select name="reason" id="flagit-reason-filter">
<option value="">{{ _('All reasons') }}</option>
{% for value, display in reasons %}
<option value="{{ value }}" {% if selected_reason == value %}selected{% endif %}>{{ display }}</option>
{% endfor %}
</select>
</form>
</div>
{% block filter_dropdown %}
{{ filter_dropdown("reason-filter-form", "flagit-reason-filter", "Filter by reason:", "reason", "All reasons", reasons, selected_reason) }}
{% endblock %}
21 changes: 17 additions & 4 deletions kitsune/flagit/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@

from kitsune.access.decorators import login_required, permission_required
from kitsune.flagit.models import FlaggedObject
from kitsune.products.models import Topic
from kitsune.products.models import Product, Topic
from kitsune.questions.events import QuestionReplyEvent
from kitsune.questions.models import Answer, Question
from kitsune.sumo.templatetags.jinja_helpers import urlparams
from kitsune.sumo.urlresolvers import reverse
from kitsune.tags.models import SumoTag


def get_flagged_objects(reason=None, exclude_reason=None, content_model=None):
def get_flagged_objects(reason=None, exclude_reason=None, content_model=None, product_slug=None):
"""Retrieve pending flagged objects with optional filtering, eager loading related fields."""
queryset = FlaggedObject.objects.pending().select_related("content_type", "creator")
if exclude_reason:
Expand All @@ -26,6 +26,14 @@ def get_flagged_objects(reason=None, exclude_reason=None, content_model=None):
queryset = queryset.filter(reason=reason)
if content_model:
queryset = queryset.filter(content_type=content_model)
if product_slug:
matching_product_ids = [
obj.id
for obj in queryset
if hasattr(obj.content_object, "product")
and obj.content_object.product.slug == product_slug
]
queryset = queryset.filter(id__in=matching_product_ids)
return queryset


Expand Down Expand Up @@ -119,11 +127,14 @@ def get_hierarchical_topics(topics, parent=None, level=0):
@permission_required("flagit.can_moderate")
def moderate_content(request):
"""Display flagged content that needs moderation."""
content_type = ContentType.objects.get_for_model(Question)
product_slug = request.GET.get("product")

content_type = ContentType.objects.get_for_model(Question)
objects = (
get_flagged_objects(
reason=FlaggedObject.REASON_CONTENT_MODERATION, content_model=content_type
reason=FlaggedObject.REASON_CONTENT_MODERATION,
content_model=content_type,
product_slug=product_slug,
)
.select_related("content_type", "creator")
.prefetch_related("content_object__product")
Expand All @@ -143,6 +154,8 @@ def moderate_content(request):
{
"objects": objects,
"locale": request.LANGUAGE_CODE,
"products": [(p.slug, p.title) for p in Product.active.filter(codename="")],
"selected_product": product_slug,
},
)

Expand Down
53 changes: 28 additions & 25 deletions kitsune/sumo/static/sumo/js/flagit.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,37 +127,40 @@ document.addEventListener('DOMContentLoaded', () => {
});
}

async function updateReasonAndFetchContent(reason) {
const url = new URL(window.location.href);
if (reason) {
url.searchParams.set('reason', reason);
window.history.pushState({}, '', url);
} else {
url.searchParams.delete('reason');
window.history.replaceState({}, '', url.pathname);
}
const flaggedQueue = document.getElementById('flagged-queue');
initializeFilterDropdown('flagit-reason-filter', 'reason');
initializeFilterDropdown('flagit-product-filter', 'product');

const response = await fetchData(url);
if (response) {
const parser = new DOMParser();
const doc = parser.parseFromString(await response.text(), 'text/html');
flaggedQueue.innerHTML = doc.querySelector('#flagged-queue').innerHTML;
disableUpdateStatusButtons();
initializeDropdownsAndTags();
function initializeFilterDropdown(filterId, queryParam) {
const filterElement = document.getElementById(filterId);
if (!filterElement) return;

const currentFilter = new URL(window.location.href).searchParams.get(queryParam);
if (currentFilter) {
filterElement.value = currentFilter;
}
}

const reasonFilter = document.getElementById('flagit-reason-filter');
const flaggedQueue = document.getElementById('flagged-queue');
filterElement.addEventListener('change', async () => {
const selectedValue = filterElement.value;
const url = new URL(window.location.href);

if (reasonFilter) {
const reason = new URL(window.location.href).searchParams.get('reason');
if (reason) reasonFilter.value = reason;
if (selectedValue) {
url.searchParams.set(queryParam, selectedValue);
} else {
url.searchParams.delete(queryParam);
}
window.history.pushState({}, '', url);

reasonFilter.addEventListener('change', async () => {
const selectedReason = reasonFilter.value;
await updateReasonAndFetchContent(selectedReason);
const response = await fetchData(url);
if (response) {
const parser = new DOMParser();
const doc = parser.parseFromString(await response.text(), 'text/html');
flaggedQueue.innerHTML = doc.querySelector('#flagged-queue').innerHTML;
disableUpdateStatusButtons();
initializeDropdownsAndTags();
}
});
}

initializeDropdownsAndTags();
});

0 comments on commit 65cc113

Please sign in to comment.