CommentLike::remove(&conn, &like_form)?;
// Only add the like if the score isnt 0
- let do_add = &like_form.score != &0 && (&like_form.score == &1 || &like_form.score == &-1);
+ let do_add = like_form.score != 0 && (like_form.score == 1 || like_form.score == -1);
if do_add {
let _inserted_like = match CommentLike::like(&conn, &like_form) {
Ok(like) => like,
+++ /dev/null
-extern crate activitypub;
-use self::activitypub::{actor::Person, context};
-use crate::db::user::User_;
-
-impl User_ {
- pub fn person(&self) -> Person {
- use crate::{to_datetime_utc, Settings};
- let base_url = &format!("{}/user/{}", Settings::get().api_endpoint(), self.name);
- let mut person = Person::default();
- person.object_props.set_context_object(context()).ok();
- person.object_props.set_id_string(base_url.to_string()).ok();
- person
- .object_props
- .set_name_string(self.name.to_owned())
- .ok();
- person
- .object_props
- .set_published_utctime(to_datetime_utc(self.published))
- .ok();
- if let Some(i) = self.updated {
- person
- .object_props
- .set_updated_utctime(to_datetime_utc(i))
- .ok();
- }
- // person.object_props.summary = self.summary;
-
- person
- .ap_actor_props
- .set_inbox_string(format!("{}/inbox", &base_url))
- .ok();
- person
- .ap_actor_props
- .set_outbox_string(format!("{}/outbox", &base_url))
- .ok();
- person
- .ap_actor_props
- .set_following_string(format!("{}/following", &base_url))
- .ok();
- person
- .ap_actor_props
- .set_liked_string(format!("{}/liked", &base_url))
- .ok();
- if let Some(i) = &self.preferred_username {
- person
- .ap_actor_props
- .set_preferred_username_string(i.to_string())
- .ok();
- }
-
- person
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::User_;
- use crate::db::{ListingType, SortType};
- use crate::naive_now;
-
- #[test]
- fn test_person() {
- let expected_user = User_ {
- id: 52,
- name: "thom".into(),
- fedi_name: "rrf".into(),
- preferred_username: None,
- password_encrypted: "here".into(),
- email: None,
- icon: None,
- published: naive_now(),
- admin: false,
- banned: false,
- updated: None,
- show_nsfw: false,
- theme: "darkly".into(),
- default_sort_type: SortType::Hot as i16,
- default_listing_type: ListingType::Subscribed as i16,
- lang: "browser".into(),
- };
-
- let person = expected_user.person();
- assert_eq!(
- "rrr/api/v1/user/thom",
- person.object_props.id_string().unwrap()
- );
- let json = serde_json::to_string_pretty(&person).unwrap();
- println!("{}", json);
- }
-}
--- /dev/null
+use crate::apub::make_apub_endpoint;
+use crate::db::community::Community;
+use crate::db::community_view::CommunityFollowerView;
+use crate::db::establish_connection;
+use crate::to_datetime_utc;
+use activitypub::{actor::Group, collection::UnorderedCollection, context};
+use actix_web::body::Body;
+use actix_web::web::Path;
+use actix_web::HttpResponse;
+use serde::Deserialize;
+
+impl Community {
+ pub fn as_group(&self) -> Group {
+ let base_url = make_apub_endpoint("c", &self.name);
+
+ let mut group = Group::default();
+
+ group.object_props.set_context_object(context()).ok();
+ group.object_props.set_id_string(base_url.to_string()).ok();
+ group
+ .object_props
+ .set_name_string(self.name.to_owned())
+ .ok();
+ group
+ .object_props
+ .set_published_utctime(to_datetime_utc(self.published))
+ .ok();
+ if let Some(updated) = self.updated {
+ group
+ .object_props
+ .set_updated_utctime(to_datetime_utc(updated))
+ .ok();
+ }
+
+ if let Some(description) = &self.description {
+ group
+ .object_props
+ .set_summary_string(description.to_string())
+ .ok();
+ }
+
+ group
+ .ap_actor_props
+ .set_inbox_string(format!("{}/inbox", &base_url))
+ .ok();
+ group
+ .ap_actor_props
+ .set_outbox_string(format!("{}/outbox", &base_url))
+ .ok();
+ group
+ .ap_actor_props
+ .set_followers_string(format!("{}/followers", &base_url))
+ .ok();
+
+ group
+ }
+
+ pub fn followers_as_collection(&self) -> UnorderedCollection {
+ let base_url = make_apub_endpoint("c", &self.name);
+
+ let mut collection = UnorderedCollection::default();
+ collection.object_props.set_context_object(context()).ok();
+ collection
+ .object_props
+ .set_id_string(base_url.to_string())
+ .ok();
+
+ let connection = establish_connection();
+ //As we are an object, we validated that the community id was valid
+ let community_followers = CommunityFollowerView::for_community(&connection, self.id).unwrap();
+
+ let ap_followers = community_followers
+ .iter()
+ .map(|follower| make_apub_endpoint("u", &follower.user_name))
+ .collect();
+
+ collection
+ .collection_props
+ .set_items_string_vec(ap_followers)
+ .unwrap();
+ collection
+ }
+}
+
+#[derive(Deserialize)]
+pub struct CommunityQuery {
+ community_name: String,
+}
+
+pub fn get_apub_community(info: Path<CommunityQuery>) -> HttpResponse<Body> {
+ let connection = establish_connection();
+
+ if let Ok(community) = Community::read_from_name(&connection, info.community_name.to_owned()) {
+ HttpResponse::Ok()
+ .content_type("application/activity+json")
+ .body(serde_json::to_string(&community.as_group()).unwrap())
+ } else {
+ HttpResponse::NotFound().finish()
+ }
+}
+
+pub fn get_apub_community_followers(info: Path<CommunityQuery>) -> HttpResponse<Body> {
+ let connection = establish_connection();
+
+ if let Ok(community) = Community::read_from_name(&connection, info.community_name.to_owned()) {
+ HttpResponse::Ok()
+ .content_type("application/activity+json")
+ .body(serde_json::to_string(&community.followers_as_collection()).unwrap())
+ } else {
+ HttpResponse::NotFound().finish()
+ }
+}
--- /dev/null
+pub mod community;
+pub mod post;
+pub mod user;
+use crate::Settings;
+
+use std::fmt::Display;
+
+#[cfg(test)]
+mod tests {
+ use crate::db::community::Community;
+ use crate::db::post::Post;
+ use crate::db::user::User_;
+ use crate::db::{ListingType, SortType};
+ use crate::{naive_now, Settings};
+
+ #[test]
+ fn test_person() {
+ let user = User_ {
+ id: 52,
+ name: "thom".into(),
+ fedi_name: "rrf".into(),
+ preferred_username: None,
+ password_encrypted: "here".into(),
+ email: None,
+ icon: None,
+ published: naive_now(),
+ admin: false,
+ banned: false,
+ updated: None,
+ show_nsfw: false,
+ theme: "darkly".into(),
+ default_sort_type: SortType::Hot as i16,
+ default_listing_type: ListingType::Subscribed as i16,
+ lang: "browser".into(),
+ };
+
+ let person = user.as_person();
+ assert_eq!(
+ format!("https://{}/federation/u/thom", Settings::get().hostname),
+ person.object_props.id_string().unwrap()
+ );
+ }
+
+ #[test]
+ fn test_community() {
+ let community = Community {
+ id: 42,
+ name: "Test".into(),
+ title: "Test Title".into(),
+ description: Some("Test community".into()),
+ category_id: 32,
+ creator_id: 52,
+ removed: false,
+ published: naive_now(),
+ updated: Some(naive_now()),
+ deleted: false,
+ nsfw: false,
+ };
+
+ let group = community.as_group();
+ assert_eq!(
+ format!("https://{}/federation/c/Test", Settings::get().hostname),
+ group.object_props.id_string().unwrap()
+ );
+ }
+
+ #[test]
+ fn test_post() {
+ let post = Post {
+ id: 62,
+ name: "A test post".into(),
+ url: None,
+ body: None,
+ creator_id: 52,
+ community_id: 42,
+ published: naive_now(),
+ removed: false,
+ locked: false,
+ stickied: false,
+ nsfw: false,
+ deleted: false,
+ updated: None,
+ };
+
+ let page = post.as_page();
+ assert_eq!(
+ format!("https://{}/federation/post/62", Settings::get().hostname),
+ page.object_props.id_string().unwrap()
+ );
+ }
+}
+
+pub fn make_apub_endpoint<S: Display, T: Display>(point: S, value: T) -> String {
+ format!(
+ "https://{}/federation/{}/{}",
+ Settings::get().hostname,
+ point,
+ value
+ )
+}
--- /dev/null
+use crate::apub::make_apub_endpoint;
+use crate::db::post::Post;
+use crate::to_datetime_utc;
+use activitypub::{context, object::Page};
+
+impl Post {
+ pub fn as_page(&self) -> Page {
+ let base_url = make_apub_endpoint("post", self.id);
+ let mut page = Page::default();
+
+ page.object_props.set_context_object(context()).ok();
+ page.object_props.set_id_string(base_url.to_string()).ok();
+ page.object_props.set_name_string(self.name.to_owned()).ok();
+
+ if let Some(body) = &self.body {
+ page.object_props.set_content_string(body.to_owned()).ok();
+ }
+
+ if let Some(url) = &self.url {
+ page.object_props.set_url_string(url.to_owned()).ok();
+ }
+
+ //page.object_props.set_attributed_to_string
+
+ page
+ .object_props
+ .set_published_utctime(to_datetime_utc(self.published))
+ .ok();
+ if let Some(updated) = self.updated {
+ page
+ .object_props
+ .set_updated_utctime(to_datetime_utc(updated))
+ .ok();
+ }
+
+ page
+ }
+}
--- /dev/null
+use crate::apub::make_apub_endpoint;
+use crate::db::establish_connection;
+use crate::db::user::User_;
+use crate::to_datetime_utc;
+use activitypub::{actor::Person, context};
+use actix_web::body::Body;
+use actix_web::web::Path;
+use actix_web::HttpResponse;
+use serde::Deserialize;
+
+impl User_ {
+ pub fn as_person(&self) -> Person {
+ let base_url = make_apub_endpoint("u", &self.name);
+ let mut person = Person::default();
+ person.object_props.set_context_object(context()).ok();
+ person.object_props.set_id_string(base_url.to_string()).ok();
+ person
+ .object_props
+ .set_name_string(self.name.to_owned())
+ .ok();
+ person
+ .object_props
+ .set_published_utctime(to_datetime_utc(self.published))
+ .ok();
+ if let Some(updated) = self.updated {
+ person
+ .object_props
+ .set_updated_utctime(to_datetime_utc(updated))
+ .ok();
+ }
+
+ person
+ .ap_actor_props
+ .set_inbox_string(format!("{}/inbox", &base_url))
+ .ok();
+ person
+ .ap_actor_props
+ .set_outbox_string(format!("{}/outbox", &base_url))
+ .ok();
+ person
+ .ap_actor_props
+ .set_following_string(format!("{}/following", &base_url))
+ .ok();
+ person
+ .ap_actor_props
+ .set_liked_string(format!("{}/liked", &base_url))
+ .ok();
+ if let Some(i) = &self.preferred_username {
+ person
+ .ap_actor_props
+ .set_preferred_username_string(i.to_string())
+ .ok();
+ }
+
+ person
+ }
+}
+
+#[derive(Deserialize)]
+pub struct UserQuery {
+ user_name: String,
+}
+
+pub fn get_apub_user(info: Path<UserQuery>) -> HttpResponse<Body> {
+ let connection = establish_connection();
+
+ if let Ok(user) = User_::find_by_email_or_username(&connection, &info.user_name) {
+ HttpResponse::Ok()
+ .content_type("application/activity+json")
+ .body(serde_json::to_string(&user.as_person()).unwrap())
+ } else {
+ HttpResponse::NotFound().finish()
+ }
+}
email_config,
}
}
- fn api_endpoint(&self) -> String {
- format!("{}/api/v1", self.hostname)
- }
}
pub fn to_datetime_utc(ndt: NaiveDateTime) -> DateTime<Utc> {
#[cfg(test)]
mod tests {
use crate::{extract_usernames, has_slurs, is_email_regex, remove_slurs, Settings};
- #[test]
- fn test_api() {
- assert_eq!(Settings::get().api_endpoint(), "rrr/api/v1");
- }
#[test]
fn test_email() {
use actix_files::NamedFile;
use actix_web::*;
use actix_web_actors::ws;
+use lemmy_server::apub;
use lemmy_server::db::establish_connection;
use lemmy_server::feeds;
use lemmy_server::nodeinfo;
// RSS
.route("/feeds/{type}/{name}.xml", web::get().to(feeds::get_feed))
.route("/feeds/all.xml", web::get().to(feeds::get_all_feed))
+ // Federation
+ .route(
+ "/federation/c/{community_name}",
+ web::get().to(apub::community::get_apub_community),
+ )
+ .route(
+ "/federation/c/{community_name}/followers",
+ web::get().to(apub::community::get_apub_community_followers),
+ )
+ .route(
+ "/federation/u/{user_name}",
+ web::get().to(apub::user::get_apub_user),
+ )
})
.bind((settings.bind, settings.port))
.unwrap()