Allow for comment deletion (#363)
* Allow for comment deletion Receive and emit deletion activity Add button to delete comment * Remove debug print and fix copy-past typo * Improve style of comment deletion button
This commit is contained in:
parent
0df9c4d400
commit
5c5cf36b0d
@ -1,4 +1,4 @@
|
||||
use activitypub::{activity::Create, link, object::Note};
|
||||
use activitypub::{activity::{Create, Delete}, link, object::{Note, Tombstone}};
|
||||
use chrono::{self, NaiveDateTime};
|
||||
use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl};
|
||||
use serde_json;
|
||||
@ -7,7 +7,7 @@ use instance::Instance;
|
||||
use mentions::Mention;
|
||||
use notifications::*;
|
||||
use plume_common::activity_pub::{
|
||||
inbox::{FromActivity, Notify},
|
||||
inbox::{FromActivity, Notify, Deletable},
|
||||
Id, IntoId, PUBLIC_VISIBILTY,
|
||||
};
|
||||
use plume_common::utils;
|
||||
@ -254,3 +254,49 @@ impl Notify<Connection> for Comment {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'a> Deletable<Connection, Delete> for Comment {
|
||||
fn delete(&self, conn: &Connection) -> Delete {
|
||||
let mut act = Delete::default();
|
||||
act.delete_props
|
||||
.set_actor_link(self.get_author(conn).into_id())
|
||||
.expect("Comment::delete: actor error");
|
||||
|
||||
let mut tombstone = Tombstone::default();
|
||||
tombstone
|
||||
.object_props
|
||||
.set_id_string(self.ap_url.clone().expect("Comment::delete: no ap_url"))
|
||||
.expect("Comment::delete: object.id error");
|
||||
act.delete_props
|
||||
.set_object_object(tombstone)
|
||||
.expect("Comment::delete: object error");
|
||||
|
||||
act.object_props
|
||||
.set_id_string(format!("{}#delete", self.ap_url.clone().unwrap()))
|
||||
.expect("Comment::delete: id error");
|
||||
act.object_props
|
||||
.set_to_link_vec(vec![Id::new(PUBLIC_VISIBILTY)])
|
||||
.expect("Comment::delete: to error");
|
||||
|
||||
for m in Mention::list_for_comment(&conn, self.id) {
|
||||
m.delete(conn);
|
||||
}
|
||||
diesel::update(comments::table).filter(comments::in_response_to_id.eq(self.id))
|
||||
.set(comments::in_response_to_id.eq(self.in_response_to_id))
|
||||
.execute(conn)
|
||||
.expect("Comment::delete: DB error could not update other comments");
|
||||
diesel::delete(self)
|
||||
.execute(conn)
|
||||
.expect("Comment::delete: DB error");
|
||||
act
|
||||
}
|
||||
|
||||
fn delete_id(id: &str, actor_id: &str, conn: &Connection) {
|
||||
let actor = User::find_by_ap_url(conn, actor_id);
|
||||
let comment = Comment::find_by_ap_url(conn, id);
|
||||
if let Some(comment) = comment.filter(|c| c.author_id == actor.unwrap().id) {
|
||||
comment.delete(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -65,6 +65,14 @@ pub trait Inbox {
|
||||
actor_id.as_ref(),
|
||||
&(conn, searcher),
|
||||
);
|
||||
Comment::delete_id(
|
||||
&act.delete_props
|
||||
.object_object::<Tombstone>()?
|
||||
.object_props
|
||||
.id_string()?,
|
||||
actor_id.as_ref(),
|
||||
conn,
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
"Follow" => {
|
||||
|
@ -91,6 +91,7 @@ fn main() {
|
||||
routes::blogs::atom_feed,
|
||||
|
||||
routes::comments::create,
|
||||
routes::comments::delete,
|
||||
routes::comments::activity_pub,
|
||||
|
||||
routes::instance::index,
|
||||
|
@ -7,7 +7,8 @@ use rocket_i18n::I18n;
|
||||
use validator::Validate;
|
||||
use template_utils::Ructe;
|
||||
|
||||
use plume_common::{utils, activity_pub::{broadcast, ApRequest, ActivityStream}};
|
||||
use plume_common::{utils, activity_pub::{broadcast, ApRequest,
|
||||
ActivityStream, inbox::Deletable}};
|
||||
use plume_models::{
|
||||
blogs::Blog,
|
||||
comments::*,
|
||||
@ -86,6 +87,18 @@ pub fn create(blog_name: String, slug: String, form: LenientForm<NewCommentForm>
|
||||
})
|
||||
}
|
||||
|
||||
#[post("/~/<blog>/<slug>/comment/<id>/delete")]
|
||||
pub fn delete(blog: String, slug: String, id: i32, user: User, conn: DbConn, worker: Worker) -> Redirect {
|
||||
if let Some(comment) = Comment::get(&*conn, id) {
|
||||
if comment.author_id == user.id {
|
||||
let dest = User::one_by_instance(&*conn);
|
||||
let delete_activity = comment.delete(&*conn);
|
||||
worker.execute(move || broadcast(&user, delete_activity, dest));
|
||||
}
|
||||
}
|
||||
Redirect::to(uri!(super::posts::details: blog = blog, slug = slug, responding_to = _))
|
||||
}
|
||||
|
||||
#[get("/~/<_blog>/<_slug>/comment/<id>")]
|
||||
pub fn activity_pub(_blog: String, _slug: String, id: i32, _ap: ApRequest, conn: DbConn) -> Option<ActivityStream<Note>> {
|
||||
Comment::get(&*conn, id).map(|c| ActivityStream::new(c.to_activity(&*conn)))
|
||||
|
@ -202,17 +202,18 @@ main .article-meta {
|
||||
}
|
||||
|
||||
// New comment form
|
||||
form input[type="submit"] {
|
||||
> form input[type="submit"] {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
// Response button
|
||||
a.button {
|
||||
// Response/delete buttons
|
||||
a.button, form.inline, form.inline input {
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
background: none;
|
||||
color: $black;
|
||||
border: none;
|
||||
margin-right: 2em;
|
||||
|
||||
&::before {
|
||||
color: $purple;
|
||||
|
@ -17,7 +17,7 @@
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.icon {
|
||||
.icon:before {
|
||||
font-family: "Feather";
|
||||
speak: none;
|
||||
font-style: normal;
|
||||
@ -257,4 +257,4 @@
|
||||
.icon-command:before { content: "\e8fb"; }
|
||||
.icon-cloud:before { content: "\e8fc"; }
|
||||
.icon-hash:before { content: "\e8fd"; }
|
||||
.icon-headphones:before { content: "\e8fe"; }
|
||||
.icon-headphones:before { content: "\e8fe"; }
|
||||
|
@ -3,14 +3,14 @@
|
||||
@use plume_models::users::User;
|
||||
@use routes::*;
|
||||
|
||||
@(ctx: BaseContext, comm: &Comment, author: User, in_reply_to: Option<&str>)
|
||||
@(ctx: BaseContext, comm: &Comment, author: User, in_reply_to: Option<&str>, blog: &str, slug: &str)
|
||||
|
||||
<div class="comment u-comment h-cite" id="comment-@comm.id">
|
||||
<a class="author u-author h-card" href="@uri!(user::details: name = author.get_fqn(ctx.0))">
|
||||
@avatar(ctx.0, &author, Size::Small, true, ctx.1)
|
||||
<span class="display-name p-name">@author.name(ctx.0)</span>
|
||||
<small>@author.get_fqn(ctx.0)</small>
|
||||
</a>
|
||||
</a>
|
||||
@if let Some(ref ap_url) = comm.ap_url {
|
||||
<a class="u-url" href="@ap_url"></a>
|
||||
}
|
||||
@ -28,7 +28,12 @@
|
||||
}
|
||||
</div>
|
||||
<a class="button icon icon-message-circle" href="?responding_to=@comm.id">@i18n!(ctx.1, "Respond")</a>
|
||||
@if ctx.2.clone().map(|u| u.id == author.id).unwrap_or(false) {
|
||||
<form class="inline icon icon-trash" method="post" action="@uri!(comments::delete: blog = blog, slug = slug, id = comm.id)">
|
||||
<input onclick="return confirm('Are you sure you?')" type="submit" value="@i18n!(ctx.1, "Delete this comment")">
|
||||
</form>
|
||||
}
|
||||
@for res in comm.get_responses(ctx.0) {
|
||||
@:comment(ctx, &res, res.get_author(ctx.0), comm.ap_url.as_ref().map(|u| &**u))
|
||||
@:comment(ctx, &res, res.get_author(ctx.0), comm.ap_url.as_ref().map(|u| &**u), blog, slug)
|
||||
}
|
||||
</div>
|
||||
|
@ -146,7 +146,7 @@
|
||||
@if !comments.is_empty() {
|
||||
<div class="list">
|
||||
@for comm in comments {
|
||||
@:comment(ctx, &comm, comm.get_author(ctx.0), Some(&article.ap_url))
|
||||
@:comment(ctx, &comm, comm.get_author(ctx.0), Some(&article.ap_url), &blog.get_fqn(ctx.0), &article.slug)
|
||||
}
|
||||
</div>
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user