Add post modify view

This allows moderators to modify posts (add sticky, etc).

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2022-06-30 16:21:36 -07:00
parent 2947ab6cf2
commit 6f99472f16
13 changed files with 124 additions and 22 deletions

View File

@@ -115,3 +115,17 @@ class BanForm(ModelForm):
else: else:
expires = None expires = None
self.instance.expires = expires self.instance.expires = expires
class PostModifyForm(ModelForm):
"""
A form used to modify the attributes of a post (sticky, locked, sink, etc)
"""
class Meta:
model = Post
fields = ["bump", "sticky"]
def clean(self):
super(PostModifyForm, self).clean()
print(self.fields["sticky"])

View File

@@ -68,7 +68,7 @@ class Board(models.Model):
return self.max_pages * self.threads_per_page return self.max_pages * self.threads_per_page
def prune_threads(self): def prune_threads(self):
to_remove = self.threads.order_by("-last_bump")[self.max_threads :] to_remove = self.threads.order_by("-sticky", "-last_bump")[self.max_threads :]
for thread in to_remove: for thread in to_remove:
thread.delete() thread.delete()
@@ -93,6 +93,8 @@ class Post(models.Model):
ip = models.GenericIPAddressField() ip = models.GenericIPAddressField()
# Capcode # Capcode
capcode = models.ForeignKey("Capcode", null=True, blank=True, on_delete=SET_NULL) capcode = models.ForeignKey("Capcode", null=True, blank=True, on_delete=SET_NULL)
# Post is stickied
sticky = models.BooleanField(default=False, blank=True)
# Creation time # Creation time
created = models.DateTimeField(auto_now_add=True) created = models.DateTimeField(auto_now_add=True)
# Last bump time # Last bump time
@@ -116,6 +118,9 @@ class Post(models.Model):
image_width = models.IntegerField(null=True) image_width = models.IntegerField(null=True)
image_height = models.IntegerField(null=True) image_height = models.IntegerField(null=True)
class Meta:
permissions = [("set_sticky", "Can sticky post")]
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if self.image: if self.image:
self.original_image_name = Path(self.image.name).parts[-1] self.original_image_name = Path(self.image.name).parts[-1]

View File

@@ -4,6 +4,18 @@ if (typeof window.banWindowName === "undefined") {
window.banWindowName = "ban-window"; window.banWindowName = "ban-window";
} }
if (typeof window.menuItemFactories !== "undefined") {
window.menuItemFactories.push(
(postElement) => $("<a>")
.text("Ban")
.attr("href", "#")
.on("click", (e) => {
e.preventDefault();
openBanWindow($(postElement).attr("data-ban-url"));
})
);
}
function getBanWindow() { function getBanWindow() {
return window.top.jsFrame.getWindowByName(banWindowName); return window.top.jsFrame.getWindowByName(banWindowName);
} }

View File

@@ -1,11 +0,0 @@
if (typeof window.menuItemFactories !== "undefined") {
window.menuItemFactories.push(
(postElement) => $("<a>")
.text("Ban")
.attr("href", "#")
.on("click", (e) => {
e.preventDefault();
openBanWindow($(postElement).attr("data-ban-url"));
})
)
}

View File

@@ -0,0 +1,36 @@
if (typeof window.menuItemFactories !== "undefined") {
window.menuItemFactories.push(
(postElement) => $("<a>")
.text("Modify post")
.attr("href", "#")
.on("click", (e) => {
e.preventDefault();
openModifyWindow($(postElement).attr("data-modify-url"));
})
);
}
// HACK: this should be a const, but it will cause an error if included twice in
// the same page (like an iframe).
if (typeof window.modifyWindowName === "undefined") {
window.modifyWindowName = "modify-window";
}
function getModifyWindow() {
return window.top.jsFrame.getWindowByName(modifyWindowName);
}
function openModifyWindow(modifyUrl) {
if (window.top.jsFrame.containsWindowName(modifyWindowName)) {
getModifyWindow().closeFrame();
}
let modifyWindow = window.top.jsFrame.create({
title: "Modifying post",
name: modifyWindowName,
width: 475,
height: 475,
url: modifyUrl,
});
modifyWindow.show();
}

View File

@@ -85,6 +85,10 @@ th {
clear: both; clear: both;
} }
.post_sticky {
font-weight: bold;
}
.post_id { .post_id {
cursor: pointer; cursor: pointer;
} }

View File

@@ -32,7 +32,7 @@
{{block.super}} {{block.super}}
<script src="{% static 'board/jquery.js' %}"></script> <script src="{% static 'board/jquery.js' %}"></script>
<script src="{% static 'board/jsframe.min.js' %}"></script> <script src="{% static 'board/jsframe.min.js' %}"></script>
<script src="{% static 'board/ban_window.js' %}"></script> <script src="{% static 'board/ban.js' %}"></script>
{% endblock extrahead %} {% endblock extrahead %}
{% block footer %} {% block footer %}

View File

