Add the ability to ban posts
This commit is contained in:
parent
782f069031
commit
1d00a8f60d
10 changed files with 146 additions and 1 deletions
|
@ -108,7 +108,7 @@
|
||||||
</section>
|
</section>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<% if (ctx.canFeaturePosts || ctx.canDeletePosts || ctx.canMergePosts) { %>
|
<% if (ctx.canFeaturePosts || ctx.canDeletePosts || ctx.canMergePosts || ctx.canBanPosts) { %>
|
||||||
<section class='management'>
|
<section class='management'>
|
||||||
<ul>
|
<ul>
|
||||||
<% if (ctx.canFeaturePosts) { %>
|
<% if (ctx.canFeaturePosts) { %>
|
||||||
|
@ -120,6 +120,9 @@
|
||||||
<% if (ctx.canDeletePosts) { %>
|
<% if (ctx.canDeletePosts) { %>
|
||||||
<li><a href class='delete'>Delete this post</a></li>
|
<li><a href class='delete'>Delete this post</a></li>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
<% if (ctx.canBanPosts) { %>
|
||||||
|
<li><a href class='ban'>Ban this post</a></li>
|
||||||
|
<% } %>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
|
@ -88,6 +88,9 @@ class PostMainController extends BasePostController {
|
||||||
this._view.sidebarControl.addEventListener("delete", (e) =>
|
this._view.sidebarControl.addEventListener("delete", (e) =>
|
||||||
this._evtDeletePost(e)
|
this._evtDeletePost(e)
|
||||||
);
|
);
|
||||||
|
this._view.sidebarControl.addEventListener("ban", (e) =>
|
||||||
|
this._evtBanPost(e)
|
||||||
|
);
|
||||||
this._view.sidebarControl.addEventListener("merge", (e) =>
|
this._view.sidebarControl.addEventListener("merge", (e) =>
|
||||||
this._evtMergePost(e)
|
this._evtMergePost(e)
|
||||||
);
|
);
|
||||||
|
@ -165,6 +168,22 @@ class PostMainController extends BasePostController {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_evtBanPost(e) {
|
||||||
|
this._view.sidebarControl.disableForm();
|
||||||
|
this._view.sidebarControl.clearMessages();
|
||||||
|
e.detail.post.ban().then(
|
||||||
|
() => {
|
||||||
|
misc.disableExitConfirmation();
|
||||||
|
const ctx = router.show(uri.formatClientLink("posts"));
|
||||||
|
ctx.controller.showSuccess("Post banned.");
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
this._view.sidebarControl.showError(error.message);
|
||||||
|
this._view.sidebarControl.enableForm();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
_evtUpdatePost(e) {
|
_evtUpdatePost(e) {
|
||||||
this._view.sidebarControl.disableForm();
|
this._view.sidebarControl.disableForm();
|
||||||
this._view.sidebarControl.clearMessages();
|
this._view.sidebarControl.clearMessages();
|
||||||
|
|
|
@ -46,6 +46,7 @@ class PostEditSidebarControl extends events.EventTarget {
|
||||||
"posts:create:anonymous"
|
"posts:create:anonymous"
|
||||||
),
|
),
|
||||||
canDeletePosts: api.hasPrivilege("posts:delete"),
|
canDeletePosts: api.hasPrivilege("posts:delete"),
|
||||||
|
canBanPosts: api.hasPrivilege("posts:ban"),
|
||||||
canFeaturePosts: api.hasPrivilege("posts:feature"),
|
canFeaturePosts: api.hasPrivilege("posts:feature"),
|
||||||
canMergePosts: api.hasPrivilege("posts:merge"),
|
canMergePosts: api.hasPrivilege("posts:merge"),
|
||||||
})
|
})
|
||||||
|
@ -186,6 +187,12 @@ class PostEditSidebarControl extends events.EventTarget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this._banLinkNode) {
|
||||||
|
this._banLinkNode.addEventListener("click", (e) =>
|
||||||
|
this._evtBanClick(e)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
this._postNotesOverlayControl.addEventListener("blur", (e) =>
|
this._postNotesOverlayControl.addEventListener("blur", (e) =>
|
||||||
this._evtNoteBlur(e)
|
this._evtNoteBlur(e)
|
||||||
);
|
);
|
||||||
|
@ -301,6 +308,19 @@ class PostEditSidebarControl extends events.EventTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_evtBanClick(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (confirm("Are you sure you want to ban this post?")) {
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent("ban", {
|
||||||
|
detail: {
|
||||||
|
post: this._post,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_evtNoteTextChangeRequest(e) {
|
_evtNoteTextChangeRequest(e) {
|
||||||
if (this._editedNote) {
|
if (this._editedNote) {
|
||||||
this._editedNote.text = this._noteTextareaNode.value;
|
this._editedNote.text = this._noteTextareaNode.value;
|
||||||
|
@ -517,6 +537,11 @@ class PostEditSidebarControl extends events.EventTarget {
|
||||||
return this._formNode.querySelector(".management .delete");
|
return this._formNode.querySelector(".management .delete");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get _banLinkNode() {
|
||||||
|
return this._formNode.querySelector(".management .ban");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
get _addNoteLinkNode() {
|
get _addNoteLinkNode() {
|
||||||
return this._formNode.querySelector(".notes .add");
|
return this._formNode.querySelector(".notes .add");
|
||||||
}
|
}
|
||||||
|
|
|
@ -334,6 +334,23 @@ class Post extends events.EventTarget {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ban() {
|
||||||
|
return api
|
||||||
|
.post(uri.formatApiLink("post-ban", this.id), {
|
||||||
|
version: this._version
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent("ban", {
|
||||||
|
detail: {
|
||||||
|
post: this
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return Promise.resolve();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
delete() {
|
delete() {
|
||||||
return api
|
return api
|
||||||
.delete(uri.formatApiLink("post", this.id), {
|
.delete(uri.formatApiLink("post", this.id), {
|
||||||
|
|
|
@ -116,6 +116,7 @@ privileges:
|
||||||
'posts:bulk-edit:tags': power
|
'posts:bulk-edit:tags': power
|
||||||
'posts:bulk-edit:safety': power
|
'posts:bulk-edit:safety': power
|
||||||
'posts:bulk-edit:delete': power
|
'posts:bulk-edit:delete': power
|
||||||
|
'posts:ban': moderator
|
||||||
|
|
||||||
'tags:create': regular
|
'tags:create': regular
|
||||||
'tags:edit:names': power
|
'tags:edit:names': power
|
||||||
|
|
|
@ -183,6 +183,18 @@ def delete_post(ctx: rest.Context, params: Dict[str, str]) -> rest.Response:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
@rest.routes.post("/post-ban/(?P<post_id>[^/]+)/?")
|
||||||
|
def ban_post(ctx: rest.Context, params: Dict[str, str]) -> rest.Response:
|
||||||
|
auth.verify_privilege(ctx.user, "posts:ban")
|
||||||
|
post = _get_post(params)
|
||||||
|
versions.verify_version(post, ctx)
|
||||||
|
posts.ban(posts.create_ban(post))
|
||||||
|
snapshots.delete(post, ctx.user)
|
||||||
|
posts.delete(post)
|
||||||
|
ctx.session.commit()
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
@rest.routes.post("/post-merge/?")
|
@rest.routes.post("/post-merge/?")
|
||||||
def merge_posts(
|
def merge_posts(
|
||||||
ctx: rest.Context, _params: Dict[str, str] = {}
|
ctx: rest.Context, _params: Dict[str, str] = {}
|
||||||
|
|
|
@ -50,6 +50,12 @@ class PostAlreadyUploadedError(errors.ValidationError):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class PostBannedError(errors.ValidationError):
|
||||||
|
def __init__(self, message: str = "This file was banned", extra_fields: Dict[str, str] = None) -> None:
|
||||||
|
super().__init__(message, extra_fields)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class InvalidPostIdError(errors.ValidationError):
|
class InvalidPostIdError(errors.ValidationError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -425,6 +431,15 @@ def create_post(
|
||||||
return post, new_tags
|
return post, new_tags
|
||||||
|
|
||||||
|
|
||||||
|
def create_ban(post: model.Post) -> model.PostBan:
|
||||||
|
ban = model.PostBan()
|
||||||
|
ban.checksum = post.checksum
|
||||||
|
ban.time = datetime.utcnow()
|
||||||
|
|
||||||
|
db.session.add(ban)
|
||||||
|
return ban
|
||||||
|
|
||||||
|
|
||||||
def update_post_safety(post: model.Post, safety: str) -> None:
|
def update_post_safety(post: model.Post, safety: str) -> None:
|
||||||
assert post
|
assert post
|
||||||
safety = util.flip(SAFETY_MAP).get(safety, None)
|
safety = util.flip(SAFETY_MAP).get(safety, None)
|
||||||
|
@ -634,6 +649,7 @@ def update_post_content(post: model.Post, content: Optional[bytes]) -> None:
|
||||||
.filter(model.Post.post_id != post.post_id)
|
.filter(model.Post.post_id != post.post_id)
|
||||||
.one_or_none()
|
.one_or_none()
|
||||||
)
|
)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
other_post
|
other_post
|
||||||
and other_post.post_id
|
and other_post.post_id
|
||||||
|
@ -641,6 +657,15 @@ def update_post_content(post: model.Post, content: Optional[bytes]) -> None:
|
||||||
):
|
):
|
||||||
raise PostAlreadyUploadedError(other_post)
|
raise PostAlreadyUploadedError(other_post)
|
||||||
|
|
||||||
|
|
||||||
|
post_ban = (db.session.query(model.PostBan)
|
||||||
|
.filter(model.PostBan.checksum == post.checksum)
|
||||||
|
.one_or_none()
|
||||||
|
)
|
||||||
|
if (post_ban):
|
||||||
|
raise PostBannedError()
|
||||||
|
|
||||||
|
|
||||||
if update_signature:
|
if update_signature:
|
||||||
purge_post_signature(post)
|
purge_post_signature(post)
|
||||||
post.signature = generate_post_signature(post, content)
|
post.signature = generate_post_signature(post, content)
|
||||||
|
@ -806,6 +831,11 @@ def delete(post: model.Post) -> None:
|
||||||
db.session.delete(post)
|
db.session.delete(post)
|
||||||
|
|
||||||
|
|
||||||
|
def ban(ban: model.PostBan) -> None:
|
||||||
|
assert ban
|
||||||
|
db.session.add(ban)
|
||||||
|
|
||||||
|
|
||||||
def merge_posts(
|
def merge_posts(
|
||||||
source_post: model.Post, target_post: model.Post, replace_content: bool
|
source_post: model.Post, target_post: model.Post, replace_content: bool
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
'''
|
||||||
|
create ban table
|
||||||
|
|
||||||
|
Revision ID: cc2956cb8ee7
|
||||||
|
Created at: 2023-05-12 02:04:22.592006
|
||||||
|
'''
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
revision = 'cc2956cb8ee7'
|
||||||
|
down_revision = 'adcd63ff76a2'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.create_table(
|
||||||
|
"post_ban",
|
||||||
|
sa.Column("id", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("checksum", sa.Unicode(64), nullable=False),
|
||||||
|
sa.Column("time", sa.DateTime, nullable=False),
|
||||||
|
sa.PrimaryKeyConstraint("id")
|
||||||
|
)
|
||||||
|
op.create_unique_constraint("uq_ban_checksum", "post_ban", ["checksum"])
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.drop_table("post_ban")
|
|
@ -5,6 +5,7 @@ from szurubooru.model.pool import Pool, PoolName, PoolPost
|
||||||
from szurubooru.model.pool_category import PoolCategory
|
from szurubooru.model.pool_category import PoolCategory
|
||||||
from szurubooru.model.post import (
|
from szurubooru.model.post import (
|
||||||
Post,
|
Post,
|
||||||
|
PostBan,
|
||||||
PostFavorite,
|
PostFavorite,
|
||||||
PostFeature,
|
PostFeature,
|
||||||
PostNote,
|
PostNote,
|
||||||
|
|
|
@ -94,6 +94,14 @@ class PostFavorite(Base):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class PostBan(Base):
|
||||||
|
__tablename__ = "post_ban"
|
||||||
|
|
||||||
|
ban_id = sa.Column("id", sa.Integer, primary_key=True)
|
||||||
|
checksum = sa.Column("checksum", sa.Unicode(64), nullable=False)
|
||||||
|
time = sa.Column("time", sa.DateTime, nullable=False)
|
||||||
|
|
||||||
|
|
||||||
class PostNote(Base):
|
class PostNote(Base):
|
||||||
__tablename__ = "post_note"
|
__tablename__ = "post_note"
|
||||||
|
|
||||||
|
|
Reference in a new issue