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.auth import LoginView, LogoutView
|
||||||
from moku.views.blog import IndexBlogView
|
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 (
|
from moku.views.recipe import (
|
||||||
DeleteRecipeView,
|
DeleteRecipeView,
|
||||||
DeleteStepView,
|
DeleteStepView,
|
||||||
|
|
@ -34,7 +34,8 @@ urlpatterns = [
|
||||||
path("blog", IndexBlogView.as_view(), name="blog.index"),
|
path("blog", IndexBlogView.as_view(), name="blog.index"),
|
||||||
path("privacy", PrivacyView.as_view(), name="privacy"),
|
path("privacy", PrivacyView.as_view(), name="privacy"),
|
||||||
path("terms", TermsView.as_view(), name="terms"),
|
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>", ProfileView.as_view(), name="profile"),
|
||||||
path("user/<str:username>/json", UserJSONView.as_view(), name="json"),
|
path("user/<str:username>/json", UserJSONView.as_view(), name="json"),
|
||||||
path("recipes", IndexRecipeView.as_view(), name="recipe.index"),
|
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 django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from moku.models import Post
|
from moku.models import Post
|
||||||
|
|
||||||
|
|
||||||
|
class DeletePostForm(Form):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class PostForm(ModelForm):
|
class PostForm(ModelForm):
|
||||||
"""Form for creating and updating posts."""
|
"""Form for creating and updating posts."""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -86,10 +86,10 @@ class Post(models.Model):
|
||||||
objects = PostManager()
|
objects = PostManager()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.text} on {self.created_at}"
|
return f"{self.plain_text} on {self.created_at}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def text(self):
|
def html(self):
|
||||||
"""
|
"""
|
||||||
The text of the post, with the post's chosen verb hydrated with food and user
|
The text of the post, with the post's chosen verb hydrated with food and user
|
||||||
information.
|
information.
|
||||||
|
|
@ -101,3 +101,11 @@ class Post(models.Model):
|
||||||
),
|
),
|
||||||
"food": escape(self.food),
|
"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 %}
|
{% block content %}
|
||||||
<div class="content block">
|
<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" %}
|
{% include "moku/snippets/post_form.jinja" %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="emoji">{{ post.emoji }}</div>
|
<div class="emoji">{{ post.emoji }}</div>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<p class="food user-content">{{ post.text|safe }}</p>
|
<p class="food user-content">{{ post.html|safe }}</p>
|
||||||
<p class="metadata">
|
<p class="metadata">
|
||||||
{{ post.created_at|naturaltime }}
|
{{ post.created_at|naturaltime }}
|
||||||
{% if request.user.is_authenticated and request.user.id == post.created_by.id %}
|
{% 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 > 0
|
||||||
assert post.pk == post.id
|
assert post.pk == post.id
|
||||||
assert re_uuid.match(post.uuid) is not None
|
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 import messages
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
|
||||||
|
from django.contrib.humanize.templatetags.humanize import naturaltime
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.shortcuts import get_object_or_404, redirect
|
from django.shortcuts import get_object_or_404, redirect
|
||||||
|
from django.urls import reverse
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from moku.constants import EMOJI_CATEGORIES, Verbs
|
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.images import process_post_image
|
||||||
from moku.models.post import Post
|
from moku.models.post import Post
|
||||||
from moku.models.recipe import Recipe
|
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):
|
class EditPostview(LoginRequiredMixin, UserPassesTestMixin, FormView):
|
||||||
"""Allows users to edit their previous posts."""
|
"""Allows users to edit their previous posts."""
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue