diff --git a/src/activity_pub/inbox.rs b/src/activity_pub/inbox.rs index 9e6586d..e7b119c 100644 --- a/src/activity_pub/inbox.rs +++ b/src/activity_pub/inbox.rs @@ -30,7 +30,7 @@ pub trait Inbox: Actor + Sized { }); }, "Note" => { - let previous_comment = Comment::get_by_ap_url(conn, act["object"]["inReplyTo"].as_str().unwrap().to_string()); + let previous_comment = Comment::find_by_ap_url(conn, act["object"]["inReplyTo"].as_str().unwrap().to_string()); Comment::insert(conn, NewComment { content: act["object"]["content"].as_str().unwrap().to_string(), spoiler_text: act["object"]["summary"].as_str().unwrap_or("").to_string(), @@ -38,7 +38,7 @@ pub trait Inbox: Actor + Sized { in_response_to_id: previous_comment.clone().map(|c| c.id), post_id: previous_comment .map(|c| c.post_id) - .unwrap_or_else(|| Post::get_by_ap_url(conn, act["object"]["inReplyTo"].as_str().unwrap().to_string()).unwrap().id), + .unwrap_or_else(|| Post::find_by_ap_url(conn, act["object"]["inReplyTo"].as_str().unwrap().to_string()).unwrap().id), author_id: User::from_url(conn, act["actor"].as_str().unwrap().to_string()).unwrap().id, sensitive: act["object"]["sensitive"].as_bool().unwrap_or(false) }); @@ -61,7 +61,7 @@ pub trait Inbox: Actor + Sized { } "Like" => { let liker = User::from_url(conn, act["actor"].as_str().unwrap().to_string()); - let post = Post::get_by_ap_url(conn, act["object"].as_str().unwrap().to_string()); + let post = Post::find_by_ap_url(conn, act["object"].as_str().unwrap().to_string()); Like::insert(conn, NewLike { post_id: post.unwrap().id, user_id: liker.unwrap().id, diff --git a/src/main.rs b/src/main.rs index db5103d..fbf7f86 100644 --- a/src/main.rs +++ b/src/main.rs @@ -69,13 +69,14 @@ fn main() { routes::user::me, routes::user::details, + routes::user::followers, routes::user::edit, routes::user::update, routes::user::follow, routes::user::activity_details, routes::user::outbox, routes::user::inbox, - routes::user::followers, + routes::user::ap_followers, routes::user::new, routes::user::create, diff --git a/src/models/comments.rs b/src/models/comments.rs index dbb9521..43f38e1 100644 --- a/src/models/comments.rs +++ b/src/models/comments.rs @@ -50,13 +50,13 @@ impl Comment { .into_iter().nth(0) } - pub fn for_post(conn: &PgConnection, post_id: i32) -> Vec { + pub fn find_by_post(conn: &PgConnection, post_id: i32) -> Vec { comments::table.filter(comments::post_id.eq(post_id)) .load::(conn) .expect("Error loading comment by post id") } - pub fn get_by_ap_url(conn: &PgConnection, ap_url: String) -> Option { + pub fn find_by_ap_url(conn: &PgConnection, ap_url: String) -> Option { comments::table.filter(comments::ap_url.eq(ap_url)) .limit(1) .load::(conn) diff --git a/src/models/instance.rs b/src/models/instance.rs index 9b302dc..626a6dc 100644 --- a/src/models/instance.rs +++ b/src/models/instance.rs @@ -61,7 +61,7 @@ impl Instance { .into_iter().nth(0) } - pub fn get_by_domain(conn: &PgConnection, domain: String) -> Option { + pub fn find_by_domain(conn: &PgConnection, domain: String) -> Option { instances::table.filter(instances::public_domain.eq(domain)) .limit(1) .load::(conn) @@ -69,7 +69,9 @@ impl Instance { .into_iter().nth(0) } - pub fn block(&self) {} + pub fn block(&self) { + unimplemented!() + } pub fn has_admin(&self, conn: &PgConnection) -> bool { users::table.filter(users::instance_id.eq(self.id)) diff --git a/src/models/likes.rs b/src/models/likes.rs index f822d49..1cf3bef 100644 --- a/src/models/likes.rs +++ b/src/models/likes.rs @@ -57,7 +57,7 @@ impl Like { .into_iter().nth(0) } - pub fn for_user_on_post(conn: &PgConnection, user: &User, post: &Post) -> Option { + pub fn find_by_user_on_post(conn: &PgConnection, user: &User, post: &Post) -> Option { likes::table.filter(likes::post_id.eq(post.id)) .filter(likes::user_id.eq(user.id)) .limit(1) diff --git a/src/models/posts.rs b/src/models/posts.rs index 9a2f1d0..87f8eea 100644 --- a/src/models/posts.rs +++ b/src/models/posts.rs @@ -39,7 +39,7 @@ pub struct NewPost { } impl Post { - pub fn insert (conn: &PgConnection, new: NewPost) -> Post { + pub fn insert(conn: &PgConnection, new: NewPost) -> Post { diesel::insert_into(posts::table) .values(new) .get_result(conn) @@ -62,7 +62,7 @@ impl Post { .into_iter().nth(0) } - pub fn get_by_ap_url(conn: &PgConnection, ap_url: String) -> Option { + pub fn find_by_ap_url(conn: &PgConnection, ap_url: String) -> Option { posts::table.filter(posts::ap_url.eq(ap_url)) .limit(1) .load::(conn) diff --git a/src/models/users.rs b/src/models/users.rs index 5580d5e..3b17c83 100644 --- a/src/models/users.rs +++ b/src/models/users.rs @@ -67,9 +67,14 @@ pub struct NewUser { } impl User { - pub fn grant_admin_rights() {} + pub fn grant_admin_rights(&self, conn: &PgConnection) { + diesel::update(self) + .set(users::is_admin.eq(true)) + .load::(conn) + .expect("Couldn't grant admin rights"); + } - pub fn insert (conn: &PgConnection, new: NewUser) -> User { + pub fn insert(conn: &PgConnection, new: NewUser) -> User { diesel::insert_into(users::table) .values(new) .get_result(conn) @@ -118,7 +123,7 @@ impl User { pub fn find_by_fqn(conn: &PgConnection, fqn: String) -> Option { if fqn.contains("@") { // remote user - match Instance::get_by_domain(conn, String::from(fqn.split("@").last().unwrap())) { + match Instance::find_by_domain(conn, String::from(fqn.split("@").last().unwrap())) { Some(instance) => { match User::find_by_name(conn, String::from(fqn.split("@").nth(0).unwrap()), instance.id) { Some(u) => Some(u), @@ -157,7 +162,7 @@ impl User { } fn from_activity(conn: &PgConnection, acct: serde_json::Value, inst: String) -> User { - let instance = match Instance::get_by_domain(conn, inst.clone()) { + let instance = match Instance::find_by_domain(conn, inst.clone()) { Some(instance) => instance, None => { Instance::insert(conn, inst.clone(), inst.clone(), false) @@ -219,6 +224,10 @@ impl User { posts.into_iter().map(|p| Arc::new(Create::new(self, &p, conn)) as Arc).collect::>>() } + pub fn get_fqn(&self, conn: &PgConnection) -> String { + format!("{}@{}", self.username, self.get_instance(conn).public_domain) + } + pub fn get_followers(&self, conn: &PgConnection) -> Vec { use schema::follows; let follows = Follow::belonging_to(self).select(follows::follower_id); diff --git a/src/routes/likes.rs b/src/routes/likes.rs index 2ccee27..30e8884 100644 --- a/src/routes/likes.rs +++ b/src/routes/likes.rs @@ -21,7 +21,7 @@ fn create(blog: String, slug: String, user: User, conn: DbConn) -> Redirect { let act = Like::new(&user, &post, &*conn); broadcast(&*conn, &user, act, user.get_followers(&*conn)); } else { - let like = likes::Like::for_user_on_post(&*conn, &user, &post).unwrap(); + let like = likes::Like::find_by_user_on_post(&*conn, &user, &post).unwrap(); like.delete(&*conn); broadcast(&*conn, &user, Undo::new(&user, &like, &*conn), user.get_followers(&*conn)); } diff --git a/src/routes/posts.rs b/src/routes/posts.rs index 6b3b9bd..d187f6c 100644 --- a/src/routes/posts.rs +++ b/src/routes/posts.rs @@ -20,7 +20,7 @@ use utils; fn details(blog: String, slug: String, conn: DbConn, user: Option) -> Template { let blog = Blog::find_by_actor_id(&*conn, blog).unwrap(); let post = Post::find_by_slug(&*conn, slug).unwrap(); - let comments = Comment::for_post(&*conn, post.id); + let comments = Comment::find_by_post(&*conn, post.id); Template::render("posts/details", json!({ "post": post, "blog": blog, diff --git a/src/routes/user.rs b/src/routes/user.rs index 833d29a..863fa0c 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -23,6 +23,7 @@ fn details(name: String, conn: DbConn, account: Option) -> Template { let user = User::find_by_fqn(&*conn, name).unwrap(); let recents = Post::get_recents_for_author(&*conn, &user, 5); let user_id = user.id.clone(); + let n_followers = user.get_followers(&*conn).len(); Template::render("users/details", json!({ "user": serde_json::to_value(user).unwrap(), @@ -35,7 +36,8 @@ fn details(name: String, conn: DbConn, account: Option) -> Template { "date": p.creation_date.timestamp() }) }).collect::>(), - "is_self": account.map(|a| a.id == user_id).unwrap_or(false) + "is_self": account.map(|a| a.id == user_id).unwrap_or(false), + "n_followers": n_followers })) } @@ -50,6 +52,24 @@ fn follow(name: String, conn: DbConn, user: User) -> Redirect { Redirect::to(format!("/@/{}", name).as_ref()) } +#[get("/@//followers", rank = 2)] +fn followers(name: String, conn: DbConn, account: Option) -> Template { + let user = User::find_by_fqn(&*conn, name.clone()).unwrap(); + let user_id = user.id.clone(); + + Template::render("users/followers", json!({ + "user": serde_json::to_value(user.clone()).unwrap(), + "followers": user.get_followers(&*conn).into_iter().map(|f| { + let fqn = f.get_fqn(&*conn); + let mut json = serde_json::to_value(f).unwrap(); + json["fqn"] = serde_json::Value::String(fqn); + json + }).collect::>(), + "account": account, + "is_self": account.map(|a| a.id == user_id).unwrap_or(false) + })) +} + #[get("/@/", format = "application/activity+json", rank = 1)] fn activity_details(name: String, conn: DbConn) -> ActivityPub { let user = User::find_local(&*conn, name).unwrap(); @@ -133,8 +153,8 @@ fn inbox(name: String, conn: DbConn, data: String) -> String { String::from("") } -#[get("/@//followers")] -fn followers(name: String, conn: DbConn) -> ActivityPub { +#[get("/@//followers", format = "application/activity+json")] +fn ap_followers(name: String, conn: DbConn) -> ActivityPub { let user = User::find_local(&*conn, name).unwrap(); let followers = user.get_followers(&*conn).into_iter().map(|f| f.compute_id(&*conn)).collect::>(); diff --git a/templates/users/details.tera b/templates/users/details.tera index 7cf5a8f..d48bb17 100644 --- a/templates/users/details.tera +++ b/templates/users/details.tera @@ -22,6 +22,10 @@ {% endif %} + +
{{ user.summary | safe }}
diff --git a/templates/users/followers.tera b/templates/users/followers.tera new file mode 100644 index 0000000..154c630 --- /dev/null +++ b/templates/users/followers.tera @@ -0,0 +1,28 @@ +{% extends "base" %} + +{% block title %} +{{ user.display_name }}'s Followers +{% endblock title %} + +{% block content %} +
+

+ {{ user.display_name }} + {% if user.is_admin %} + Admin + {% endif %} + + {% if is_self %} + It is you + {% endif %} +

+
+ +

Followers

+ {% for follower in followers %} +
+

{{ follower.display_name }} — @{{ follower.fqn }}

+

{{ follower.summary }}

+
+ {% endfor %} +{% endblock content %}