Update PostModifyForm to use permissions to create its fields
Fields are only displayed via the PostModifyForm if the user has specific permissions to do things, like set stickies. Also, add PostModifySuccessView that will close the modify window when the process is complete. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -4,6 +4,7 @@ from django.db import transaction
|
|||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.forms import ModelForm, ModelChoiceField
|
from django.forms import ModelForm, ModelChoiceField
|
||||||
|
from django.forms.models import fields_for_model
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from board.models import Ban, Post, Report, ReportReason, ReportRecord
|
from board.models import Ban, Post, Report, ReportReason, ReportRecord
|
||||||
from hcaptcha.fields import hCaptchaField
|
from hcaptcha.fields import hCaptchaField
|
||||||
@@ -124,8 +125,23 @@ class PostModifyForm(ModelForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Post
|
model = Post
|
||||||
fields = ["bump", "sticky"]
|
# we specify fields up here too because otherwise they won't be
|
||||||
|
# recognized by the form to update values
|
||||||
|
fields: list[str] = ["sticky"]
|
||||||
|
|
||||||
def clean(self):
|
def __init__(self, *args, user, **kwargs):
|
||||||
super(PostModifyForm, self).clean()
|
super(PostModifyForm, self).__init__(*args, **kwargs)
|
||||||
print(self.fields["sticky"])
|
self.user = user
|
||||||
|
fields = []
|
||||||
|
if self.user.has_perm("board.set_sticky"):
|
||||||
|
fields += ["sticky"]
|
||||||
|
# NOTE:
|
||||||
|
# We do *not* need to check permissions against these fields we're
|
||||||
|
# setting down here in the self.clean() function in the case that a
|
||||||
|
# malicious actor has access to the modify form and injects a "sticky"
|
||||||
|
# value to their modify request.
|
||||||
|
#
|
||||||
|
# We specify fields up in the Meta class, but we reset them down here.
|
||||||
|
# If the field isn't present in this list, then it doesn't get updated.
|
||||||
|
# If the field isn't present in the above list, then it doesn't get updated.
|
||||||
|
self.fields = fields_for_model(Post, fields)
|
||||||
|
|||||||
@@ -12,8 +12,11 @@
|
|||||||
<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.add_ban %}
|
||||||
<script src="{% static 'board/ban_window.js' %}"></script>
|
<script src="{% static 'board/ban.js' %}"></script>
|
||||||
|
{% endif %}
|
||||||
|
{% if can_modify %}
|
||||||
|
<script src="{% static 'board/modify.js' %}"></script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% block extrajs %}{% endblock %}
|
{% block extrajs %}{% endblock %}
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
33
board/templates/board/post_modify_success.html
Normal file
33
board/templates/board/post_modify_success.html
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{% extends "board/base.html" %}
|
||||||
|
{% load i18n static %}
|
||||||
|
{# Title #}
|
||||||
|
{% block title %}{% translate "Post modify success" %}{% endblock %}
|
||||||
|
{# Body #}
|
||||||
|
{% block content %}
|
||||||
|
<div class="row" id="message">
|
||||||
|
{# We do not use pluralize filter for "seconds" because it's a pain to get it to translate. #}
|
||||||
|
{% blocktranslate %}Post has been modified. This window will close in {{window_timeout}} second(s).{% endblocktranslate %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function isIframe() {
|
||||||
|
try {
|
||||||
|
return window.self !== window.top;
|
||||||
|
} catch (_) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
if(isIframe()) {
|
||||||
|
let modifyWindow = getModifyWindow();
|
||||||
|
if(modifyWindow) {
|
||||||
|
modifyWindow.closeFrame();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
}, 1000 * {{window_timeout}});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
<form method="post" action="{% url 'board:post_modify' post.id %}">
|
<form method="post" action="{% url 'board:post_modify' post.id %}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<table>
|
<table>
|
||||||
{% if perms.board.can_sticky %}
|
{% if perms.board.set_sticky %}
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{form.sticky.label_tag}}</th>
|
<th>{{form.sticky.label_tag}}</th>
|
||||||
<td>{{form.sticky}}</td>
|
<td>{{form.sticky}}</td>
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
<div
|
<div
|
||||||
id="p{{post.id}}"
|
id="p{{post.id}}"
|
||||||
data-report-url="{% url 'board:report_form' board.url post.id %}"
|
data-report-url="{% url 'board:report_form' board.url post.id %}"
|
||||||
{% if perms.board.create_ban %}
|
{% if perms.board.add_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 %}
|
{% if can_modify %}
|
||||||
data-modify-url="{% url 'board:post_modify' post.id %}"
|
data-modify-url="{% url 'board:post_modify' post.id %}"
|
||||||
{% endif %}
|
{% endif %}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ urlpatterns = [
|
|||||||
path("banned", BannedView.as_view(), name="banned"),
|
path("banned", BannedView.as_view(), name="banned"),
|
||||||
# Other moderation pages
|
# Other moderation pages
|
||||||
path("modify/<int:pk>/", PostModifyView.as_view(), name="post_modify"),
|
path("modify/<int:pk>/", PostModifyView.as_view(), name="post_modify"),
|
||||||
|
path(
|
||||||
|
"modify/success/", PostModifySuccessView.as_view(), name="post_modify_success"
|
||||||
|
),
|
||||||
]
|
]
|
||||||
# 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)
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ __all__ = (
|
|||||||
"BoardView",
|
"BoardView",
|
||||||
"PostCreateView",
|
"PostCreateView",
|
||||||
"PostModifyView",
|
"PostModifyView",
|
||||||
|
"PostModifySuccessView",
|
||||||
"PostView",
|
"PostView",
|
||||||
"PostSuccessView",
|
"PostSuccessView",
|
||||||
"ReplyCreateView",
|
"ReplyCreateView",
|
||||||
@@ -35,6 +36,13 @@ __all__ = (
|
|||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
|
def can_modify(user):
|
||||||
|
if not user:
|
||||||
|
return False
|
||||||
|
# TODO add more permissions as required
|
||||||
|
return user.has_perm("board.set_sticky")
|
||||||
|
|
||||||
|
|
||||||
class BannedView(TemplateView):
|
class BannedView(TemplateView):
|
||||||
template_name = "board/banned.html"
|
template_name = "board/banned.html"
|
||||||
|
|
||||||
@@ -117,6 +125,7 @@ class BoardView(TemplateView):
|
|||||||
kwargs["pages"] = range(1, last_page + 1)
|
kwargs["pages"] = range(1, last_page + 1)
|
||||||
kwargs["last_page"] = last_page
|
kwargs["last_page"] = last_page
|
||||||
kwargs["max_upload_size"] = settings.MAX_UPLOAD_SIZE
|
kwargs["max_upload_size"] = settings.MAX_UPLOAD_SIZE
|
||||||
|
kwargs["can_modify"] = can_modify(self.request.user)
|
||||||
|
|
||||||
return super(BoardView, self).get_context_data(**kwargs)
|
return super(BoardView, self).get_context_data(**kwargs)
|
||||||
|
|
||||||
@@ -135,6 +144,7 @@ class PostCreateView(CreateView):
|
|||||||
context["capcodes"] = get_objects_for_user(
|
context["capcodes"] = get_objects_for_user(
|
||||||
get_user(self.request), "board.use_capcode"
|
get_user(self.request), "board.use_capcode"
|
||||||
)
|
)
|
||||||
|
kwargs["can_modify"] = can_modify(self.request.user)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
@@ -152,19 +162,34 @@ class PostModifyView(PermissionRequiredMixin, edit.UpdateView):
|
|||||||
model = Post
|
model = Post
|
||||||
form_class = PostModifyForm
|
form_class = PostModifyForm
|
||||||
template_name = "board/post_modify_view.html"
|
template_name = "board/post_modify_view.html"
|
||||||
|
success_url = reverse_lazy("board:post_modify_success")
|
||||||
|
|
||||||
def has_permission(self) -> bool:
|
def has_permission(self) -> bool:
|
||||||
user = self.request.user
|
return can_modify(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):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
self.post_obj = get_object_or_404(Post, id=kwargs["pk"])
|
self.post_obj = get_object_or_404(Post, id=kwargs["pk"])
|
||||||
self.board = self.post_obj.board
|
self.board = self.post_obj.board
|
||||||
return super(PostModifyView, self).dispatch(request, *args, **kwargs)
|
return super(PostModifyView, self).dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def get_form_kwargs(self) -> Dict[str, Any]:
|
||||||
|
kwargs = super(PostModifyView, self).get_form_kwargs()
|
||||||
|
kwargs["user"] = self.request.user
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
|
class PostModifySuccessView(PermissionRequiredMixin, TemplateView):
|
||||||
|
template_name = "board/post_modify_success.html"
|
||||||
|
|
||||||
|
def has_permission(self) -> bool:
|
||||||
|
return can_modify(self.request.user)
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context["window_timeout"] = settings.BAN_WINDOW_CLOSE_TIMEOUT
|
||||||
|
context["can_modify"] = self.has_permission()
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
class ReplyCreateView(CreateView):
|
class ReplyCreateView(CreateView):
|
||||||
model = Post
|
model = Post
|
||||||
@@ -183,6 +208,7 @@ class ReplyCreateView(CreateView):
|
|||||||
context["capcodes"] = get_objects_for_user(
|
context["capcodes"] = get_objects_for_user(
|
||||||
get_user(self.request), "board.use_capcode"
|
get_user(self.request), "board.use_capcode"
|
||||||
)
|
)
|
||||||
|
kwargs["can_modify"] = can_modify(self.request.user)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
@@ -262,7 +288,7 @@ class ReportSuccessView(TemplateView):
|
|||||||
class BanCreateView(PermissionRequiredMixin, edit.CreateView):
|
class BanCreateView(PermissionRequiredMixin, edit.CreateView):
|
||||||
model = Ban
|
model = Ban
|
||||||
form_class = BanForm
|
form_class = BanForm
|
||||||
permission_required = "ban.create"
|
permission_required = "board.add_ban"
|
||||||
success_url = reverse_lazy("board:ban_success")
|
success_url = reverse_lazy("board:ban_success")
|
||||||
|
|
||||||
def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
|
def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
|
||||||
|
|||||||
Reference in New Issue
Block a user