feat: ❌ allow deleting of posts
This commit is contained in:
parent
2fed369027
commit
ad27fdf1c2
7 changed files with 63 additions and 9 deletions
|
|
@ -5,7 +5,7 @@ from django.urls import include, path
|
|||
|
||||
from moku.views.auth import LoginView, LogoutView
|
||||
from moku.views.blog import IndexBlogView
|
||||
from moku.views.post import EditPostview, FeedView
|
||||
from moku.views.post import DeletePostView, EditPostview, FeedView
|
||||
from moku.views.recipe import (
|
||||
DeleteRecipeView,
|
||||
DeleteStepView,
|
||||
|
|
@ -34,7 +34,8 @@ urlpatterns = [
|
|||
path("blog", IndexBlogView.as_view(), name="blog.index"),
|
||||
path("privacy", PrivacyView.as_view(), name="privacy"),
|
||||
path("terms", TermsView.as_view(), name="terms"),
|
||||
path("edit/<str:uuid>", EditPostview.as_view(), name="post.edit"),
|
||||
path("post/<str:uuid>", EditPostview.as_view(), name="post.edit"),
|
||||
path("post/<str:uuid>/delete", DeletePostView.as_view(), name="post.delete"),
|
||||
path("user/<str:username>", ProfileView.as_view(), name="profile"),
|
||||
path("user/<str:username>/json", UserJSONView.as_view(), name="json"),
|
||||
path("recipes", IndexRecipeView.as_view(), name="recipe.index"),
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
from django.forms import ModelForm
|
||||
from django.forms import Form, ModelForm
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from moku.models import Post
|
||||
|
||||
|
||||
class DeletePostForm(Form):
|
||||
pass
|
||||
|
||||
|
||||
class PostForm(ModelForm):
|
||||
"""Form for creating and updating posts."""
|
||||
|
||||
|
|
|
|||
|
|
@ -86,10 +86,10 @@ class Post(models.Model):
|
|||
objects = PostManager()
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.text} on {self.created_at}"
|
||||
return f"{self.plain_text} on {self.created_at}"
|
||||
|
||||
@property
|
||||
def text(self):
|
||||
def html(self):
|
||||
"""
|
||||
The text of the post, with the post's chosen verb hydrated with food and user
|
||||
information.
|
||||
|
|
@ -101,3 +101,11 @@ class Post(models.Model):
|
|||
),
|
||||
"food": escape(self.food),
|
||||
}
|
||||
|
||||
@property
|
||||
def plain_text(self):
|
||||
"""The text of the post as plain text."""
|
||||
return self.get_verb_display() % {
|
||||
"user": f"@{self.created_by.username}",
|
||||
"food": escape(self.food),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,16 @@
|
|||
|
||||
{% block content %}
|
||||
<div class="content block">
|
||||
<h2>{% trans time_ago=post.created_at|naturaltime %}editing post from {{ time_ago }}{% endtrans %}</h2>
|
||||
<p class="mb">
|
||||
👈 <a href="{{ url('feed') }}">back to feed</a>
|
||||
<span class="mx">•</span>
|
||||
❌ <a href="{{ url('post.delete', uuid=post.uuid) }}">delete post</a>
|
||||
</p>
|
||||
<h2>
|
||||
{% trans post_text=post.plain_text, time_ago=post.created_at|naturaltime %}
|
||||
editing {{ post_text }} from {{ time_ago }}
|
||||
{% endtrans %}
|
||||
</h2>
|
||||
{% include "moku/snippets/post_form.jinja" %}
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
{% endif %}
|
||||
<div class="emoji">{{ post.emoji }}</div>
|
||||
<div class="body">
|
||||
<p class="food user-content">{{ post.text|safe }}</p>
|
||||
<p class="food user-content">{{ post.html|safe }}</p>
|
||||
<p class="metadata">
|
||||
{{ post.created_at|naturaltime }}
|
||||
{% if request.user.is_authenticated and request.user.id == post.created_by.id %}
|
||||
|
|
|
|||
|
|
@ -12,4 +12,5 @@ def test_post(post: Post, re_uuid: re.Pattern):
|
|||
assert post.pk > 0
|
||||
assert post.pk == post.id
|
||||
assert re_uuid.match(post.uuid) is not None
|
||||
assert post.text == '<a href="/user/jean">@jean</a> cooked sausage surprise'
|
||||
assert post.html == '<a href="/user/jean">@jean</a> cooked sausage surprise'
|
||||
assert post.plain_text == "@jean cooked sausage surprise"
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
|
||||
from django.contrib.humanize.templatetags.humanize import naturaltime
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.urls import reverse
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from moku.constants import EMOJI_CATEGORIES, Verbs
|
||||
from moku.forms.post import PostForm
|
||||
from moku.forms.post import DeletePostForm, PostForm
|
||||
from moku.images import process_post_image
|
||||
from moku.models.post import Post
|
||||
from moku.models.recipe import Recipe
|
||||
|
|
@ -20,6 +22,35 @@ def _get_verbs(username):
|
|||
)
|
||||
|
||||
|
||||
class DeletePostView(LoginRequiredMixin, UserPassesTestMixin, FormView):
|
||||
"""Allows users to delete their previous posts."""
|
||||
|
||||
template_name = "moku/delete.jinja"
|
||||
form_class = DeletePostForm
|
||||
|
||||
def form_valid(self, form):
|
||||
self.post_object.delete()
|
||||
messages.success(self.request, _("post deleted successfully!"))
|
||||
return redirect("feed")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
return {
|
||||
**super().get_context_data(**kwargs),
|
||||
"item": _("%(post_text)s from %(time_ago)s") % {
|
||||
"post_text": self.post_object.plain_text,
|
||||
"time_ago": naturaltime(self.post_object.created_at),
|
||||
},
|
||||
"back_url": reverse("post.edit", kwargs={"uuid": self.post_object.uuid}),
|
||||
}
|
||||
|
||||
@cached_property
|
||||
def post_object(self):
|
||||
return get_object_or_404(Post, uuid=self.kwargs.get("uuid"))
|
||||
|
||||
def test_func(self):
|
||||
return self.request.user.id == self.post_object.created_by.id
|
||||
|
||||
|
||||
class EditPostview(LoginRequiredMixin, UserPassesTestMixin, FormView):
|
||||
"""Allows users to edit their previous posts."""
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue