Allow likes to be deleted with AP

This commit is contained in:
Bat 2018-05-13 11:44:05 +01:00
parent bae49bcb47
commit 601fe7cf4f
7 changed files with 81 additions and 10 deletions

View file

@ -0,0 +1,2 @@
-- This file should undo anything in `up.sql`
ALTER TABLE likes DROP COLUMN ap_url;

View file

@ -0,0 +1,2 @@
-- Your SQL goes here
ALTER TABLE likes ADD COLUMN ap_url VARCHAR NOT NULL default '';

View file

@ -210,12 +210,48 @@ impl Activity for Like {
} }
fn get_type(&self) -> String { fn get_type(&self) -> String {
"Follow".to_string() "Like".to_string()
} }
fn serialize(&self) -> serde_json::Value { fn serialize(&self) -> serde_json::Value {
json!({ json!({
"type": "Follow", "type": "Like",
"id": self.id,
"actor": self.actor,
"object": self.object
})
}
}
#[derive(Clone)]
pub struct Undo {
id: String,
actor: serde_json::Value,
object: serde_json::Value
}
impl Undo {
pub fn new<A: Actor, B: Object>(actor: &A, obj: &B, conn: &PgConnection) -> Undo {
Undo {
id: format!("{}/undo", obj.compute_id(conn)),
actor: serde_json::Value::String(actor.compute_id(conn)),
object: obj.serialize(conn)
}
}
}
impl Activity for Undo {
fn get_id(&self) -> String {
self.id.clone()
}
fn get_type(&self) -> String {
"Undo".to_string()
}
fn serialize(&self) -> serde_json::Value {
json!({
"type": "Undo",
"id": self.id, "id": self.id,
"actor": self.actor, "actor": self.actor,
"object": self.object "object": self.object

View file

@ -64,9 +64,19 @@ pub trait Inbox: Actor + Sized {
let post = Post::get_by_ap_url(conn, act["object"].as_str().unwrap().to_string()); let post = Post::get_by_ap_url(conn, act["object"].as_str().unwrap().to_string());
Like::insert(conn, NewLike { Like::insert(conn, NewLike {
post_id: post.unwrap().id, post_id: post.unwrap().id,
user_id: liker.unwrap().id user_id: liker.unwrap().id,
ap_url: act["id"].as_str().unwrap().to_string()
}); });
}, },
"Undo" => {
match act["object"]["type"].as_str().unwrap() {
"Like" => {
let like = Like::find_by_ap_url(conn, act["object"]["id"].as_str().unwrap().to_string()).unwrap();
like.delete(conn);
}
x => println!("Wanted to Undo a {}, but it is not supported yet", x)
}
},
x => println!("Received unknow activity type: {}", x) x => println!("Received unknow activity type: {}", x)
} }
} }

View file

@ -13,14 +13,16 @@ pub struct Like {
pub id: i32, pub id: i32,
pub user_id: i32, pub user_id: i32,
pub post_id: i32, pub post_id: i32,
pub creation_date: chrono::NaiveDateTime pub creation_date: chrono::NaiveDateTime,
pub ap_url: String
} }
#[derive(Insertable)] #[derive(Insertable)]
#[table_name = "likes"] #[table_name = "likes"]
pub struct NewLike { pub struct NewLike {
pub user_id: i32, pub user_id: i32,
pub post_id: i32 pub post_id: i32,
pub ap_url: String
} }
impl Like { impl Like {
@ -31,6 +33,14 @@ impl Like {
.expect("Unable to insert new like") .expect("Unable to insert new like")
} }
pub fn update_ap_url(&self, conn: &PgConnection) {
if self.ap_url.len() == 0 {
diesel::update(self)
.set(likes::ap_url.eq(self.compute_id(conn)))
.get_result::<Like>(conn).expect("Couldn't update AP URL");
}
}
pub fn get(conn: &PgConnection, id: i32) -> Option<Like> { pub fn get(conn: &PgConnection, id: i32) -> Option<Like> {
likes::table.filter(likes::id.eq(id)) likes::table.filter(likes::id.eq(id))
.limit(1) .limit(1)
@ -39,6 +49,14 @@ impl Like {
.into_iter().nth(0) .into_iter().nth(0)
} }
pub fn find_by_ap_url(conn: &PgConnection, ap_url: String) -> Option<Like> {
likes::table.filter(likes::ap_url.eq(ap_url))
.limit(1)
.load::<Like>(conn)
.expect("Error loading like by AP URL")
.into_iter().nth(0)
}
pub fn for_user_on_post(conn: &PgConnection, user: &User, post: &Post) -> Option<Like> { pub fn for_user_on_post(conn: &PgConnection, user: &User, post: &Post) -> Option<Like> {
likes::table.filter(likes::post_id.eq(post.id)) likes::table.filter(likes::post_id.eq(post.id))
.filter(likes::user_id.eq(user.id)) .filter(likes::user_id.eq(user.id))

View file

@ -1,6 +1,6 @@
use rocket::response::Redirect; use rocket::response::Redirect;
use activity_pub::activity::{Like, Delete}; use activity_pub::activity::{Like, Undo};
use activity_pub::outbox::broadcast; use activity_pub::outbox::broadcast;
use db_conn::DbConn; use db_conn::DbConn;
use models::likes; use models::likes;
@ -12,17 +12,19 @@ fn create(blog: String, slug: String, user: User, conn: DbConn) -> Redirect {
let post = Post::find_by_slug(&*conn, slug.clone()).unwrap(); let post = Post::find_by_slug(&*conn, slug.clone()).unwrap();
if !user.has_liked(&*conn, &post) { if !user.has_liked(&*conn, &post) {
likes::Like::insert(&*conn, likes::NewLike { let like = likes::Like::insert(&*conn, likes::NewLike {
post_id: post.id, post_id: post.id,
user_id: user.id user_id: user.id,
ap_url: "".to_string()
}); });
like.update_ap_url(&*conn);
let act = Like::new(&user, &post, &*conn); let act = Like::new(&user, &post, &*conn);
broadcast(&*conn, &user, act, user.get_followers(&*conn)); broadcast(&*conn, &user, act, user.get_followers(&*conn));
} else { } else {
let like = likes::Like::for_user_on_post(&*conn, &user, &post).unwrap(); let like = likes::Like::for_user_on_post(&*conn, &user, &post).unwrap();
like.delete(&*conn); like.delete(&*conn);
broadcast(&*conn, &user, Delete::new(&user, &like, &*conn), user.get_followers(&*conn)); broadcast(&*conn, &user, Undo::new(&user, &like, &*conn), user.get_followers(&*conn));
} }
Redirect::to(format!("/~/{}/{}/", blog, slug).as_ref()) Redirect::to(format!("/~/{}/{}/", blog, slug).as_ref())
} }

View file

@ -62,6 +62,7 @@ table! {
user_id -> Int4, user_id -> Int4,
post_id -> Int4, post_id -> Int4,
creation_date -> Timestamp, creation_date -> Timestamp,
ap_url -> Varchar,
} }
} }