diff --git a/board/models.py b/board/models.py index fcb4d0c..5bf0015 100644 --- a/board/models.py +++ b/board/models.py @@ -134,6 +134,7 @@ class Post(models.Model): ("set_sticky", "Can sticky post"), ("set_bump", "Can bumplock post"), ("set_lock", "Can lock post"), + ("wipe_user", "Can wipe all posts by a user"), ] def save(self, *args, **kwargs): diff --git a/board/static/board/restricted.js b/board/static/board/restricted.js index 7322713..7743309 100644 --- a/board/static/board/restricted.js +++ b/board/static/board/restricted.js @@ -7,6 +7,7 @@ if (typeof window.banWindowName === "undefined") { window.banWindowName = "ban-window"; window.modifyWindowName = "modify-window"; + window.wipeWindowName = "wipe-window"; } if (typeof window.menuItemFactories !== "undefined") { @@ -28,6 +29,15 @@ if (typeof window.menuItemFactories !== "undefined") { openModifyWindow($(postElement).attr("data-modify-url")); }) ); + window.menuItemFactories.push( + (postElement) => $("") + .text("Wipe user posts") + .attr("href", "#") + .on("click", (e) => { + e.preventDefault(); + openWipeWindow($(postElement).attr("data-wipe-url")); + }) + ); } //////////////////////////////////////////////////////////////////////////////// @@ -88,4 +98,30 @@ function openModifyWindow(modifyUrl) { modifyWindow.iframe.contentWindow.thisWindow = modifyWindow; }); modifyWindow.show(); +} + +//////////////////////////////////////////////////////////////////////////////// +// Wipe window +//////////////////////////////////////////////////////////////////////////////// +function getWipeWindow() { + return window.top.jsFrame.getWindowByName(wipeWindowName); +} + +function openWipeWindow(wipeUrl) { + if (window.top.jsFrame.containsWindowName(wipeWindowName)) { + getWipeWindow().closeFrame(); + } + + let wipeWindow = window.top.jsFrame.create({ + title: "Wipe post", + name: wipeWindowName, + width: 475, + url: wipeUrl, + }); + $(wipeWindow.iframe, "iframe").on("load", () => { + fitWindowToContent(wipeWindow); + wipeWindow.setResizable(false); + wipeWindow.iframe.contentWindow.thisWindow = wipeWindow; + }); + wipeWindow.show(); } \ No newline at end of file diff --git a/board/templates/board/post_snippet.html b/board/templates/board/post_snippet.html index a9ea41e..31c349d 100644 --- a/board/templates/board/post_snippet.html +++ b/board/templates/board/post_snippet.html @@ -8,6 +8,7 @@ {% if user.is_staff %} data-ban-url="{% url 'board:ban_create' board.url post.id %}" data-modify-url="{% url 'board:post_modify' post.id %}" + data-wipe-url="{% url 'board:post_wipe' post.id %}" {% endif %} > diff --git a/board/templates/board/post_wipe.html b/board/templates/board/post_wipe.html new file mode 100644 index 0000000..5a99592 --- /dev/null +++ b/board/templates/board/post_wipe.html @@ -0,0 +1,10 @@ +{% extends "board/base.html" %} +{% load i18n %} + +{% block content %} + {% blocktranslate %}This will delete {{all_posts_count}} posts.{% endblocktranslate %} +
+ {% csrf_token %} + +
+{% endblock content %} \ No newline at end of file diff --git a/board/urls.py b/board/urls.py index 704fcd7..faad6aa 100644 --- a/board/urls.py +++ b/board/urls.py @@ -42,6 +42,14 @@ urlpatterns = [ ActionSuccessView.as_view(window_timeout=settings.ACTION_SUCCESS_CLOSE_TIMEOUT), name="post_delete_success", ), + path("post/wipe//", PostWipeView.as_view(), name="post_wipe"), + path( + "post/wipe/success/", + ActionSuccessView.as_view( + window_timeout=settings.ACTION_SUCCESS_CLOSE_TIMEOUT, message="Posts wiped." + ), + name="post_wipe_success", + ), # Board views path("post/success/", PostSuccessView.as_view(), name="post_success"), path("/page//", BoardView.as_view(), name="board_detail"), diff --git a/board/views.py b/board/views.py index 6c3f21c..8e127ef 100644 --- a/board/views.py +++ b/board/views.py @@ -8,7 +8,7 @@ from django.http import Http404, HttpResponseRedirect from django.http.request import QueryDict from django.shortcuts import get_object_or_404 from django.views.generic.base import TemplateView -from django.views.generic import edit, list +from django.views.generic import detail, edit, list from django.urls import reverse, reverse_lazy from django.utils import timezone @@ -31,6 +31,7 @@ __all__ = ( "PostView", "PostSuccessView", "PostDeleteView", + "PostWipeView", "ReplyCreateView", "ReportView", ) @@ -279,6 +280,38 @@ class PostDeleteView(PermissionRequiredMixin, edit.DeleteView): return HttpResponseRedirect(success_url) +class PostWipeView(PermissionRequiredMixin, detail.SingleObjectMixin, TemplateView): + model = Post + permission_required = ("wipe_user",) + template_name = "board/post_wipe.html" + success_url = reverse_lazy("board:post_wipe_success") + + @property + def all_posts(self): + return Post.objects.filter(ip=self.object.ip) + + def dispatch(self, request, *args, **kwargs): + self.object = self.get_object() + return super(PostWipeView, self).dispatch(request, *args, **kwargs) + + def post(self, request, *args, **kwargs): + # Wipe user's posts + self.all_posts.delete() + # Success redirect + success_url = self.get_success_url() + return HttpResponseRedirect(success_url) + + def get_context_data(self, **kwargs): + context = super(PostWipeView, self).get_context_data(**kwargs) + # context["all_posts"] = self.all_posts + # for some reason, {{all_posts.count}} does not seem to work in the template. + context["all_posts_count"] = self.all_posts.count() + return context + + def get_success_url(self): + return self.success_url + + class ReportView(CreateView): model = Report form_class = ReportForm