diff --git a/CHANGELOG.md b/CHANGELOG.md index e5bc9eb..10f4493 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Added dependency to [SUOU](https://github.com/sakuragasaki46/suou) library - Added user blocks - Added user strikes: a strike logs the content of a removed message for future use +- Posts may now be deleted by author. If it has comments, comments are not spared - Implemented guild subscriptions + Blocking a user prevents them from seeing your comments, posts (standalone or in feed) and profile - Added ✨color themes✨ diff --git a/alembic/versions/6d418df3c72f_.py b/alembic/versions/6d418df3c72f_.py new file mode 100644 index 0000000..68c2f56 --- /dev/null +++ b/alembic/versions/6d418df3c72f_.py @@ -0,0 +1,34 @@ +"""empty message + +Revision ID: 6d418df3c72f +Revises: 90c7d0098efe +Create Date: 2025-07-07 13:37:51.667620 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = '6d418df3c72f' +down_revision: Union[str, None] = '90c7d0098efe' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + """Upgrade schema.""" + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint('comment_parent_post_id_fkey', 'freak_comment', type_='foreignkey') + op.create_foreign_key('comment_parent_post_id', 'freak_comment', 'freak_post', ['parent_post_id'], ['id'], ondelete='cascade') + # ### end Alembic commands ### + + +def downgrade() -> None: + """Downgrade schema.""" + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint('comment_parent_post_id', 'freak_comment', type_='foreignkey') + op.create_foreign_key('comment_parent_post_id_fkey', 'freak_comment', 'freak_post', ['parent_post_id'], ['id']) + # ### end Alembic commands ### diff --git a/freak/models.py b/freak/models.py index 009bff7..a478595 100644 --- a/freak/models.py +++ b/freak/models.py @@ -245,7 +245,6 @@ class User(Base): target_id = target qq= ~select(UserBlock).where(UserBlock.c.actor_id == actor_id, UserBlock.c.target_id == target_id).exists() - print(qq) return qq def recompute_karma(self): @@ -437,7 +436,7 @@ class Comment(Base): id = snowflake_column() author_id = Column(BigInteger, ForeignKey('freak_user.id', name='comment_author_id'), nullable=True) - parent_post_id = Column(BigInteger, ForeignKey('freak_post.id', name='comment_parent_post_id'), nullable=False) + parent_post_id = Column(BigInteger, ForeignKey('freak_post.id', name='comment_parent_post_id', ondelete='cascade'), nullable=False) parent_comment_id = Column(BigInteger, ForeignKey('freak_comment.id', name='comment_parent_comment_id'), nullable=True) text_content = Column(String(16384), nullable=False) created_at = Column(DateTime, server_default=func.current_timestamp(), index=True) diff --git a/freak/templates/singledelete.html b/freak/templates/singledelete.html new file mode 100644 index 0000000..c60fb68 --- /dev/null +++ b/freak/templates/singledelete.html @@ -0,0 +1,27 @@ +{% extends "base.html" %} +{% from "macros/title.html" import title_tag with context %} +{% from "macros/icon.html" import icon, callout with context %} + +{% block title %}{{ title_tag('Confirm deletion: ' + p.title, False) }}{% endblock %} + +{% block heading %} +

Confirm deletion: {{ p.title }}

+{% endblock %} + +{% block content %} +
+
+ +
+

You are about to delete permanently your post on {{ p.topic_or_user().handle() }}.

+ {% call callout('spoiler', 'error') %}This action cannot be undone.{% endcall %} + {% if (p.comments | count) %} + {% call callout('spoiler') %}Your post has {{ (p.comments | count) }} comments. Your post will be deleted along with ALL the comments.{% endcall %} + {% endif %} +
+
+ +
+
+
+{% endblock %} \ No newline at end of file diff --git a/freak/website/__init__.py b/freak/website/__init__.py index 5d19801..cc1aed7 100644 --- a/freak/website/__init__.py +++ b/freak/website/__init__.py @@ -17,6 +17,9 @@ blueprints.append(bp) from .edit import bp blueprints.append(bp) +from .delete import bp +blueprints.append(bp) + from .about import bp blueprints.append(bp) diff --git a/freak/website/delete.py b/freak/website/delete.py new file mode 100644 index 0000000..afbf5fa --- /dev/null +++ b/freak/website/delete.py @@ -0,0 +1,31 @@ + + +from flask import Blueprint, abort, flash, redirect, render_template, request +from flask_login import current_user, login_required +from sqlalchemy import delete, select + +from ..models import Post, db + + +bp = Blueprint('delete', __name__) + + +@bp.route('/delete/post/', methods=['GET', 'POST']) +@login_required +def delete_post(id: int): + p = db.session.execute(select(Post).where(Post.id == id, Post.author == current_user)).scalar() + + if p is None: + abort(404) + if p.author != current_user: + abort(403) + + pt = p.topic_or_user() + + if request.method == 'POST': + db.session.execute(delete(Post).where(Post.id == id, Post.author == current_user)) + db.session.commit() + flash('Your post has been deleted') + return redirect(pt.url()), 303 + + return render_template('singledelete.html', p=p) \ No newline at end of file diff --git a/freak/website/edit.py b/freak/website/edit.py index cfdf0be..3547b9f 100644 --- a/freak/website/edit.py +++ b/freak/website/edit.py @@ -14,7 +14,7 @@ bp = Blueprint('edit', __name__) @bp.route('/edit/post/', methods=['GET', 'POST']) @login_required def edit_post(id): - p: Post | None = db.session.execute(select(Post).where(Post.id == id)).scalar() + p: Post | None = db.session.execute(select(Post).where(Post.id == id, Post.author == current_user)).scalar() if p is None: abort(404)