diff --git a/board/forms.py b/board/forms.py index 2f5312f..bb4b557 100644 --- a/board/forms.py +++ b/board/forms.py @@ -115,3 +115,17 @@ class BanForm(ModelForm): else: expires = None 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"]) diff --git a/board/models.py b/board/models.py index 15a3047..fa70b24 100644 --- a/board/models.py +++ b/board/models.py @@ -68,7 +68,7 @@ class Board(models.Model): return self.max_pages * self.threads_per_page 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: thread.delete() @@ -93,6 +93,8 @@ class Post(models.Model): ip = models.GenericIPAddressField() # Capcode capcode = models.ForeignKey("Capcode", null=True, blank=True, on_delete=SET_NULL) + # Post is stickied + sticky = models.BooleanField(default=False, blank=True) # Creation time created = models.DateTimeField(auto_now_add=True) # Last bump time @@ -116,6 +118,9 @@ class Post(models.Model): image_width = models.IntegerField(null=True) image_height = models.IntegerField(null=True) + class Meta: + permissions = [("set_sticky", "Can sticky post")] + def save(self, *args, **kwargs): if self.image: self.original_image_name = Path(self.image.name).parts[-1] diff --git a/board/static/board/ban_window.js b/board/static/board/ban.js similarity index 64% rename from board/static/board/ban_window.js rename to board/static/board/ban.js index 80da26c..bce0260 100644 --- a/board/static/board/ban_window.js +++ b/board/static/board/ban.js @@ -4,6 +4,18 @@ if (typeof window.banWindowName === "undefined") { window.banWindowName = "ban-window"; } +if (typeof window.menuItemFactories !== "undefined") { + window.menuItemFactories.push( + (postElement) => $("") + .text("Ban") + .attr("href", "#") + .on("click", (e) => { + e.preventDefault(); + openBanWindow($(postElement).attr("data-ban-url")); + }) + ); +} + function getBanWindow() { return window.top.jsFrame.getWindowByName(banWindowName); } @@ -20,4 +32,4 @@ function openBanWindow(banUrl) { url: banUrl, }); banWindow.show(); -} \ No newline at end of file +} diff --git a/board/static/board/ban_menu.js b/board/static/board/ban_menu.js deleted file mode 100644 index cb20168..0000000 --- a/board/static/board/ban_menu.js +++ /dev/null @@ -1,11 +0,0 @@ -if (typeof window.menuItemFactories !== "undefined") { - window.menuItemFactories.push( - (postElement) => $("") - .text("Ban") - .attr("href", "#") - .on("click", (e) => { - e.preventDefault(); - openBanWindow($(postElement).attr("data-ban-url")); - }) - ) -} \ No newline at end of file diff --git a/board/static/board/modify.js b/board/static/board/modify.js new file mode 100644 index 0000000..99991c2 --- /dev/null +++ b/board/static/board/modify.js @@ -0,0 +1,36 @@ +if (typeof window.menuItemFactories !== "undefined") { + window.menuItemFactories.push( + (postElement) => $("") + .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(); +} \ No newline at end of file diff --git a/board/static/board/style.css b/board/static/board/style.css index 07cb15a..97335fe 100644 --- a/board/static/board/style.css +++ b/board/static/board/style.css @@ -85,6 +85,10 @@ th { clear: both; } +.post_sticky { + font-weight: bold; +} + .post_id { cursor: pointer; } diff --git a/board/templates/admin/board/reportrecord/change_list.html b/board/templates/admin/board/reportrecord/change_list.html index 651caf2..a27d185 100644 --- a/board/templates/admin/board/reportrecord/change_list.html +++ b/board/templates/admin/board/reportrecord/change_list.html @@ -32,7 +32,7 @@ {{block.super}} - + {% endblock extrahead %} {% block footer %} diff --git a/board/templates/board/ban_success.html b/board/templates/board/ban_success.html index 7762141..8d14073 100644 --- a/board/templates/board/ban_success.html +++ b/board/templates/board/ban_success.html @@ -2,10 +2,6 @@ {% load i18n static %} {# Title #} {% block title %}{% translate "Ban success" %}{% endblock %} -{# Extra JS #} -{% block extrajs %} - -{% endblock extrajs %} {# Body #} {% block content %}
diff --git a/board/templates/board/base.html b/board/templates/board/base.html index ce0ed4c..30b9b68 100644 --- a/board/templates/board/base.html +++ b/board/templates/board/base.html @@ -7,13 +7,13 @@ {% block title %}{% if title %}{{title}}{% else %}Index{% endif %}{% endblock %} + {% block extrastyle %}{% endblock %} {% if perms.board.create_ban %} - {% endif %} {% block extrajs %}{% endblock %} diff --git a/board/templates/board/post_modify_view.html b/board/templates/board/post_modify_view.html new file mode 100644 index 0000000..78543d5 --- /dev/null +++ b/board/templates/board/post_modify_view.html @@ -0,0 +1,17 @@ +{% extends "board/base.html" %} +{% load i18n %} + +{% block content %} +
+ {% csrf_token %} + + {% if perms.board.can_sticky %} + + + + + {% endif %} + +
{{form.sticky.label_tag}}{{form.sticky}}
 
+
+{% endblock content %} \ No newline at end of file diff --git a/board/templates/board/post_snippet.html b/board/templates/board/post_snippet.html index 8297397..f90f73a 100644 --- a/board/templates/board/post_snippet.html +++ b/board/templates/board/post_snippet.html @@ -6,6 +6,9 @@ {% if perms.board.create_ban %} data-ban-url="{% url 'board:ban_create' board.url post.id %}" {% endif %} + {% if perms.board.can_sticky %} + data-modify-url="{% url 'board:post_modify' post.id %}" + {% endif %} > {# Image #} {% if post.thumbnail %} @@ -24,7 +27,10 @@
{% endif %} -{# Post ID, username, time #} +{# Post ID, sticky, username, time #} +{% if post.sticky and not post.op %} + +{% endif %}
#. {{post.id}} {% if post.subject %} diff --git a/board/urls.py b/board/urls.py index 4ccec93..39eeeb2 100644 --- a/board/urls.py +++ b/board/urls.py @@ -20,6 +20,8 @@ urlpatterns = [ path("ban///", BanCreateView.as_view(), name="ban_create"), path("ban/success/", BanSuccessView.as_view(), name="ban_success"), path("banned", BannedView.as_view(), name="banned"), + # Other moderation pages + path("modify//", PostModifyView.as_view(), name="post_modify"), ] # 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) diff --git a/board/views.py b/board/views.py index d57417a..a2ec22f 100644 --- a/board/views.py +++ b/board/views.py @@ -13,7 +13,7 @@ from django.utils import timezone 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.utils import * @@ -23,6 +23,7 @@ __all__ = ( "BannedView", "BoardView", "PostCreateView", + "PostModifyView", "PostView", "PostSuccessView", "ReplyCreateView", @@ -109,7 +110,9 @@ class BoardView(TemplateView): last_page = (thread_count // threads_per_page) + 1 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["pages"] = range(1, last_page + 1) kwargs["last_page"] = last_page @@ -145,6 +148,24 @@ class PostCreateView(CreateView): 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): model = Post form_class = ReplyForm