forked from nutomic/lemmy
Remove boilerplate code
This commit is contained in:
parent
6dac23b887
commit
48d237beb2
6 changed files with 120 additions and 225 deletions
6
server/Cargo.lock
generated
vendored
6
server/Cargo.lock
generated
vendored
|
@ -2,7 +2,7 @@
|
|||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "activitystreams"
|
||||
version = "0.5.0-alpha.4"
|
||||
version = "0.5.0-alpha.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"activitystreams-derive 0.5.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1562,7 +1562,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
name = "lemmy_server"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"activitystreams 0.5.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"activitystreams 0.5.0-alpha.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"actix 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"actix-files 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"actix-rt 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3282,7 +3282,7 @@ dependencies = [
|
|||
]
|
||||
|
||||
[metadata]
|
||||
"checksum activitystreams 0.5.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1f5d1db7f182bc74c9a6d2002cb7a5eb99b001ef41ddc8df1c21750ccc3638fa"
|
||||
"checksum activitystreams 0.5.0-alpha.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a9e82b6649331396e8bd17547a3b775ba7f530a30d574d43cf1d373899dafd94"
|
||||
"checksum activitystreams-derive 0.5.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f95c948a832a0b7b230b28369bafe79477bb8ebe7306dc97bcaff43832d3cc4d"
|
||||
"checksum actix 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4af87564ff659dee8f9981540cac9418c45e910c8072fdedd643a262a38fcaf"
|
||||
"checksum actix-codec 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "09e55f0a5c2ca15795035d90c46bd0e73a5123b72f68f12596d6ba5282051380"
|
||||
|
|
2
server/Cargo.toml
vendored
2
server/Cargo.toml
vendored
|
@ -9,7 +9,7 @@ diesel = { version = "1.4.2", features = ["postgres","chrono", "r2d2", "64-colum
|
|||
diesel_migrations = "1.4.0"
|
||||
dotenv = "0.15.0"
|
||||
bcrypt = "0.6.1"
|
||||
activitystreams = "0.5.0-alpha.4"
|
||||
activitystreams = "0.5.0-alpha.7"
|
||||
chrono = { version = "0.4.7", features = ["serde"] }
|
||||
failure = "0.1.5"
|
||||
serde_json = { version = "1.0.45", features = ["preserve_order"]}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::apub::make_apub_endpoint;
|
||||
use crate::apub::{create_apub_response, make_apub_endpoint};
|
||||
use crate::convert_datetime;
|
||||
use crate::db::community::Community;
|
||||
use crate::db::community_view::CommunityFollowerView;
|
||||
|
@ -12,134 +12,101 @@ use activitystreams::{
|
|||
use actix_web::body::Body;
|
||||
use actix_web::web::Path;
|
||||
use actix_web::HttpResponse;
|
||||
use actix_web::{web, Result};
|
||||
use diesel::r2d2::{ConnectionManager, Pool};
|
||||
use diesel::PgConnection;
|
||||
use failure::Error;
|
||||
use serde::Deserialize;
|
||||
|
||||
impl Community {
|
||||
pub fn as_group(&self) -> Result<Group, Error> {
|
||||
let base_url = make_apub_endpoint("c", &self.name);
|
||||
|
||||
let mut group = Group::default();
|
||||
let oprops: &mut ObjectProperties = group.as_mut();
|
||||
|
||||
oprops
|
||||
.set_context_xsd_any_uri(context())?
|
||||
.set_id(base_url.to_owned())?
|
||||
.set_name_xsd_string(self.title.to_owned())?
|
||||
.set_published(convert_datetime(self.published))?
|
||||
.set_attributed_to_xsd_any_uri(make_apub_endpoint("u", &self.creator_id))?;
|
||||
|
||||
if let Some(u) = self.updated.to_owned() {
|
||||
oprops.set_updated(convert_datetime(u))?;
|
||||
}
|
||||
if let Some(d) = self.description.to_owned() {
|
||||
oprops.set_summary_xsd_string(d)?;
|
||||
}
|
||||
|
||||
group
|
||||
.ap_actor_props
|
||||
.set_inbox(format!("{}/inbox", &base_url))?
|
||||
.set_outbox(format!("{}/outbox", &base_url))?
|
||||
.set_followers(format!("{}/followers", &base_url))?;
|
||||
|
||||
Ok(group)
|
||||
}
|
||||
|
||||
pub fn get_followers(&self) -> Result<UnorderedCollection, Error> {
|
||||
let base_url = make_apub_endpoint("c", &self.name);
|
||||
|
||||
let connection = establish_unpooled_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 mut collection = UnorderedCollection::default();
|
||||
let oprops: &mut ObjectProperties = collection.as_mut();
|
||||
oprops
|
||||
.set_context_xsd_any_uri(context())?
|
||||
.set_id(base_url)?;
|
||||
collection
|
||||
.collection_props
|
||||
.set_total_items(community_followers.len() as u64)?;
|
||||
Ok(collection)
|
||||
}
|
||||
|
||||
pub fn get_outbox(&self) -> Result<OrderedCollection, Error> {
|
||||
let base_url = make_apub_endpoint("c", &self.name);
|
||||
|
||||
let connection = establish_unpooled_connection();
|
||||
//As we are an object, we validated that the community id was valid
|
||||
let community_posts: Vec<PostView> = PostQueryBuilder::create(&connection)
|
||||
.for_community_id(self.id)
|
||||
.list()
|
||||
.unwrap();
|
||||
|
||||
let mut collection = OrderedCollection::default();
|
||||
let oprops: &mut ObjectProperties = collection.as_mut();
|
||||
oprops
|
||||
.set_context_xsd_any_uri(context())?
|
||||
.set_id(base_url)?;
|
||||
collection
|
||||
.collection_props
|
||||
.set_many_items_object_boxs(
|
||||
community_posts
|
||||
.iter()
|
||||
.map(|c| c.as_page().unwrap())
|
||||
.collect(),
|
||||
)?
|
||||
.set_total_items(community_posts.len() as u64)?;
|
||||
|
||||
Ok(collection)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CommunityQuery {
|
||||
community_name: String,
|
||||
}
|
||||
|
||||
// TODO: move all this boilerplate code to routes::federation or such
|
||||
pub async fn get_apub_community(info: Path<CommunityQuery>) -> Result<HttpResponse<Body>, Error> {
|
||||
let connection = establish_unpooled_connection();
|
||||
pub async fn get_apub_community(
|
||||
info: Path<CommunityQuery>,
|
||||
db: web::Data<Pool<ConnectionManager<PgConnection>>>,
|
||||
) -> Result<HttpResponse<Body>, Error> {
|
||||
let community = Community::read_from_name(&&db.get()?, info.community_name.to_owned())?;
|
||||
let base_url = make_apub_endpoint("c", &community.name);
|
||||
|
||||
if let Ok(community) = Community::read_from_name(&connection, info.community_name.to_owned()) {
|
||||
Ok(
|
||||
HttpResponse::Ok()
|
||||
.content_type("application/activity+json")
|
||||
.body(serde_json::to_string(&community.as_group()?).unwrap()),
|
||||
)
|
||||
} else {
|
||||
Ok(HttpResponse::NotFound().finish())
|
||||
let mut group = Group::default();
|
||||
let oprops: &mut ObjectProperties = group.as_mut();
|
||||
|
||||
oprops
|
||||
.set_context_xsd_any_uri(context())?
|
||||
.set_id(base_url.to_owned())?
|
||||
.set_name_xsd_string(community.title.to_owned())?
|
||||
.set_published(convert_datetime(community.published))?
|
||||
.set_attributed_to_xsd_any_uri(make_apub_endpoint("u", &community.creator_id))?;
|
||||
|
||||
if let Some(u) = community.updated.to_owned() {
|
||||
oprops.set_updated(convert_datetime(u))?;
|
||||
}
|
||||
if let Some(d) = community.description {
|
||||
oprops.set_summary_xsd_string(d)?;
|
||||
}
|
||||
|
||||
group
|
||||
.ap_actor_props
|
||||
.set_inbox(format!("{}/inbox", &base_url))?
|
||||
.set_outbox(format!("{}/outbox", &base_url))?
|
||||
.set_followers(format!("{}/followers", &base_url))?;
|
||||
|
||||
Ok(create_apub_response(serde_json::to_string(&group)?))
|
||||
}
|
||||
|
||||
pub async fn get_apub_community_followers(
|
||||
info: Path<CommunityQuery>,
|
||||
db: web::Data<Pool<ConnectionManager<PgConnection>>>,
|
||||
) -> Result<HttpResponse<Body>, Error> {
|
||||
let connection = establish_unpooled_connection();
|
||||
let community = Community::read_from_name(&&db.get()?, info.community_name.to_owned())?;
|
||||
let base_url = make_apub_endpoint("c", &community.name);
|
||||
|
||||
if let Ok(community) = Community::read_from_name(&connection, info.community_name.to_owned()) {
|
||||
Ok(
|
||||
HttpResponse::Ok()
|
||||
.content_type("application/activity+json")
|
||||
.body(serde_json::to_string(&community.get_followers()?).unwrap()),
|
||||
)
|
||||
} else {
|
||||
Ok(HttpResponse::NotFound().finish())
|
||||
}
|
||||
let connection = establish_unpooled_connection();
|
||||
//As we are an object, we validated that the community id was valid
|
||||
let community_followers =
|
||||
CommunityFollowerView::for_community(&connection, community.id).unwrap();
|
||||
|
||||
let mut collection = UnorderedCollection::default();
|
||||
let oprops: &mut ObjectProperties = collection.as_mut();
|
||||
oprops
|
||||
.set_context_xsd_any_uri(context())?
|
||||
.set_id(base_url)?;
|
||||
collection
|
||||
.collection_props
|
||||
.set_total_items(community_followers.len() as u64)?;
|
||||
Ok(create_apub_response(serde_json::to_string(&collection)?))
|
||||
}
|
||||
|
||||
pub async fn get_apub_community_outbox(
|
||||
info: Path<CommunityQuery>,
|
||||
db: web::Data<Pool<ConnectionManager<PgConnection>>>,
|
||||
) -> Result<HttpResponse<Body>, Error> {
|
||||
let connection = establish_unpooled_connection();
|
||||
let community = Community::read_from_name(&&db.get()?, info.community_name.to_owned())?;
|
||||
let base_url = make_apub_endpoint("c", &community.name);
|
||||
|
||||
if let Ok(community) = Community::read_from_name(&connection, info.community_name.to_owned()) {
|
||||
Ok(
|
||||
HttpResponse::Ok()
|
||||
.content_type("application/activity+json")
|
||||
.body(serde_json::to_string(&community.get_outbox()?).unwrap()),
|
||||
)
|
||||
} else {
|
||||
Ok(HttpResponse::NotFound().finish())
|
||||
}
|
||||
let connection = establish_unpooled_connection();
|
||||
//As we are an object, we validated that the community id was valid
|
||||
let community_posts: Vec<PostView> = PostQueryBuilder::create(&connection)
|
||||
.for_community_id(community.id)
|
||||
.list()
|
||||
.unwrap();
|
||||
|
||||
let mut collection = OrderedCollection::default();
|
||||
let oprops: &mut ObjectProperties = collection.as_mut();
|
||||
oprops
|
||||
.set_context_xsd_any_uri(context())?
|
||||
.set_id(base_url)?;
|
||||
collection
|
||||
.collection_props
|
||||
.set_many_items_object_boxs(
|
||||
community_posts
|
||||
.iter()
|
||||
.map(|c| c.as_page().unwrap())
|
||||
.collect(),
|
||||
)?
|
||||
.set_total_items(community_posts.len() as u64)?;
|
||||
|
||||
Ok(create_apub_response(serde_json::to_string(&collection)?))
|
||||
}
|
||||
|
|
|
@ -3,76 +3,21 @@ pub mod post;
|
|||
pub mod puller;
|
||||
pub mod user;
|
||||
use crate::Settings;
|
||||
use failure::Error;
|
||||
|
||||
use actix_web::body::Body;
|
||||
use actix_web::HttpResponse;
|
||||
use std::fmt::Display;
|
||||
use url::Url;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::db::community::Community;
|
||||
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,
|
||||
matrix_user_id: None,
|
||||
avatar: 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(),
|
||||
show_avatars: true,
|
||||
send_notifications_to_email: false,
|
||||
};
|
||||
|
||||
let person = user.as_person();
|
||||
assert_eq!(
|
||||
format!("https://{}/federation/u/thom", Settings::get().hostname),
|
||||
person.unwrap().object_props.get_id().unwrap().to_string()
|
||||
);
|
||||
}
|
||||
|
||||
#[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.unwrap().object_props.get_id().unwrap().to_string()
|
||||
);
|
||||
}
|
||||
fn create_apub_response(json_data: String) -> HttpResponse<Body> {
|
||||
HttpResponse::Ok()
|
||||
.content_type("application/activity+json")
|
||||
.body(json_data)
|
||||
}
|
||||
|
||||
// TODO: this should take an enum community/user/post for `point`
|
||||
// TODO: also not sure what exactly `value` should be (numeric id, name string, ...)
|
||||
pub fn make_apub_endpoint<S: Display, T: Display>(point: S, value: T) -> Url {
|
||||
fn make_apub_endpoint<S: Display, T: Display>(point: S, value: T) -> Url {
|
||||
Url::parse(&format!(
|
||||
"{}://{}/federation/{}/{}",
|
||||
get_apub_protocol_string(),
|
||||
|
@ -83,13 +28,6 @@ pub fn make_apub_endpoint<S: Display, T: Display>(point: S, value: T) -> Url {
|
|||
.unwrap()
|
||||
}
|
||||
|
||||
/// Parses an ID generated by `make_apub_endpoint()`. Will break when federating with anything
|
||||
/// that is not Lemmy. This is just a crutch until we change the database to store URLs as ID.
|
||||
pub fn parse_apub_endpoint(id: &str) -> Result<(&str, &str), Error> {
|
||||
let split = id.split('/').collect::<Vec<&str>>();
|
||||
Ok((split[4], split[5]))
|
||||
}
|
||||
|
||||
pub fn get_apub_protocol_string() -> &'static str {
|
||||
fn get_apub_protocol_string() -> &'static str {
|
||||
"http"
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ where
|
|||
{
|
||||
// TODO: should cache responses here when we are in production
|
||||
// TODO: this function should return a future
|
||||
// TODO: in production mode, fail if protocol is not https
|
||||
let x: Response = reqwest::get(uri)?.json()?;
|
||||
Ok(x)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::apub::make_apub_endpoint;
|
||||
use crate::apub::{make_apub_endpoint, create_apub_response};
|
||||
use crate::convert_datetime;
|
||||
use crate::db::establish_unpooled_connection;
|
||||
use crate::db::user::User_;
|
||||
use activitystreams::{actor::apub::Person, context, object::properties::ObjectProperties};
|
||||
use actix_web::body::Body;
|
||||
|
@ -8,52 +7,42 @@ use actix_web::web::Path;
|
|||
use actix_web::HttpResponse;
|
||||
use failure::Error;
|
||||
use serde::Deserialize;
|
||||
|
||||
impl User_ {
|
||||
pub fn as_person(&self) -> Result<Person, Error> {
|
||||
let base_url = make_apub_endpoint("u", &self.name);
|
||||
|
||||
let mut person = Person::default();
|
||||
let oprops: &mut ObjectProperties = person.as_mut();
|
||||
oprops
|
||||
.set_context_xsd_any_uri(context())?
|
||||
.set_id(base_url.to_string())?
|
||||
.set_published(convert_datetime(self.published))?;
|
||||
|
||||
if let Some(u) = self.updated {
|
||||
oprops.set_updated(convert_datetime(u))?;
|
||||
}
|
||||
|
||||
if let Some(i) = &self.preferred_username {
|
||||
oprops.set_name_xsd_string(i.to_owned())?;
|
||||
}
|
||||
|
||||
person
|
||||
.ap_actor_props
|
||||
.set_inbox(format!("{}/inbox", &base_url))?
|
||||
.set_outbox(format!("{}/outbox", &base_url))?
|
||||
.set_following(format!("{}/following", &base_url))?
|
||||
.set_liked(format!("{}/liked", &base_url))?;
|
||||
|
||||
Ok(person)
|
||||
}
|
||||
}
|
||||
use diesel::r2d2::{ConnectionManager, Pool};
|
||||
use diesel::PgConnection;
|
||||
use actix_web::{web, Result};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct UserQuery {
|
||||
user_name: String,
|
||||
}
|
||||
|
||||
pub async fn get_apub_user(info: Path<UserQuery>) -> Result<HttpResponse<Body>, Error> {
|
||||
let connection = establish_unpooled_connection();
|
||||
pub async fn get_apub_user(
|
||||
info: Path<UserQuery>,
|
||||
db: web::Data<Pool<ConnectionManager<PgConnection>>>,) -> Result<HttpResponse<Body>, Error> {
|
||||
let user = User_::find_by_email_or_username(&&db.get()?, &info.user_name)?;
|
||||
let base_url = make_apub_endpoint("u", &user.name);
|
||||
|
||||
if let Ok(user) = User_::find_by_email_or_username(&connection, &info.user_name) {
|
||||
Ok(
|
||||
HttpResponse::Ok()
|
||||
.content_type("application/activity+json")
|
||||
.body(serde_json::to_string(&user.as_person()?).unwrap()),
|
||||
)
|
||||
} else {
|
||||
Ok(HttpResponse::NotFound().finish())
|
||||
let mut person = Person::default();
|
||||
let oprops: &mut ObjectProperties = person.as_mut();
|
||||
oprops
|
||||
.set_context_xsd_any_uri(context())?
|
||||
.set_id(base_url.to_string())?
|
||||
.set_published(convert_datetime(user.published))?;
|
||||
|
||||
if let Some(u) = user.updated {
|
||||
oprops.set_updated(convert_datetime(u))?;
|
||||
}
|
||||
|
||||
if let Some(i) = &user.preferred_username {
|
||||
oprops.set_name_xsd_string(i.to_owned())?;
|
||||
}
|
||||
|
||||
person
|
||||
.ap_actor_props
|
||||
.set_inbox(format!("{}/inbox", &base_url))?
|
||||
.set_outbox(format!("{}/outbox", &base_url))?
|
||||
.set_following(format!("{}/following", &base_url))?
|
||||
.set_liked(format!("{}/liked", &base_url))?;
|
||||
|
||||
Ok(create_apub_response(serde_json::to_string(&person)?))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue