Enable users to report without sending a mail

This commit is contained in:
Alexandre Iooss 2022-03-02 21:22:44 +01:00
parent f9c33e2cad
commit 2ad0c8dbc7
5 changed files with 119 additions and 6 deletions

View file

@ -9,6 +9,8 @@ class lgAdmin {
this.core = instance;
this.$LG = $LG;
this.isStaff = instance.settings.isStaff;
this.csrfToken = instance.settings.csrfToken;
this.photoId = 0;
return this;
}
@ -18,24 +20,78 @@ class lgAdmin {
const reportIcon = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" fill=\"currentColor\" viewBox=\"0 0 16 16\"><path d=\"M11.46.146A.5.5 0 0 0 11.107 0H4.893a.5.5 0 0 0-.353.146L.146 4.54A.5.5 0 0 0 0 4.893v6.214a.5.5 0 0 0 .146.353l4.394 4.394a.5.5 0 0 0 .353.146h6.214a.5.5 0 0 0 .353-.146l4.394-4.394a.5.5 0 0 0 .146-.353V4.893a.5.5 0 0 0-.146-.353L11.46.146zM8 4c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 4.995A.905.905 0 0 1 8 4zm.002 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2z\"/></svg>";
// Add button linking to Django admin page
this.core.$toolbar.append(`<a href="#" id="lg-admin" title="Go to admin" class="lg-icon lg-bi-icon">${adminIcon}</a>`);
this.core.$toolbar.append(`<a href="#" target="_blank" id="lg-admin" title="Go to admin" class="lg-icon lg-bi-icon">${adminIcon}</a>`);
document.getElementById("lg-admin").style.display = this.isStaff ? 'block' : 'none';
// Add button to delete photo
this.core.$toolbar.append(`<a href="#" id="lg-delete" title="Remove this photo" class="lg-icon lg-bi-icon">${deleteIcon}</a>`);
document.getElementById("lg-delete").style.display = this.isStaff ? 'block' : 'none';
document.getElementById("lg-delete").addEventListener('click', this.onDelete.bind(this));
// Add button to report photo
this.core.$toolbar.append(`<a href="#" id="lg-report" title="Notify abuse" class="lg-icon lg-bi-icon">${reportIcon}</a>`);
document.getElementById("lg-report").addEventListener('click', this.onReport.bind(this));
this.core.LGel.on("lgAfterSlide.admin", this.onAfterSlide.bind(this));
}
// Event called when showing a new slide
onAfterSlide(event) {
const photoId = this.core.galleryItems[event.detail.index].slideName;
document.getElementById("lg-admin").href = `https://photos.crans.org/admin/photologue/photo/${photoId}/change/`;
document.getElementById("lg-delete").href = `https://photos.crans.org/admin/photologue/photo/${photoId}/delete/`;
document.getElementById("lg-report").href = `mailto:photos@crans.org?subject=[ABUS] Photo ${photoId}&body=${encodeURIComponent(window.location.href)}`;
this.photoId = this.core.galleryItems[event.detail.index].slideName;
document.getElementById("lg-admin").href = `/admin/photologue/photo/${this.photoId}/change/`;
}
// Event called when user click on delete button
onDelete(event) {
event.preventDefault();
if(confirm("Are you sure to delete this photo?")) {
// Build form request
let data = new FormData();
data.append('csrfmiddlewaretoken', this.csrfToken);
fetch(`/photo/${this.photoId}/delete/`, {
method: "POST",
body: data,
credentials: 'same-origin',
}).then(res => {
if(res.ok) {
console.log("Deletion complete, response:", res);
// Remove HTML element
document.querySelectorAll(`[data-slide-name='${this.photoId}']`)[0].remove()
this.core.goToNextSlide();
this.core.refresh();
}
});
}
}
// Event called when user click on report button
onReport(event) {
event.preventDefault();
if(confirm("Are you sure to report this photo?")) {
// Build form request
let data = new FormData();
data.append('csrfmiddlewaretoken', this.csrfToken);
fetch(`/photo/${this.photoId}/report/`, {
method: "POST",
body: data,
credentials: 'same-origin',
}).then(res => {
if(res.ok) {
console.log("Report complete, response:", res);
// Update HTML element
const thumbnail = document.querySelectorAll(`[data-slide-name='${this.photoId}']`)[0];
if (!this.isStaff) {
thumbnail.remove()
this.core.goToNextSlide();
this.core.refresh();
} else {
location.reload();
}
}
});
}
}
// Plugins must have destroy prototype

