diff --git a/photologue/static/lightgallery/plugins/admin/lg-admin.js b/photologue/static/lightgallery/plugins/admin/lg-admin.js index 9f8695c..3faef11 100644 --- a/photologue/static/lightgallery/plugins/admin/lg-admin.js +++ b/photologue/static/lightgallery/plugins/admin/lg-admin.js @@ -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 = ""; // Add button linking to Django admin page - this.core.$toolbar.append(`${adminIcon}`); + this.core.$toolbar.append(`${adminIcon}`); document.getElementById("lg-admin").style.display = this.isStaff ? 'block' : 'none'; // Add button to delete photo this.core.$toolbar.append(`${deleteIcon}`); 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(`${reportIcon}`); + 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 diff --git a/photologue/templates/photologue/gallery_detail.html b/photologue/templates/photologue/gallery_detail.html index 35d3538..0d14bac 100644 --- a/photologue/templates/photologue/gallery_detail.html +++ b/photologue/templates/photologue/gallery_detail.html @@ -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 }}", }); {% endblock %} diff --git a/photologue/templates/photologue/photo_confirm_report.html b/photologue/templates/photologue/photo_confirm_report.html new file mode 100644 index 0000000..e682b9b --- /dev/null +++ b/photologue/templates/photologue/photo_confirm_report.html @@ -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 %} +
+
+

{% trans "Report confirmation" %}

+
{% csrf_token %} +

+ {% blocktranslate trimmed %} + Are you sure you want to report {{ object }}? + This photo will no longer be public, and administrators will be notified. + {% endblocktranslate %} +

+ +
+
+
+{% endblock %} \ No newline at end of file diff --git a/photologue/urls.py b/photologue/urls.py index 547b0f0..bb47615 100644 --- a/photologue/urls.py +++ b/photologue/urls.py @@ -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//download/', GalleryDownload.as_view(), name='pl-gallery-download'), path('photo//', PhotoDetailView.as_view(), name='pl-photo'), path('photo//delete/', PhotoDeleteView.as_view(), name='pl-photo-delete'), + path('photo//report/', PhotoReportView.as_view(), name='pl-photo-report'), path('upload/', GalleryUpload.as_view(), name='pl-gallery-upload'), ] diff --git a/photologue/views.py b/photologue/views.py index 75621ca..3df8fa6 100644 --- a/photologue/views.py +++ b/photologue/views.py @@ -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