@@ -2,10 +2,6 @@
{% load i18n static %} {% load i18n static %}
{# Title #} {# Title #}
{% block title %}{% translate "Ban success" %}{% endblock %} {% block title %}{% translate "Ban success" %}{% endblock %}
{# Extra JS #}
{% block extrajs %}
<script src="{% static 'board/ban_window.js' %}"></script>
{% endblock extrajs %}
{# Body #} {# Body #}
{% block content %} {% block content %}
<div class="row" id="message"> <div class="row" id="message">

View File

@@ -7,13 +7,13 @@
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>{% block title %}{% if title %}{{title}}{% else %}Index{% endif %}{% endblock %}</title> <title>{% block title %}{% if title %}{{title}}{% else %}Index{% endif %}{% endblock %}</title>
<link rel="stylesheet" href="{% static 'board/style.css' %}"> <link rel="stylesheet" href="{% static 'board/style.css' %}">
<link rel="stylesheet" href="{% static 'board/font-awesome/css/font-awesome.min.css' %}">
{% block extrastyle %}{% endblock %} {% block extrastyle %}{% endblock %}
<script src="{% static 'board/jquery.js' %}"></script> <script src="{% static 'board/jquery.js' %}"></script>
<script src="{% static 'board/jsframe.min.js' %}"></script> <script src="{% static 'board/jsframe.min.js' %}"></script>
<script src="{% static 'board/post.js' %}"></script> <script src="{% static 'board/post.js' %}"></script>
{% if perms.board.create_ban %} {% if perms.board.create_ban %}
<script src="{% static 'board/ban_window.js' %}"></script> <script src="{% static 'board/ban_window.js' %}"></script>
<script src="{% static 'board/ban_menu.js' %}"></script>
{% endif %} {% endif %}
{% block extrajs %}{% endblock %} {% block extrajs %}{% endblock %}
</head> </head>

View File

@@ -0,0 +1,17 @@
{% extends "board/base.html" %}
{% load i18n %}
{% block content %}
<form method="post" action="{% url 'board:post_modify' post.id %}">
{% csrf_token %}
<table>
{% if perms.board.can_sticky %}
<tr>
<th>{{form.sticky.label_tag}}</th>
<td>{{form.sticky}}</td>
</tr>
{% endif %}
<tr><td>&nbsp;</td><td><input type="submit" value="Modify post" /></td></tr>
</table>
</form>
{% endblock content %}

View File

@@ -6,6 +6,9 @@
{% if perms.board.create_ban %} {% if perms.board.create_ban %}
data-ban-url="{% url 'board:ban_create' board.url post.id %}" data-ban-url="{% url 'board:ban_create' board.url post.id %}"
{% endif %} {% endif %}
{% if perms.board.can_sticky %}
data-modify-url="{% url 'board:post_modify' post.id %}"
{% endif %}
> >
{# Image #} {# Image #}
{% if post.thumbnail %} {% if post.thumbnail %}
@@ -24,7 +27,10 @@
</div> </div>
{% endif %} {% endif %}
{# Post ID, username, time #} {# Post ID, sticky, username, time #}
{% if post.sticky and not post.op %}
<span title="Stickied" class="fa fa-sticky-note"></span>
{% endif %}
<a href="#p{{post.id}}">#.</a> <a href="#p{{post.id}}">#.</a>
<span class="post_id">{{post.id}}</span> <span class="post_id">{{post.id}}</span>
{% if post.subject %} {% if post.subject %}

View File

@@ -20,6 +20,8 @@ urlpatterns = [
path("ban/<slug:url>/<int:id>/", BanCreateView.as_view(), name="ban_create"), path("ban/<slug:url>/<int:id>/", BanCreateView.as_view(), name="ban_create"),
path("ban/success/", BanSuccessView.as_view(), name="ban_success"), path("ban/success/", BanSuccessView.as_view(), name="ban_success"),
path("banned", BannedView.as_view(), name="banned"), path("banned", BannedView.as_view(), name="banned"),
# Other moderation pages
path("modify/<int:pk>/", PostModifyView.as_view(), name="post_modify"),
] ]
# TODO - make this conditional so we can serve images up with whatever server we want # TODO - make this conditional so we can serve images up with whatever server we want
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View File

@@ -13,7 +13,7 @@ from django.utils import timezone
from guardian.shortcuts import get_objects_for_user from guardian.shortcuts import get_objects_for_user
from board.forms import BanForm, PostForm, ReplyForm, ReportForm from board.forms import *
from board.models import Ban, BanTemplate, Board, Post, Report from board.models import Ban, BanTemplate, Board, Post, Report
from board.utils import * from board.utils import *
@@ -23,6 +23,7 @@ __all__ = (
"BannedView", "BannedView",
"BoardView", "BoardView",
"PostCreateView", "PostCreateView",
"PostModifyView",
"PostView", "PostView",
"PostSuccessView", "PostSuccessView",
"ReplyCreateView", "ReplyCreateView",
@@ -109,7 +110,9 @@ class BoardView(TemplateView):
last_page = (thread_count // threads_per_page) + 1 last_page = (thread_count // threads_per_page) + 1
kwargs["board"] = self.board kwargs["board"] = self.board
kwargs["threads"] = self.board.threads.order_by("-last_bump")[start:end] kwargs["threads"] = self.board.threads.order_by("-sticky", "-last_bump")[
start:end
]
kwargs["current_page"] = page kwargs["current_page"] = page
kwargs["pages"] = range(1, last_page + 1) kwargs["pages"] = range(1, last_page + 1)
kwargs["last_page"] = last_page kwargs["last_page"] = last_page
@@ -145,6 +148,24 @@ class PostCreateView(CreateView):
return reverse("board:post_success") + "?" + query.urlencode() return reverse("board:post_success") + "?" + query.urlencode()
class PostModifyView(PermissionRequiredMixin, edit.UpdateView):
model = Post
form_class = PostModifyForm
template_name = "board/post_modify_view.html"
def has_permission(self) -> bool:
user = self.request.user
if not user:
return False
# TODO add more permissions as required
return user.has_perm("board.can_sticky")
def dispatch(self, request, *args, **kwargs):
self.post_obj = get_object_or_404(Post, id=kwargs["pk"])
self.board = self.post_obj.board
return super(PostModifyView, self).dispatch(request, *args, **kwargs)
class ReplyCreateView(CreateView): class ReplyCreateView(CreateView):
model = Post model = Post
form_class = ReplyForm form_class = ReplyForm