View file

@ -23,6 +23,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
plugins: [lgAdmin, lgHash, lgThumbnail, lgZoom],
customSlideName: true,
isStaff: {{ request.user.is_staff|yesno:"true,false" }},
csrfToken: "{{ csrf_token }}",
});
</script>
{% endblock %}

View file

@ -0,0 +1,24 @@
{% extends "base.html" %}
{% comment %}
SPDX-License-Identifier: GPL-3.0-or-later
{% endcomment %}
{% load i18n %}
{% block title %}{% trans "Report confirmation" %}{% endblock %}
{% block content %}
<div class="row">
<div class="col-lg-12">
<h1>{% trans "Report confirmation" %}</h1>
<form method="post">{% csrf_token %}
<p>
{% blocktranslate trimmed %}
Are you sure you want to report <code>{{ object }}</code>?
This photo will no longer be public, and administrators will be notified.
{% endblocktranslate %}
</p>
<input type="submit" class="btn btn-warning" value="{% trans "Confirm" %}">
</form>
</div>
</div>
{% endblock %}

View file

@ -2,7 +2,7 @@ from django.urls import path, re_path
from .views import (GalleryDetailView, GalleryArchiveIndexView,
GalleryDownload, GalleryUpload, GalleryYearArchiveView,
PhotoDetailView, PhotoDeleteView, TagDetail)
PhotoDetailView, PhotoDeleteView, PhotoReportView, TagDetail)
app_name = 'photologue'
urlpatterns = [
@ -14,5 +14,6 @@ urlpatterns = [
path('gallery/<slug:slug>/download/', GalleryDownload.as_view(), name='pl-gallery-download'),
path('photo/<int:pk>/', PhotoDetailView.as_view(), name='pl-photo'),
path('photo/<int:pk>/delete/', PhotoDeleteView.as_view(), name='pl-photo-delete'),
path('photo/<int:pk>/report/', PhotoReportView.as_view(), name='pl-photo-report'),
path('upload/', GalleryUpload.as_view(), name='pl-gallery-upload'),
]

View file

@ -18,6 +18,7 @@ from django.views.generic.dates import ArchiveIndexView, YearArchiveView
from django.views.generic.detail import DetailView
from django.views.generic.edit import FormView, DeleteView
from PIL import Image
from django.shortcuts import redirect
from .forms import UploadForm
from .models import Gallery, Photo, Tag
@ -68,6 +69,36 @@ class PhotoDeleteView(PermissionRequiredMixin, DeleteView):
return reverse_lazy('photologue:pl-gallery', args=[slug])
class PhotoReportView(LoginRequiredMixin, DetailView):
model = Photo
template_name = 'photologue/photo_confirm_report.html'
def post(self, request, *args, **kwargs):
"""
Make photo private on POST.
"""
# Mark photo as private
photo = self.get_object()
photo.is_public = False
photo.save()
# Get gallery
galleries = photo.galleries.all()
gallery_slug = galleries[0].slug if galleries else ''
if not gallery_slug:
url = reverse_lazy('photologue:pl-gallery-archive')
url = reverse_lazy('photologue:pl-gallery', args=[gallery_slug])
# Send mail to managers
mail_managers(
subject=f"Abuse report for photo id {photo.pk}",
message=f"{self.request.user.username} reported an abuse for `{photo.title}`: {url}#lg=1&slide={photo.pk}",
)
# Redirect to gallery
return redirect(url)
class TagDetail(LoginRequiredMixin, DetailView):
model = Tag