Compare commits

...

1 commit

Author SHA1 Message Date
ef25414aff First sync try, not working. 2020-04-16 13:11:33 -04:00
19 changed files with 602 additions and 348 deletions

View file

@ -65,17 +65,21 @@ pub struct GetCommentsResponse {
} }
impl Perform<CommentResponse> for Oper<CreateComment> { impl Perform<CommentResponse> for Oper<CreateComment> {
fn perform(&self, conn: &PgConnection) -> Result<CommentResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<CommentResponse, Error> {
let data: &CreateComment = &self.data; let data: &CreateComment = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
let user_id = claims.id; let user_id = claims.id;
let hostname = &format!("https://{}", Settings::get().hostname); let hostname = &format!("https://{}", settings.hostname);
// Check for a community ban // Check for a community ban
let post = Post::read(&conn, data.post_id)?; let post = Post::read(&conn, data.post_id)?;
@ -137,14 +141,14 @@ impl Perform<CommentResponse> for Oper<CreateComment> {
if let Some(mention_email) = mention_user.email { if let Some(mention_email) = mention_user.email {
let subject = &format!( let subject = &format!(
"{} - Mentioned by {}", "{} - Mentioned by {}",
Settings::get().hostname, settings.hostname,
claims.username claims.username
); );
let html = &format!( let html = &format!(
"<h1>User Mention</h1><br><div>{} - {}</div><br><a href={}/inbox>inbox</a>", "<h1>User Mention</h1><br><div>{} - {}</div><br><a href={}/inbox>inbox</a>",
claims.username, comment_form.content, hostname claims.username, comment_form.content, hostname
); );
match send_email(subject, &mention_email, &mention_user.name, html) { match send_email(subject, &mention_email, &mention_user.name, html, settings) {
Ok(_o) => _o, Ok(_o) => _o,
Err(e) => error!("{}", e), Err(e) => error!("{}", e),
}; };
@ -166,14 +170,14 @@ impl Perform<CommentResponse> for Oper<CreateComment> {
if let Some(comment_reply_email) = parent_user.email { if let Some(comment_reply_email) = parent_user.email {
let subject = &format!( let subject = &format!(
"{} - Reply from {}", "{} - Reply from {}",
Settings::get().hostname, settings.hostname,
claims.username claims.username
); );
let html = &format!( let html = &format!(
"<h1>Comment Reply</h1><br><div>{} - {}</div><br><a href={}/inbox>inbox</a>", "<h1>Comment Reply</h1><br><div>{} - {}</div><br><a href={}/inbox>inbox</a>",
claims.username, comment_form.content, hostname claims.username, comment_form.content, hostname
); );
match send_email(subject, &comment_reply_email, &parent_user.name, html) { match send_email(subject, &comment_reply_email, &parent_user.name, html, settings) {
Ok(_o) => _o, Ok(_o) => _o,
Err(e) => error!("{}", e), Err(e) => error!("{}", e),
}; };
@ -191,14 +195,14 @@ impl Perform<CommentResponse> for Oper<CreateComment> {
if let Some(post_reply_email) = parent_user.email { if let Some(post_reply_email) = parent_user.email {
let subject = &format!( let subject = &format!(
"{} - Reply from {}", "{} - Reply from {}",
Settings::get().hostname, settings.hostname,
claims.username claims.username
); );
let html = &format!( let html = &format!(
"<h1>Post Reply</h1><br><div>{} - {}</div><br><a href={}/inbox>inbox</a>", "<h1>Post Reply</h1><br><div>{} - {}</div><br><a href={}/inbox>inbox</a>",
claims.username, comment_form.content, hostname claims.username, comment_form.content, hostname
); );
match send_email(subject, &post_reply_email, &parent_user.name, html) { match send_email(subject, &post_reply_email, &parent_user.name, html, settings) {
Ok(_o) => _o, Ok(_o) => _o,
Err(e) => error!("{}", e), Err(e) => error!("{}", e),
}; };
@ -231,10 +235,14 @@ impl Perform<CommentResponse> for Oper<CreateComment> {
} }
impl Perform<CommentResponse> for Oper<EditComment> { impl Perform<CommentResponse> for Oper<EditComment> {
fn perform(&self, conn: &PgConnection) -> Result<CommentResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<CommentResponse, Error> {
let data: &EditComment = &self.data; let data: &EditComment = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -361,10 +369,14 @@ impl Perform<CommentResponse> for Oper<EditComment> {
} }
impl Perform<CommentResponse> for Oper<SaveComment> { impl Perform<CommentResponse> for Oper<SaveComment> {
fn perform(&self, conn: &PgConnection) -> Result<CommentResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<CommentResponse, Error> {
let data: &SaveComment = &self.data; let data: &SaveComment = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -398,10 +410,14 @@ impl Perform<CommentResponse> for Oper<SaveComment> {
} }
impl Perform<CommentResponse> for Oper<CreateCommentLike> { impl Perform<CommentResponse> for Oper<CreateCommentLike> {
fn perform(&self, conn: &PgConnection) -> Result<CommentResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<CommentResponse, Error> {
let data: &CreateCommentLike = &self.data; let data: &CreateCommentLike = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -475,11 +491,15 @@ impl Perform<CommentResponse> for Oper<CreateCommentLike> {
} }
impl Perform<GetCommentsResponse> for Oper<GetComments> { impl Perform<GetCommentsResponse> for Oper<GetComments> {
fn perform(&self, conn: &PgConnection) -> Result<GetCommentsResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<GetCommentsResponse, Error> {
let data: &GetComments = &self.data; let data: &GetComments = &self.data;
let user_claims: Option<Claims> = match &data.auth { let user_claims: Option<Claims> = match &data.auth {
Some(auth) => match Claims::decode(&auth) { Some(auth) => match Claims::decode(&auth, &settings.jwt_secret) {
Ok(claims) => Some(claims.claims), Ok(claims) => Some(claims.claims),
Err(_e) => None, Err(_e) => None,
}, },

View file

@ -114,11 +114,15 @@ pub struct TransferCommunity {
} }
impl Perform<GetCommunityResponse> for Oper<GetCommunity> { impl Perform<GetCommunityResponse> for Oper<GetCommunity> {
fn perform(&self, conn: &PgConnection) -> Result<GetCommunityResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<GetCommunityResponse, Error> {
let data: &GetCommunity = &self.data; let data: &GetCommunity = &self.data;
let user_id: Option<i32> = match &data.auth { let user_id: Option<i32> = match &data.auth {
Some(auth) => match Claims::decode(&auth) { Some(auth) => match Claims::decode(&auth, &settings.jwt_secret) {
Ok(claims) => { Ok(claims) => {
let user_id = claims.claims.id; let user_id = claims.claims.id;
Some(user_id) Some(user_id)
@ -168,10 +172,14 @@ impl Perform<GetCommunityResponse> for Oper<GetCommunity> {
} }
impl Perform<CommunityResponse> for Oper<CreateCommunity> { impl Perform<CommunityResponse> for Oper<CreateCommunity> {
fn perform(&self, conn: &PgConnection) -> Result<CommunityResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<CommunityResponse, Error> {
let data: &CreateCommunity = &self.data; let data: &CreateCommunity = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -246,7 +254,11 @@ impl Perform<CommunityResponse> for Oper<CreateCommunity> {
} }
impl Perform<CommunityResponse> for Oper<EditCommunity> { impl Perform<CommunityResponse> for Oper<EditCommunity> {
fn perform(&self, conn: &PgConnection) -> Result<CommunityResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<CommunityResponse, Error> {
let data: &EditCommunity = &self.data; let data: &EditCommunity = &self.data;
if let Err(slurs) = slur_check(&data.name) { if let Err(slurs) = slur_check(&data.name) {
@ -263,7 +275,7 @@ impl Perform<CommunityResponse> for Oper<EditCommunity> {
} }
} }
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -330,11 +342,15 @@ impl Perform<CommunityResponse> for Oper<EditCommunity> {
} }
impl Perform<ListCommunitiesResponse> for Oper<ListCommunities> { impl Perform<ListCommunitiesResponse> for Oper<ListCommunities> {
fn perform(&self, conn: &PgConnection) -> Result<ListCommunitiesResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<ListCommunitiesResponse, Error> {
let data: &ListCommunities = &self.data; let data: &ListCommunities = &self.data;
let user_claims: Option<Claims> = match &data.auth { let user_claims: Option<Claims> = match &data.auth {
Some(auth) => match Claims::decode(&auth) { Some(auth) => match Claims::decode(&auth, &settings.jwt_secret) {
Ok(claims) => Some(claims.claims), Ok(claims) => Some(claims.claims),
Err(_e) => None, Err(_e) => None,
}, },
@ -367,10 +383,14 @@ impl Perform<ListCommunitiesResponse> for Oper<ListCommunities> {
} }
impl Perform<CommunityResponse> for Oper<FollowCommunity> { impl Perform<CommunityResponse> for Oper<FollowCommunity> {
fn perform(&self, conn: &PgConnection) -> Result<CommunityResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<CommunityResponse, Error> {
let data: &FollowCommunity = &self.data; let data: &FollowCommunity = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -403,10 +423,14 @@ impl Perform<CommunityResponse> for Oper<FollowCommunity> {
} }
impl Perform<GetFollowedCommunitiesResponse> for Oper<GetFollowedCommunities> { impl Perform<GetFollowedCommunitiesResponse> for Oper<GetFollowedCommunities> {
fn perform(&self, conn: &PgConnection) -> Result<GetFollowedCommunitiesResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<GetFollowedCommunitiesResponse, Error> {
let data: &GetFollowedCommunities = &self.data; let data: &GetFollowedCommunities = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -425,10 +449,14 @@ impl Perform<GetFollowedCommunitiesResponse> for Oper<GetFollowedCommunities> {
} }
impl Perform<BanFromCommunityResponse> for Oper<BanFromCommunity> { impl Perform<BanFromCommunityResponse> for Oper<BanFromCommunity> {
fn perform(&self, conn: &PgConnection) -> Result<BanFromCommunityResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<BanFromCommunityResponse, Error> {
let data: &BanFromCommunity = &self.data; let data: &BanFromCommunity = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -478,10 +506,14 @@ impl Perform<BanFromCommunityResponse> for Oper<BanFromCommunity> {
} }
impl Perform<AddModToCommunityResponse> for Oper<AddModToCommunity> { impl Perform<AddModToCommunityResponse> for Oper<AddModToCommunity> {
fn perform(&self, conn: &PgConnection) -> Result<AddModToCommunityResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<AddModToCommunityResponse, Error> {
let data: &AddModToCommunity = &self.data; let data: &AddModToCommunity = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -521,10 +553,14 @@ impl Perform<AddModToCommunityResponse> for Oper<AddModToCommunity> {
} }
impl Perform<GetCommunityResponse> for Oper<TransferCommunity> { impl Perform<GetCommunityResponse> for Oper<TransferCommunity> {
fn perform(&self, conn: &PgConnection) -> Result<GetCommunityResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<GetCommunityResponse, Error> {
let data: &TransferCommunity = &self.data; let data: &TransferCommunity = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };

View file

@ -17,6 +17,7 @@ use crate::db::user_mention::*;
use crate::db::user_mention_view::*; use crate::db::user_mention_view::*;
use crate::db::user_view::*; use crate::db::user_view::*;
use crate::db::*; use crate::db::*;
use crate::Settings;
use crate::{ use crate::{
extract_usernames, fetch_iframely_and_pictshare_data, naive_from_unix, naive_now, remove_slurs, extract_usernames, fetch_iframely_and_pictshare_data, naive_from_unix, naive_now, remove_slurs,
slur_check, slurs_vec_to_str, slur_check, slurs_vec_to_str,
@ -56,7 +57,7 @@ impl<T> Oper<T> {
} }
pub trait Perform<T> { pub trait Perform<T> {
fn perform(&self, conn: &PgConnection) -> Result<T, Error> fn perform(&self, conn: &PgConnection, settings: &Settings) -> Result<T, Error>
where where
T: Sized; T: Sized;
} }

View file

@ -80,10 +80,14 @@ pub struct SavePost {
} }
impl Perform<PostResponse> for Oper<CreatePost> { impl Perform<PostResponse> for Oper<CreatePost> {
fn perform(&self, conn: &PgConnection) -> Result<PostResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<PostResponse, Error> {
let data: &CreatePost = &self.data; let data: &CreatePost = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -169,11 +173,15 @@ impl Perform<PostResponse> for Oper<CreatePost> {
} }
impl Perform<GetPostResponse> for Oper<GetPost> { impl Perform<GetPostResponse> for Oper<GetPost> {
fn perform(&self, conn: &PgConnection) -> Result<GetPostResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<GetPostResponse, Error> {
let data: &GetPost = &self.data; let data: &GetPost = &self.data;
let user_id: Option<i32> = match &data.auth { let user_id: Option<i32> = match &data.auth {
Some(auth) => match Claims::decode(&auth) { Some(auth) => match Claims::decode(&auth, &settings.jwt_secret) {
Ok(claims) => { Ok(claims) => {
let user_id = claims.claims.id; let user_id = claims.claims.id;
Some(user_id) Some(user_id)
@ -217,11 +225,15 @@ impl Perform<GetPostResponse> for Oper<GetPost> {
} }
impl Perform<GetPostsResponse> for Oper<GetPosts> { impl Perform<GetPostsResponse> for Oper<GetPosts> {
fn perform(&self, conn: &PgConnection) -> Result<GetPostsResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<GetPostsResponse, Error> {
let data: &GetPosts = &self.data; let data: &GetPosts = &self.data;
let user_claims: Option<Claims> = match &data.auth { let user_claims: Option<Claims> = match &data.auth {
Some(auth) => match Claims::decode(&auth) { Some(auth) => match Claims::decode(&auth, &settings.jwt_secret) {
Ok(claims) => Some(claims.claims), Ok(claims) => Some(claims.claims),
Err(_e) => None, Err(_e) => None,
}, },
@ -260,10 +272,14 @@ impl Perform<GetPostsResponse> for Oper<GetPosts> {
} }
impl Perform<PostResponse> for Oper<CreatePostLike> { impl Perform<PostResponse> for Oper<CreatePostLike> {
fn perform(&self, conn: &PgConnection) -> Result<PostResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<PostResponse, Error> {
let data: &CreatePostLike = &self.data; let data: &CreatePostLike = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -318,7 +334,11 @@ impl Perform<PostResponse> for Oper<CreatePostLike> {
} }
impl Perform<PostResponse> for Oper<EditPost> { impl Perform<PostResponse> for Oper<EditPost> {
fn perform(&self, conn: &PgConnection) -> Result<PostResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<PostResponse, Error> {
let data: &EditPost = &self.data; let data: &EditPost = &self.data;
if let Err(slurs) = slur_check(&data.name) { if let Err(slurs) = slur_check(&data.name) {
@ -331,7 +351,7 @@ impl Perform<PostResponse> for Oper<EditPost> {
} }
} }
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -432,10 +452,14 @@ impl Perform<PostResponse> for Oper<EditPost> {
} }
impl Perform<PostResponse> for Oper<SavePost> { impl Perform<PostResponse> for Oper<SavePost> {
fn perform(&self, conn: &PgConnection) -> Result<PostResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<PostResponse, Error> {
let data: &SavePost = &self.data; let data: &SavePost = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };

View file

@ -114,7 +114,11 @@ pub struct SaveSiteConfig {
} }
impl Perform<ListCategoriesResponse> for Oper<ListCategories> { impl Perform<ListCategoriesResponse> for Oper<ListCategories> {
fn perform(&self, conn: &PgConnection) -> Result<ListCategoriesResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<ListCategoriesResponse, Error> {
let _data: &ListCategories = &self.data; let _data: &ListCategories = &self.data;
let categories: Vec<Category> = Category::list_all(&conn)?; let categories: Vec<Category> = Category::list_all(&conn)?;
@ -125,7 +129,11 @@ impl Perform<ListCategoriesResponse> for Oper<ListCategories> {
} }
impl Perform<GetModlogResponse> for Oper<GetModlog> { impl Perform<GetModlogResponse> for Oper<GetModlog> {
fn perform(&self, conn: &PgConnection) -> Result<GetModlogResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<GetModlogResponse, Error> {
let data: &GetModlog = &self.data; let data: &GetModlog = &self.data;
let removed_posts = ModRemovePostView::list( let removed_posts = ModRemovePostView::list(
@ -198,10 +206,14 @@ impl Perform<GetModlogResponse> for Oper<GetModlog> {
} }
impl Perform<SiteResponse> for Oper<CreateSite> { impl Perform<SiteResponse> for Oper<CreateSite> {
fn perform(&self, conn: &PgConnection) -> Result<SiteResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<SiteResponse, Error> {
let data: &CreateSite = &self.data; let data: &CreateSite = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -245,10 +257,14 @@ impl Perform<SiteResponse> for Oper<CreateSite> {
} }
impl Perform<SiteResponse> for Oper<EditSite> { impl Perform<SiteResponse> for Oper<EditSite> {
fn perform(&self, conn: &PgConnection) -> Result<SiteResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<SiteResponse, Error> {
let data: &EditSite = &self.data; let data: &EditSite = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -294,13 +310,17 @@ impl Perform<SiteResponse> for Oper<EditSite> {
} }
impl Perform<GetSiteResponse> for Oper<GetSite> { impl Perform<GetSiteResponse> for Oper<GetSite> {
fn perform(&self, conn: &PgConnection) -> Result<GetSiteResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<GetSiteResponse, Error> {
let _data: &GetSite = &self.data; let _data: &GetSite = &self.data;
let site = Site::read(&conn, 1); let site = Site::read(&conn, 1);
let site_view = if site.is_ok() { let site_view = if site.is_ok() {
Some(SiteView::read(&conn)?) Some(SiteView::read(&conn)?)
} else if let Some(setup) = Settings::get().setup.as_ref() { } else if let Some(setup) = &settings.setup {
let register = Register { let register = Register {
username: setup.admin_username.to_owned(), username: setup.admin_username.to_owned(),
email: setup.admin_email.to_owned(), email: setup.admin_email.to_owned(),
@ -309,7 +329,7 @@ impl Perform<GetSiteResponse> for Oper<GetSite> {
admin: true, admin: true,
show_nsfw: true, show_nsfw: true,
}; };
let login_response = Oper::new(register).perform(&conn)?; let login_response = Oper::new(register).perform(&conn, &settings)?;
info!("Admin {} created", setup.admin_username); info!("Admin {} created", setup.admin_username);
let create_site = CreateSite { let create_site = CreateSite {
@ -320,7 +340,7 @@ impl Perform<GetSiteResponse> for Oper<GetSite> {
enable_nsfw: false, enable_nsfw: false,
auth: login_response.jwt, auth: login_response.jwt,
}; };
Oper::new(create_site).perform(&conn)?; Oper::new(create_site).perform(&conn, &settings)?;
info!("Site {} created", setup.site_name); info!("Site {} created", setup.site_name);
Some(SiteView::read(&conn)?) Some(SiteView::read(&conn)?)
} else { } else {
@ -347,11 +367,15 @@ impl Perform<GetSiteResponse> for Oper<GetSite> {
} }
impl Perform<SearchResponse> for Oper<Search> { impl Perform<SearchResponse> for Oper<Search> {
fn perform(&self, conn: &PgConnection) -> Result<SearchResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<SearchResponse, Error> {
let data: &Search = &self.data; let data: &Search = &self.data;
let user_id: Option<i32> = match &data.auth { let user_id: Option<i32> = match &data.auth {
Some(auth) => match Claims::decode(&auth) { Some(auth) => match Claims::decode(&auth, &settings.jwt_secret) {
Ok(claims) => { Ok(claims) => {
let user_id = claims.claims.id; let user_id = claims.claims.id;
Some(user_id) Some(user_id)
@ -465,10 +489,14 @@ impl Perform<SearchResponse> for Oper<Search> {
} }
impl Perform<GetSiteResponse> for Oper<TransferSite> { impl Perform<GetSiteResponse> for Oper<TransferSite> {
fn perform(&self, conn: &PgConnection) -> Result<GetSiteResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<GetSiteResponse, Error> {
let data: &TransferSite = &self.data; let data: &TransferSite = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -528,10 +556,14 @@ impl Perform<GetSiteResponse> for Oper<TransferSite> {
} }
impl Perform<GetSiteConfigResponse> for Oper<GetSiteConfig> { impl Perform<GetSiteConfigResponse> for Oper<GetSiteConfig> {
fn perform(&self, conn: &PgConnection) -> Result<GetSiteConfigResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<GetSiteConfigResponse, Error> {
let data: &GetSiteConfig = &self.data; let data: &GetSiteConfig = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -553,10 +585,14 @@ impl Perform<GetSiteConfigResponse> for Oper<GetSiteConfig> {
} }
impl Perform<GetSiteConfigResponse> for Oper<SaveSiteConfig> { impl Perform<GetSiteConfigResponse> for Oper<SaveSiteConfig> {
fn perform(&self, conn: &PgConnection) -> Result<GetSiteConfigResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<GetSiteConfigResponse, Error> {
let data: &SaveSiteConfig = &self.data; let data: &SaveSiteConfig = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };

View file

@ -205,7 +205,11 @@ pub struct UserJoinResponse {
} }
impl Perform<LoginResponse> for Oper<Login> { impl Perform<LoginResponse> for Oper<Login> {
fn perform(&self, conn: &PgConnection) -> Result<LoginResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<LoginResponse, Error> {
let data: &Login = &self.data; let data: &Login = &self.data;
// Fetch that username / email // Fetch that username / email
@ -221,12 +225,16 @@ impl Perform<LoginResponse> for Oper<Login> {
} }
// Return the jwt // Return the jwt
Ok(LoginResponse { jwt: user.jwt() }) Ok(LoginResponse { jwt: user.jwt(&settings.jwt_secret) })
} }
} }
impl Perform<LoginResponse> for Oper<Register> { impl Perform<LoginResponse> for Oper<Register> {
fn perform(&self, conn: &PgConnection) -> Result<LoginResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<LoginResponse, Error> {
let data: &Register = &self.data; let data: &Register = &self.data;
// Make sure site has open registration // Make sure site has open registration
@ -253,7 +261,7 @@ impl Perform<LoginResponse> for Oper<Register> {
// Register the new user // Register the new user
let user_form = UserForm { let user_form = UserForm {
name: data.username.to_owned(), name: data.username.to_owned(),
fedi_name: Settings::get().hostname, fedi_name: settings.hostname.to_owned(),
email: data.email.to_owned(), email: data.email.to_owned(),
matrix_user_id: None, matrix_user_id: None,
avatar: None, avatar: None,
@ -334,16 +342,20 @@ impl Perform<LoginResponse> for Oper<Register> {
// Return the jwt // Return the jwt
Ok(LoginResponse { Ok(LoginResponse {
jwt: inserted_user.jwt(), jwt: inserted_user.jwt(&settings.jwt_secret),
}) })
} }
} }
impl Perform<LoginResponse> for Oper<SaveUserSettings> { impl Perform<LoginResponse> for Oper<SaveUserSettings> {
fn perform(&self, conn: &PgConnection) -> Result<LoginResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<LoginResponse, Error> {
let data: &SaveUserSettings = &self.data; let data: &SaveUserSettings = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -422,17 +434,21 @@ impl Perform<LoginResponse> for Oper<SaveUserSettings> {
// Return the jwt // Return the jwt
Ok(LoginResponse { Ok(LoginResponse {
jwt: updated_user.jwt(), jwt: updated_user.jwt(&settings.jwt_secret),
}) })
} }
} }
impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> { impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
fn perform(&self, conn: &PgConnection) -> Result<GetUserDetailsResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<GetUserDetailsResponse, Error> {
let data: &GetUserDetails = &self.data; let data: &GetUserDetails = &self.data;
let user_claims: Option<Claims> = match &data.auth { let user_claims: Option<Claims> = match &data.auth {
Some(auth) => match Claims::decode(&auth) { Some(auth) => match Claims::decode(&auth, &settings.jwt_secret) {
Ok(claims) => Some(claims.claims), Ok(claims) => Some(claims.claims),
Err(_e) => None, Err(_e) => None,
}, },
@ -525,10 +541,14 @@ impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
} }
impl Perform<AddAdminResponse> for Oper<AddAdmin> { impl Perform<AddAdminResponse> for Oper<AddAdmin> {
fn perform(&self, conn: &PgConnection) -> Result<AddAdminResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<AddAdminResponse, Error> {
let data: &AddAdmin = &self.data; let data: &AddAdmin = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -588,10 +608,14 @@ impl Perform<AddAdminResponse> for Oper<AddAdmin> {
} }
impl Perform<BanUserResponse> for Oper<BanUser> { impl Perform<BanUserResponse> for Oper<BanUser> {
fn perform(&self, conn: &PgConnection) -> Result<BanUserResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<BanUserResponse, Error> {
let data: &BanUser = &self.data; let data: &BanUser = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -657,10 +681,14 @@ impl Perform<BanUserResponse> for Oper<BanUser> {
} }
impl Perform<GetRepliesResponse> for Oper<GetReplies> { impl Perform<GetRepliesResponse> for Oper<GetReplies> {
fn perform(&self, conn: &PgConnection) -> Result<GetRepliesResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<GetRepliesResponse, Error> {
let data: &GetReplies = &self.data; let data: &GetReplies = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -681,10 +709,14 @@ impl Perform<GetRepliesResponse> for Oper<GetReplies> {
} }
impl Perform<GetUserMentionsResponse> for Oper<GetUserMentions> { impl Perform<GetUserMentionsResponse> for Oper<GetUserMentions> {
fn perform(&self, conn: &PgConnection) -> Result<GetUserMentionsResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<GetUserMentionsResponse, Error> {
let data: &GetUserMentions = &self.data; let data: &GetUserMentions = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -705,10 +737,14 @@ impl Perform<GetUserMentionsResponse> for Oper<GetUserMentions> {
} }
impl Perform<UserMentionResponse> for Oper<EditUserMention> { impl Perform<UserMentionResponse> for Oper<EditUserMention> {
fn perform(&self, conn: &PgConnection) -> Result<UserMentionResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<UserMentionResponse, Error> {
let data: &EditUserMention = &self.data; let data: &EditUserMention = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -738,10 +774,14 @@ impl Perform<UserMentionResponse> for Oper<EditUserMention> {
} }
impl Perform<GetRepliesResponse> for Oper<MarkAllAsRead> { impl Perform<GetRepliesResponse> for Oper<MarkAllAsRead> {
fn perform(&self, conn: &PgConnection) -> Result<GetRepliesResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<GetRepliesResponse, Error> {
let data: &MarkAllAsRead = &self.data; let data: &MarkAllAsRead = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -822,10 +862,14 @@ impl Perform<GetRepliesResponse> for Oper<MarkAllAsRead> {
} }
impl Perform<LoginResponse> for Oper<DeleteAccount> { impl Perform<LoginResponse> for Oper<DeleteAccount> {
fn perform(&self, conn: &PgConnection) -> Result<LoginResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<LoginResponse, Error> {
let data: &DeleteAccount = &self.data; let data: &DeleteAccount = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -903,7 +947,11 @@ impl Perform<LoginResponse> for Oper<DeleteAccount> {
} }
impl Perform<PasswordResetResponse> for Oper<PasswordReset> { impl Perform<PasswordResetResponse> for Oper<PasswordReset> {
fn perform(&self, conn: &PgConnection) -> Result<PasswordResetResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<PasswordResetResponse, Error> {
let data: &PasswordReset = &self.data; let data: &PasswordReset = &self.data;
// Fetch that email // Fetch that email
@ -922,9 +970,9 @@ impl Perform<PasswordResetResponse> for Oper<PasswordReset> {
// TODO no i18n support here. // TODO no i18n support here.
let user_email = &user.email.expect("email"); let user_email = &user.email.expect("email");
let subject = &format!("Password reset for {}", user.name); let subject = &format!("Password reset for {}", user.name);
let hostname = &format!("https://{}", Settings::get().hostname); //TODO add https for now. let hostname = &format!("https://{}", &settings.hostname); //TODO add https for now.
let html = &format!("<h1>Password Reset Request for {}</h1><br><a href={}/password_change/{}>Click here to reset your password</a>", user.name, hostname, &token); let html = &format!("<h1>Password Reset Request for {}</h1><br><a href={}/password_change/{}>Click here to reset your password</a>", user.name, hostname, &token);
match send_email(subject, user_email, &user.name, html) { match send_email(subject, user_email, &user.name, html, &settings) {
Ok(_o) => _o, Ok(_o) => _o,
Err(_e) => return Err(APIError::err(&_e).into()), Err(_e) => return Err(APIError::err(&_e).into()),
}; };
@ -934,7 +982,11 @@ impl Perform<PasswordResetResponse> for Oper<PasswordReset> {
} }
impl Perform<LoginResponse> for Oper<PasswordChange> { impl Perform<LoginResponse> for Oper<PasswordChange> {
fn perform(&self, conn: &PgConnection) -> Result<LoginResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<LoginResponse, Error> {
let data: &PasswordChange = &self.data; let data: &PasswordChange = &self.data;
// Fetch the user_id from the token // Fetch the user_id from the token
@ -953,23 +1005,27 @@ impl Perform<LoginResponse> for Oper<PasswordChange> {
// Return the jwt // Return the jwt
Ok(LoginResponse { Ok(LoginResponse {
jwt: updated_user.jwt(), jwt: updated_user.jwt(&settings.jwt_secret),
}) })
} }
} }
impl Perform<PrivateMessageResponse> for Oper<CreatePrivateMessage> { impl Perform<PrivateMessageResponse> for Oper<CreatePrivateMessage> {
fn perform(&self, conn: &PgConnection) -> Result<PrivateMessageResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<PrivateMessageResponse, Error> {
let data: &CreatePrivateMessage = &self.data; let data: &CreatePrivateMessage = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
let user_id = claims.id; let user_id = claims.id;
let hostname = &format!("https://{}", Settings::get().hostname); let hostname = &format!("https://{}", &settings.hostname);
// Check for a site ban // Check for a site ban
if UserView::read(&conn, user_id)?.banned { if UserView::read(&conn, user_id)?.banned {
@ -1000,14 +1056,14 @@ impl Perform<PrivateMessageResponse> for Oper<CreatePrivateMessage> {
if let Some(email) = recipient_user.email { if let Some(email) = recipient_user.email {
let subject = &format!( let subject = &format!(
"{} - Private Message from {}", "{} - Private Message from {}",
Settings::get().hostname, &settings.hostname,
claims.username claims.username
); );
let html = &format!( let html = &format!(
"<h1>Private Message</h1><br><div>{} - {}</div><br><a href={}/inbox>inbox</a>", "<h1>Private Message</h1><br><div>{} - {}</div><br><a href={}/inbox>inbox</a>",
claims.username, &content_slurs_removed, hostname claims.username, &content_slurs_removed, hostname
); );
match send_email(subject, &email, &recipient_user.name, html) { match send_email(subject, &email, &recipient_user.name, html, &settings) {
Ok(_o) => _o, Ok(_o) => _o,
Err(e) => error!("{}", e), Err(e) => error!("{}", e),
}; };
@ -1021,10 +1077,14 @@ impl Perform<PrivateMessageResponse> for Oper<CreatePrivateMessage> {
} }
impl Perform<PrivateMessageResponse> for Oper<EditPrivateMessage> { impl Perform<PrivateMessageResponse> for Oper<EditPrivateMessage> {
fn perform(&self, conn: &PgConnection) -> Result<PrivateMessageResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<PrivateMessageResponse, Error> {
let data: &EditPrivateMessage = &self.data; let data: &EditPrivateMessage = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -1076,10 +1136,14 @@ impl Perform<PrivateMessageResponse> for Oper<EditPrivateMessage> {
} }
impl Perform<PrivateMessagesResponse> for Oper<GetPrivateMessages> { impl Perform<PrivateMessagesResponse> for Oper<GetPrivateMessages> {
fn perform(&self, conn: &PgConnection) -> Result<PrivateMessagesResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<PrivateMessagesResponse, Error> {
let data: &GetPrivateMessages = &self.data; let data: &GetPrivateMessages = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };
@ -1097,10 +1161,14 @@ impl Perform<PrivateMessagesResponse> for Oper<GetPrivateMessages> {
} }
impl Perform<UserJoinResponse> for Oper<UserJoin> { impl Perform<UserJoinResponse> for Oper<UserJoin> {
fn perform(&self, _conn: &PgConnection) -> Result<UserJoinResponse, Error> { fn perform(
&self,
conn: &PgConnection,
settings: &Settings,
) -> Result<UserJoinResponse, Error> {
let data: &UserJoin = &self.data; let data: &UserJoin = &self.data;
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth, &settings.jwt_secret) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => return Err(APIError::err("not_logged_in").into()), Err(_e) => return Err(APIError::err("not_logged_in").into()),
}; };

View file

@ -91,7 +91,7 @@ mod tests {
let page = post.as_page(); let page = post.as_page();
assert_eq!( assert_eq!(
format!("https://{}/federation/post/62", Settings::get().hostname), format!("https://{}/federation/post/62", "fake_host"),
page.object_props.id_string().unwrap() page.object_props.id_string().unwrap()
); );
} }
@ -100,7 +100,7 @@ mod tests {
pub fn make_apub_endpoint<S: Display, T: Display>(point: S, value: T) -> String { pub fn make_apub_endpoint<S: Display, T: Display>(point: S, value: T) -> String {
format!( format!(
"https://{}/federation/{}/{}", "https://{}/federation/{}/{}",
Settings::get().hostname, "fake_host",
point, point,
value value
) )

View file

@ -69,8 +69,8 @@ impl Community {
.first::<Self>(conn) .first::<Self>(conn)
} }
pub fn get_url(&self) -> String { pub fn get_url(&self, hostname: &str) -> String {
format!("https://{}/c/{}", Settings::get().hostname, self.name) format!("https://{}/c/{}", hostname, self.name)
} }
} }

View file

@ -112,7 +112,7 @@ impl<T> MaybeOptional<T> for Option<T> {
} }
pub fn establish_unpooled_connection() -> PgConnection { pub fn establish_unpooled_connection() -> PgConnection {
let db_url = Settings::get().get_database_url(); let db_url = Settings::init().unwrap().get_database_url();
PgConnection::establish(&db_url).unwrap_or_else(|_| panic!("Error connecting to {}", db_url)) PgConnection::establish(&db_url).unwrap_or_else(|_| panic!("Error connecting to {}", db_url))
} }

View file

@ -110,14 +110,14 @@ pub struct Claims {
} }
impl Claims { impl Claims {
pub fn decode(jwt: &str) -> Result<TokenData<Claims>, jsonwebtoken::errors::Error> { pub fn decode(jwt: &str, jwt_secret: &str) -> Result<TokenData<Claims>, jsonwebtoken::errors::Error> {
let v = Validation { let v = Validation {
validate_exp: false, validate_exp: false,
..Validation::default() ..Validation::default()
}; };
decode::<Claims>( decode::<Claims>(
&jwt, &jwt,
&DecodingKey::from_secret(Settings::get().jwt_secret.as_ref()), &DecodingKey::from_secret(jwt_secret.as_bytes()),
&v, &v,
) )
} }
@ -125,7 +125,7 @@ impl Claims {
type Jwt = String; type Jwt = String;
impl User_ { impl User_ {
pub fn jwt(&self) -> Jwt { pub fn jwt(&self, jwt_secret: &str) -> Jwt {
let my_claims = Claims { let my_claims = Claims {
id: self.id, id: self.id,
username: self.name.to_owned(), username: self.name.to_owned(),
@ -141,7 +141,7 @@ impl User_ {
encode( encode(
&Header::default(), &Header::default(),
&my_claims, &my_claims,
&EncodingKey::from_secret(Settings::get().jwt_secret.as_ref()), &EncodingKey::from_secret(jwt_secret.as_bytes()),
) )
.unwrap() .unwrap()
} }
@ -165,12 +165,12 @@ impl User_ {
} }
} }
pub fn get_profile_url(&self) -> String { pub fn get_profile_url(&self, hostname: &str) -> String {
format!("https://{}/u/{}", Settings::get().hostname, self.name) format!("https://{}/u/{}", hostname, self.name)
} }
pub fn find_by_jwt(conn: &PgConnection, jwt: &str) -> Result<Self, Error> { pub fn find_by_jwt(conn: &PgConnection, jwt: &str, jwt_secret: &str) -> Result<Self, Error> {
let claims: Claims = Claims::decode(&jwt).expect("Invalid token").claims; let claims: Claims = Claims::decode(jwt, jwt_secret).expect("Invalid token").claims;
Self::read(&conn, claims.id) Self::read(&conn, claims.id)
} }
} }

View file

@ -111,8 +111,9 @@ pub fn send_email(
to_email: &str, to_email: &str,
to_username: &str, to_username: &str,
html: &str, html: &str,
settings: &Settings,
) -> Result<(), String> { ) -> Result<(), String> {
let email_config = Settings::get().email.ok_or("no_email_setup")?; let email_config = settings.email.to_owned().ok_or("no_email_setup")?;
let email = Email::builder() let email = Email::builder()
.to((to_email, to_username)) .to((to_email, to_username))
@ -127,7 +128,7 @@ pub fn send_email(
} else { } else {
SmtpClient::new(&email_config.smtp_server, ClientSecurity::None).unwrap() SmtpClient::new(&email_config.smtp_server, ClientSecurity::None).unwrap()
} }
.hello_name(ClientId::Domain(Settings::get().hostname)) .hello_name(ClientId::Domain(settings.hostname.to_owned()))
.smtp_utf8(true) .smtp_utf8(true)
.authentication_mechanism(Mechanism::Plain) .authentication_mechanism(Mechanism::Plain)
.connection_reuse(ConnectionReuseParameters::ReuseUnlimited); .connection_reuse(ConnectionReuseParameters::ReuseUnlimited);

View file

@ -2,10 +2,8 @@ extern crate lemmy_server;
#[macro_use] #[macro_use]
extern crate diesel_migrations; extern crate diesel_migrations;
use actix::prelude::*;
use actix_web::*; use actix_web::*;
use diesel::r2d2::{ConnectionManager, Pool}; use actix::prelude::*;
use diesel::PgConnection;
use lemmy_server::routes::{api, federation, feeds, index, nodeinfo, webfinger, websocket}; use lemmy_server::routes::{api, federation, feeds, index, nodeinfo, webfinger, websocket};
use lemmy_server::settings::Settings; use lemmy_server::settings::Settings;
use lemmy_server::websocket::server::*; use lemmy_server::websocket::server::*;
@ -16,21 +14,24 @@ embed_migrations!();
#[actix_rt::main] #[actix_rt::main]
async fn main() -> io::Result<()> { async fn main() -> io::Result<()> {
env_logger::init(); env_logger::init();
let settings = Settings::get();
// Set up the r2d2 connection pool // Set up the Chatserver's shared state
let manager = ConnectionManager::<PgConnection>::new(&settings.get_database_url()); let cs_state_web = web::Data::new(ChatSharedState::init());
let pool = Pool::builder() let cs_state_web_two = cs_state_web.clone();
.max_size(settings.database.pool_size) let server = SyncArbiter::start(2, move || ChatServer::init(cs_state_web.clone()));
.build(manager)
.unwrap_or_else(|_| panic!("Error connecting to {}", settings.get_database_url())); let settings = cs_state_web_two.settings.lock().unwrap().to_owned();
// Run the migrations from code // Run the migrations from code
let conn = pool.get().unwrap(); // let conn = pool.get().unwrap();
let conn = cs_state_web_two.pool.lock().unwrap().get().unwrap();
embedded_migrations::run(&conn).unwrap(); embedded_migrations::run(&conn).unwrap();
// Set up websocket server // Set up websocket server
let server = ChatServer::startup(pool.clone()).start(); // let server = ChatServer::init(cs_state).start();
// let cs_state_web_two = cs_state_web.clone();
println!( println!(
"Starting http server at {}:{}", "Starting http server at {}:{}",
@ -39,10 +40,11 @@ async fn main() -> io::Result<()> {
// Create Http server with websocket support // Create Http server with websocket support
HttpServer::new(move || { HttpServer::new(move || {
let settings = Settings::get(); let settings = cs_state_web_two.settings.lock().unwrap().to_owned();
App::new() App::new()
.wrap(middleware::Logger::default()) .wrap(middleware::Logger::default())
.data(pool.clone()) // .app_data(cs_state_web_two.clone())
.app_data(cs_state_web_two.clone())
.data(server.clone()) .data(server.clone())
// The routes // The routes
.configure(api::config) .configure(api::config)
@ -59,7 +61,7 @@ async fn main() -> io::Result<()> {
)) ))
.service(actix_files::Files::new( .service(actix_files::Files::new(
"/docs", "/docs",
settings.front_end_dir + "/documentation", settings.front_end_dir.to_owned() + "/documentation",
)) ))
}) })
.bind((settings.bind, settings.port))? .bind((settings.bind, settings.port))?

View file

@ -4,14 +4,13 @@ use crate::api::post::*;
use crate::api::site::*; use crate::api::site::*;
use crate::api::user::*; use crate::api::user::*;
use crate::api::{Oper, Perform}; use crate::api::{Oper, Perform};
use crate::websocket::server::ChatSharedState;
use actix_web::{web, HttpResponse}; use actix_web::{web, HttpResponse};
use diesel::r2d2::{ConnectionManager, Pool}; use diesel::r2d2::{ConnectionManager, Pool};
use diesel::PgConnection; use diesel::PgConnection;
use failure::Error; use failure::Error;
use serde::Serialize; use serde::Serialize;
type DbParam = web::Data<Pool<ConnectionManager<PgConnection>>>;
#[rustfmt::skip] #[rustfmt::skip]
pub fn config(cfg: &mut web::ServiceConfig) { pub fn config(cfg: &mut web::ServiceConfig) {
cfg cfg
@ -66,40 +65,46 @@ pub fn config(cfg: &mut web::ServiceConfig) {
.route("/api/v1/user/save_user_settings", web::put().to(route_post::<SaveUserSettings, LoginResponse>)); .route("/api/v1/user/save_user_settings", web::put().to(route_post::<SaveUserSettings, LoginResponse>));
} }
fn perform<Request, Response>(data: Request, db: DbParam) -> Result<HttpResponse, Error> fn perform<Request, Response>(
data: Request,
state: web::Data<ChatSharedState>,
) -> Result<HttpResponse, Error>
where where
Response: Serialize, Response: Serialize,
Oper<Request>: Perform<Response>, Oper<Request>: Perform<Response>,
{ {
let conn = match db.get() { // let conn = match db.get() {
Ok(c) => c, // Ok(c) => c,
Err(e) => return Err(format_err!("{}", e)), // Err(e) => return Err(format_err!("{}", e)),
}; // };
let conn = state.pool.lock().unwrap().get()?;
let settings = state.settings.lock().unwrap();
let oper: Oper<Request> = Oper::new(data); let oper: Oper<Request> = Oper::new(data);
let response = oper.perform(&conn); let response = oper.perform(&conn, &settings);
Ok(HttpResponse::Ok().json(response?)) Ok(HttpResponse::Ok().json(response?))
} }
async fn route_get<Data, Response>( async fn route_get<Data, Response>(
data: web::Query<Data>, data: web::Query<Data>,
db: DbParam, state: web::Data<ChatSharedState>,
) -> Result<HttpResponse, Error> ) -> Result<HttpResponse, Error>
where where
Data: Serialize, Data: Serialize,
Response: Serialize, Response: Serialize,
Oper<Data>: Perform<Response>, Oper<Data>: Perform<Response>,
{ {
perform::<Data, Response>(data.0, db) perform::<Data, Response>(data.0, state)
} }
async fn route_post<Data, Response>( async fn route_post<Data, Response>(
data: web::Json<Data>, data: web::Json<Data>,
db: DbParam, state: web::Data<ChatSharedState>,
) -> Result<HttpResponse, Error> ) -> Result<HttpResponse, Error>
where where
Data: Serialize, Data: Serialize,
Response: Serialize, Response: Serialize,
Oper<Data>: Perform<Response>, Oper<Data>: Perform<Response>,
{ {
perform::<Data, Response>(data.0, db) perform::<Data, Response>(data.0, state)
} }

View file

@ -6,10 +6,10 @@ use crate::db::site_view::SiteView;
use crate::db::user::{Claims, User_}; use crate::db::user::{Claims, User_};
use crate::db::user_mention_view::{UserMentionQueryBuilder, UserMentionView}; use crate::db::user_mention_view::{UserMentionQueryBuilder, UserMentionView};
use crate::db::{ListingType, SortType}; use crate::db::{ListingType, SortType};
use crate::{markdown_to_html, Settings}; use crate::websocket::server::ChatSharedState;
use crate::markdown_to_html;
use actix_web::{web, HttpResponse, Result}; use actix_web::{web, HttpResponse, Result};
use chrono::{DateTime, NaiveDateTime, Utc}; use chrono::{DateTime, NaiveDateTime, Utc};
use diesel::r2d2::{ConnectionManager, Pool};
use diesel::PgConnection; use diesel::PgConnection;
use failure::Error; use failure::Error;
use rss::{CategoryBuilder, ChannelBuilder, GuidBuilder, Item, ItemBuilder}; use rss::{CategoryBuilder, ChannelBuilder, GuidBuilder, Item, ItemBuilder};
@ -37,11 +37,12 @@ pub fn config(cfg: &mut web::ServiceConfig) {
async fn get_all_feed( async fn get_all_feed(
info: web::Query<Params>, info: web::Query<Params>,
db: web::Data<Pool<ConnectionManager<PgConnection>>>, state: web::Data<ChatSharedState>,
) -> Result<HttpResponse, actix_web::Error> { ) -> Result<HttpResponse, actix_web::Error> {
let res = web::block(move || { let res = web::block(move || {
let conn = db.get()?; let conn = state.pool.lock().unwrap().get()?;
get_feed_all_data(&conn, &get_sort_type(info)?) let hostname = &state.settings.lock().unwrap().hostname;
get_feed_all_data(&conn, &hostname, &get_sort_type(info)?)
}) })
.await .await
.map(|rss| { .map(|rss| {
@ -53,7 +54,7 @@ async fn get_all_feed(
Ok(res) Ok(res)
} }
fn get_feed_all_data(conn: &PgConnection, sort_type: &SortType) -> Result<String, failure::Error> { fn get_feed_all_data(conn: &PgConnection, hostname: &str, sort_type: &SortType) -> Result<String, failure::Error> {
let site_view = SiteView::read(&conn)?; let site_view = SiteView::read(&conn)?;
let posts = PostQueryBuilder::create(&conn) let posts = PostQueryBuilder::create(&conn)
@ -61,12 +62,12 @@ fn get_feed_all_data(conn: &PgConnection, sort_type: &SortType) -> Result<String
.sort(sort_type) .sort(sort_type)
.list()?; .list()?;
let items = create_post_items(posts); let items = create_post_items(posts, hostname);
let mut channel_builder = ChannelBuilder::default(); let mut channel_builder = ChannelBuilder::default();
channel_builder channel_builder
.title(&format!("{} - All", site_view.name)) .title(&format!("{} - All", site_view.name))
.link(format!("https://{}", Settings::get().hostname)) .link(format!("https://{}", hostname))
.items(items); .items(items);
if let Some(site_desc) = site_view.description { if let Some(site_desc) = site_view.description {
@ -79,10 +80,12 @@ fn get_feed_all_data(conn: &PgConnection, sort_type: &SortType) -> Result<String
async fn get_feed( async fn get_feed(
path: web::Path<(String, String)>, path: web::Path<(String, String)>,
info: web::Query<Params>, info: web::Query<Params>,
db: web::Data<Pool<ConnectionManager<PgConnection>>>, state: web::Data<ChatSharedState>,
) -> Result<HttpResponse, actix_web::Error> { ) -> Result<HttpResponse, actix_web::Error> {
let res = web::block(move || { let res = web::block(move || {
let conn = db.get()?; let conn = state.pool.lock().unwrap().get()?;
let hostname = &state.settings.lock().unwrap().hostname;
let jwt_secret = &state.settings.lock().unwrap().jwt_secret;
let sort_type = get_sort_type(info)?; let sort_type = get_sort_type(info)?;
@ -97,10 +100,10 @@ async fn get_feed(
let param = path.1.to_owned(); let param = path.1.to_owned();
match request_type { match request_type {
RequestType::User => get_feed_user(&conn, &sort_type, param), RequestType::User => get_feed_user(&conn, &hostname, &sort_type, param),
RequestType::Community => get_feed_community(&conn, &sort_type, param), RequestType::Community => get_feed_community(&conn, &hostname, &sort_type, param),
RequestType::Front => get_feed_front(&conn, &sort_type, param), RequestType::Front => get_feed_front(&conn, &hostname, &jwt_secret, &sort_type, param),
RequestType::Inbox => get_feed_inbox(&conn, param), RequestType::Inbox => get_feed_inbox(&conn, &hostname, &jwt_secret, param),
} }
}) })
.await .await
@ -124,12 +127,13 @@ fn get_sort_type(info: web::Query<Params>) -> Result<SortType, ParseError> {
fn get_feed_user( fn get_feed_user(
conn: &PgConnection, conn: &PgConnection,
hostname: &str,
sort_type: &SortType, sort_type: &SortType,
user_name: String, user_name: String,
) -> Result<ChannelBuilder, Error> { ) -> Result<ChannelBuilder, Error> {
let site_view = SiteView::read(&conn)?; let site_view = SiteView::read(&conn)?;
let user = User_::find_by_username(&conn, &user_name)?; let user = User_::find_by_username(&conn, &user_name)?;
let user_url = user.get_profile_url(); let user_url = user.get_profile_url(hostname);
let posts = PostQueryBuilder::create(&conn) let posts = PostQueryBuilder::create(&conn)
.listing_type(ListingType::All) .listing_type(ListingType::All)
@ -137,7 +141,7 @@ fn get_feed_user(
.for_creator_id(user.id) .for_creator_id(user.id)
.list()?; .list()?;
let items = create_post_items(posts); let items = create_post_items(posts, hostname);
let mut channel_builder = ChannelBuilder::default(); let mut channel_builder = ChannelBuilder::default();
channel_builder channel_builder
@ -150,12 +154,13 @@ fn get_feed_user(
fn get_feed_community( fn get_feed_community(
conn: &PgConnection, conn: &PgConnection,
hostname: &str,
sort_type: &SortType, sort_type: &SortType,
community_name: String, community_name: String,
) -> Result<ChannelBuilder, Error> { ) -> Result<ChannelBuilder, Error> {
let site_view = SiteView::read(&conn)?; let site_view = SiteView::read(&conn)?;
let community = Community::read_from_name(&conn, community_name)?; let community = Community::read_from_name(&conn, community_name)?;
let community_url = community.get_url(); let community_url = community.get_url(hostname);
let posts = PostQueryBuilder::create(&conn) let posts = PostQueryBuilder::create(&conn)
.listing_type(ListingType::All) .listing_type(ListingType::All)
@ -163,7 +168,7 @@ fn get_feed_community(
.for_community_id(community.id) .for_community_id(community.id)
.list()?; .list()?;
let items = create_post_items(posts); let items = create_post_items(posts, hostname);
let mut channel_builder = ChannelBuilder::default(); let mut channel_builder = ChannelBuilder::default();
channel_builder channel_builder
@ -180,11 +185,13 @@ fn get_feed_community(
fn get_feed_front( fn get_feed_front(
conn: &PgConnection, conn: &PgConnection,
hostname: &str,
jwt_secret: &str,
sort_type: &SortType, sort_type: &SortType,
jwt: String, jwt: String,
) -> Result<ChannelBuilder, Error> { ) -> Result<ChannelBuilder, Error> {
let site_view = SiteView::read(&conn)?; let site_view = SiteView::read(&conn)?;
let user_id = Claims::decode(&jwt)?.claims.id; let user_id = Claims::decode(&jwt, jwt_secret)?.claims.id;
let posts = PostQueryBuilder::create(&conn) let posts = PostQueryBuilder::create(&conn)
.listing_type(ListingType::Subscribed) .listing_type(ListingType::Subscribed)
@ -192,12 +199,12 @@ fn get_feed_front(
.my_user_id(user_id) .my_user_id(user_id)
.list()?; .list()?;
let items = create_post_items(posts); let items = create_post_items(posts, hostname);
let mut channel_builder = ChannelBuilder::default(); let mut channel_builder = ChannelBuilder::default();
channel_builder channel_builder
.title(&format!("{} - Subscribed", site_view.name)) .title(&format!("{} - Subscribed", site_view.name))
.link(format!("https://{}", Settings::get().hostname)) .link(format!("https://{}", hostname))
.items(items); .items(items);
if let Some(site_desc) = site_view.description { if let Some(site_desc) = site_view.description {
@ -207,9 +214,13 @@ fn get_feed_front(
Ok(channel_builder) Ok(channel_builder)
} }
fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result<ChannelBuilder, Error> { fn get_feed_inbox(
conn: &PgConnection,
hostname: &str,
jwt_secret: &str,
jwt: String) -> Result<ChannelBuilder, Error> {
let site_view = SiteView::read(&conn)?; let site_view = SiteView::read(&conn)?;
let user_id = Claims::decode(&jwt)?.claims.id; let user_id = Claims::decode(&jwt, jwt_secret)?.claims.id;
let sort = SortType::New; let sort = SortType::New;
@ -221,12 +232,12 @@ fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result<ChannelBuilder, Er
.sort(&sort) .sort(&sort)
.list()?; .list()?;
let items = create_reply_and_mention_items(replies, mentions); let items = create_reply_and_mention_items(replies, mentions, hostname);
let mut channel_builder = ChannelBuilder::default(); let mut channel_builder = ChannelBuilder::default();
channel_builder channel_builder
.title(&format!("{} - Inbox", site_view.name)) .title(&format!("{} - Inbox", site_view.name))
.link(format!("https://{}/inbox", Settings::get().hostname)) .link(format!("https://{}/inbox", hostname))
.items(items); .items(items);
if let Some(site_desc) = site_view.description { if let Some(site_desc) = site_view.description {
@ -239,17 +250,18 @@ fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result<ChannelBuilder, Er
fn create_reply_and_mention_items( fn create_reply_and_mention_items(
replies: Vec<ReplyView>, replies: Vec<ReplyView>,
mentions: Vec<UserMentionView>, mentions: Vec<UserMentionView>,
hostname: &str,
) -> Vec<Item> { ) -> Vec<Item> {
let mut reply_items: Vec<Item> = replies let mut reply_items: Vec<Item> = replies
.iter() .iter()
.map(|r| { .map(|r| {
let reply_url = format!( let reply_url = format!(
"https://{}/post/{}/comment/{}", "https://{}/post/{}/comment/{}",
Settings::get().hostname, hostname,
r.post_id, r.post_id,
r.id r.id
); );
build_item(&r.creator_name, &r.published, &reply_url, &r.content) build_item(&r.creator_name, &r.published, &reply_url, &r.content, hostname)
}) })
.collect(); .collect();
@ -258,11 +270,11 @@ fn create_reply_and_mention_items(
.map(|m| { .map(|m| {
let mention_url = format!( let mention_url = format!(
"https://{}/post/{}/comment/{}", "https://{}/post/{}/comment/{}",
Settings::get().hostname, hostname,
m.post_id, m.post_id,
m.id m.id
); );
build_item(&m.creator_name, &m.published, &mention_url, &m.content) build_item(&m.creator_name, &m.published, &mention_url, &m.content, hostname)
}) })
.collect(); .collect();
@ -270,10 +282,10 @@ fn create_reply_and_mention_items(
reply_items reply_items
} }
fn build_item(creator_name: &str, published: &NaiveDateTime, url: &str, content: &str) -> Item { fn build_item(creator_name: &str, published: &NaiveDateTime, url: &str, content: &str, hostname: &str) -> Item {
let mut i = ItemBuilder::default(); let mut i = ItemBuilder::default();
i.title(format!("Reply from {}", creator_name)); i.title(format!("Reply from {}", creator_name));
let author_url = format!("https://{}/u/{}", Settings::get().hostname, creator_name); let author_url = format!("https://{}/u/{}", hostname, creator_name);
i.author(format!( i.author(format!(
"/u/{} <a href=\"{}\">(link)</a>", "/u/{} <a href=\"{}\">(link)</a>",
creator_name, author_url creator_name, author_url
@ -290,7 +302,7 @@ fn build_item(creator_name: &str, published: &NaiveDateTime, url: &str, content:
i.build().unwrap() i.build().unwrap()
} }
fn create_post_items(posts: Vec<PostView>) -> Vec<Item> { fn create_post_items(posts: Vec<PostView>, hostname: &str) -> Vec<Item> {
let mut items: Vec<Item> = Vec::new(); let mut items: Vec<Item> = Vec::new();
for p in posts { for p in posts {
@ -298,7 +310,7 @@ fn create_post_items(posts: Vec<PostView>) -> Vec<Item> {
i.title(p.name); i.title(p.name);
let author_url = format!("https://{}/u/{}", Settings::get().hostname, p.creator_name); let author_url = format!("https://{}/u/{}", hostname, p.creator_name);
i.author(format!( i.author(format!(
"/u/{} <a href=\"{}\">(link)</a>", "/u/{} <a href=\"{}\">(link)</a>",
p.creator_name, author_url p.creator_name, author_url
@ -307,7 +319,7 @@ fn create_post_items(posts: Vec<PostView>) -> Vec<Item> {
let dt = DateTime::<Utc>::from_utc(p.published, Utc); let dt = DateTime::<Utc>::from_utc(p.published, Utc);
i.pub_date(dt.to_rfc2822()); i.pub_date(dt.to_rfc2822());
let post_url = format!("https://{}/post/{}", Settings::get().hostname, p.id); let post_url = format!("https://{}/post/{}", hostname, p.id);
i.comments(post_url.to_owned()); i.comments(post_url.to_owned());
let guid = GuidBuilder::default() let guid = GuidBuilder::default()
.permalink(true) .permalink(true)
@ -317,7 +329,7 @@ fn create_post_items(posts: Vec<PostView>) -> Vec<Item> {
let community_url = format!( let community_url = format!(
"https://{}/c/{}", "https://{}/c/{}",
Settings::get().hostname, hostname,
p.community_name p.community_name
); );
@ -326,7 +338,7 @@ fn create_post_items(posts: Vec<PostView>) -> Vec<Item> {
"/c/{} <a href=\"{}\">(link)</a>", "/c/{} <a href=\"{}\">(link)</a>",
p.community_name, community_url p.community_name, community_url
)) ))
.domain(Settings::get().hostname.to_owned()) .domain(hostname.to_string())
.build(); .build();
i.categories(vec![category.unwrap()]); i.categories(vec![category.unwrap()]);

View file

@ -1,4 +1,4 @@
use crate::settings::Settings; use crate::websocket::server::ChatSharedState;
use actix_files::NamedFile; use actix_files::NamedFile;
use actix_web::web; use actix_web::web;
@ -43,8 +43,10 @@ pub fn config(cfg: &mut web::ServiceConfig) {
.route("/password_change/{token}", web::get().to(index)); .route("/password_change/{token}", web::get().to(index));
} }
async fn index() -> Result<NamedFile, actix_web::error::Error> { async fn index(
state: web::Data<ChatSharedState>,
) -> Result<NamedFile, actix_web::error::Error> {
Ok(NamedFile::open( Ok(NamedFile::open(
Settings::get().front_end_dir + "/index.html", state.settings.lock().unwrap().front_end_dir.to_owned() + "/index.html",
)?) )?)
} }

View file

@ -1,11 +1,9 @@
use crate::db::site_view::SiteView; use crate::db::site_view::SiteView;
use crate::version; use crate::version;
use crate::Settings; use crate::websocket::server::ChatSharedState;
use actix_web::body::Body; use actix_web::body::Body;
use actix_web::web; use actix_web::web;
use actix_web::HttpResponse; use actix_web::HttpResponse;
use diesel::r2d2::{ConnectionManager, Pool};
use diesel::PgConnection;
use serde::Serialize; use serde::Serialize;
pub fn config(cfg: &mut web::ServiceConfig) { pub fn config(cfg: &mut web::ServiceConfig) {
@ -14,26 +12,29 @@ pub fn config(cfg: &mut web::ServiceConfig) {
.route("/.well-known/nodeinfo", web::get().to(node_info_well_known)); .route("/.well-known/nodeinfo", web::get().to(node_info_well_known));
} }
async fn node_info_well_known() -> HttpResponse<Body> { async fn node_info_well_known(
state: web::Data<ChatSharedState>,
) -> HttpResponse<Body> {
let node_info = NodeInfoWellKnown { let node_info = NodeInfoWellKnown {
links: NodeInfoWellKnownLinks { links: NodeInfoWellKnownLinks {
rel: "http://nodeinfo.diaspora.software/ns/schema/2.0".to_string(), rel: "http://nodeinfo.diaspora.software/ns/schema/2.0".to_string(),
href: format!("https://{}/nodeinfo/2.0.json", Settings::get().hostname), href: format!("https://{}/nodeinfo/2.0.json", state.settings.lock().unwrap().hostname),
}, },
}; };
HttpResponse::Ok().json(node_info) HttpResponse::Ok().json(node_info)
} }
async fn node_info( async fn node_info(
db: web::Data<Pool<ConnectionManager<PgConnection>>>, state: web::Data<ChatSharedState>,
) -> Result<HttpResponse, actix_web::Error> { ) -> Result<HttpResponse, actix_web::Error> {
let res = web::block(move || { let res = web::block(move || {
let conn = db.get()?;
let conn = state.pool.lock().unwrap().get()?;
let site_view = match SiteView::read(&conn) { let site_view = match SiteView::read(&conn) {
Ok(site_view) => site_view, Ok(site_view) => site_view,
Err(_) => return Err(format_err!("not_found")), Err(_) => return Err(format_err!("not_found")),
}; };
let protocols = if Settings::get().federation_enabled { let protocols = if state.settings.lock().unwrap().federation_enabled {
vec!["activitypub".to_string()] vec!["activitypub".to_string()]
} else { } else {
vec![] vec![]

View file

@ -1,4 +1,5 @@
use crate::db::community::Community; use crate::db::community::Community;
use crate::websocket::server::ChatSharedState;
use crate::Settings; use crate::Settings;
use actix_web::web; use actix_web::web;
use actix_web::web::Query; use actix_web::web::Query;
@ -14,21 +15,17 @@ pub struct Params {
resource: String, resource: String,
} }
pub fn config(cfg: &mut web::ServiceConfig) { pub fn config(
if Settings::get().federation_enabled { cfg: &mut web::ServiceConfig,
) {
// TODO couldn't get this to pass the app state
// if state.settings.lock().unwrap().federation_enabled {
cfg.route( cfg.route(
".well-known/webfinger", ".well-known/webfinger",
web::get().to(get_webfinger_response), web::get().to(get_webfinger_response),
); );
} // }
}
lazy_static! {
static ref WEBFINGER_COMMUNITY_REGEX: Regex = Regex::new(&format!(
"^group:([a-z0-9_]{{3, 20}})@{}$",
Settings::get().hostname
))
.unwrap();
} }
/// Responds to webfinger requests of the following format. There isn't any real documentation for /// Responds to webfinger requests of the following format. There isn't any real documentation for
@ -39,10 +36,16 @@ lazy_static! {
/// https://radical.town/.well-known/webfinger?resource=acct:felix@radical.town /// https://radical.town/.well-known/webfinger?resource=acct:felix@radical.town
async fn get_webfinger_response( async fn get_webfinger_response(
info: Query<Params>, info: Query<Params>,
db: web::Data<Pool<ConnectionManager<PgConnection>>>, state: web::Data<ChatSharedState>,
) -> Result<HttpResponse, actix_web::Error> { ) -> Result<HttpResponse, actix_web::Error> {
let res = web::block(move || { let res = web::block(move || {
let conn = db.get()?; let conn = state.pool.lock().unwrap().get()?;
let hostname = &state.settings.lock().unwrap().hostname;
let WEBFINGER_COMMUNITY_REGEX: Regex = Regex::new(&format!(
"^group:([a-z0-9_]{{3, 20}})@{}$",
hostname
))
.unwrap();
let regex_parsed = WEBFINGER_COMMUNITY_REGEX let regex_parsed = WEBFINGER_COMMUNITY_REGEX
.captures(&info.resource) .captures(&info.resource)
@ -63,7 +66,7 @@ async fn get_webfinger_response(
Err(_) => return Err(format_err!("not_found")), Err(_) => return Err(format_err!("not_found")),
}; };
let community_url = community.get_url(); let community_url = community.get_url(&hostname);
Ok(json!({ Ok(json!({
"subject": info.resource, "subject": info.resource,

View file

@ -4,7 +4,8 @@ use serde::Deserialize;
use std::env; use std::env;
use std::fs; use std::fs;
use std::net::IpAddr; use std::net::IpAddr;
use std::sync::RwLock; use std::sync::Mutex;
use std::sync::Arc;
static CONFIG_FILE_DEFAULTS: &str = "config/defaults.hjson"; static CONFIG_FILE_DEFAULTS: &str = "config/defaults.hjson";
static CONFIG_FILE: &str = "config/config.hjson"; static CONFIG_FILE: &str = "config/config.hjson";
@ -60,19 +61,12 @@ pub struct Database {
pub pool_size: u32, pub pool_size: u32,
} }
lazy_static! {
static ref SETTINGS: RwLock<Settings> = RwLock::new(match Settings::init() {
Ok(c) => c,
Err(e) => panic!("{}", e),
});
}
impl Settings { impl Settings {
/// Reads config from the files and environment. /// Reads config from the files and environment.
/// First, defaults are loaded from CONFIG_FILE_DEFAULTS, then these values can be overwritten /// First, defaults are loaded from CONFIG_FILE_DEFAULTS, then these values can be overwritten
/// from CONFIG_FILE (optional). Finally, values from the environment (with prefix LEMMY) are /// from CONFIG_FILE (optional). Finally, values from the environment (with prefix LEMMY) are
/// added to the config. /// added to the config.
fn init() -> Result<Self, ConfigError> { pub fn init() -> Result<Self, ConfigError> {
let mut s = Config::new(); let mut s = Config::new();
s.merge(File::with_name(CONFIG_FILE_DEFAULTS))?; s.merge(File::with_name(CONFIG_FILE_DEFAULTS))?;
@ -90,9 +84,9 @@ impl Settings {
} }
/// Returns the config as a struct. /// Returns the config as a struct.
pub fn get() -> Self { // pub fn get() -> Self {
SETTINGS.read().unwrap().to_owned() // SETTINGS.read().unwrap().to_owned()
} // }
/// Returns the postgres connection url. If LEMMY_DATABASE_URL is set, that is used, /// Returns the postgres connection url. If LEMMY_DATABASE_URL is set, that is used,
/// otherwise the connection url is generated from the config. /// otherwise the connection url is generated from the config.
@ -120,15 +114,18 @@ impl Settings {
pub fn save_config_file(data: &str) -> Result<String, Error> { pub fn save_config_file(data: &str) -> Result<String, Error> {
fs::write(CONFIG_FILE, data)?; fs::write(CONFIG_FILE, data)?;
// Reload the new settings
// From https://stackoverflow.com/questions/29654927/how-do-i-assign-a-string-to-a-mutable-static-variable/47181804#47181804
let mut new_settings = SETTINGS.write().unwrap();
*new_settings = match Settings::init() {
Ok(c) => c,
Err(e) => panic!("{}", e),
};
Self::read_config_file() Self::read_config_file()
} }
// pub fn live_reload_config(new_settings: Self) -> Result<(), Error> {
// // TODO test that this works now
// // Reload the new settings
// // From https://stackoverflow.com/questions/29654927/how-do-i-assign-a-string-to-a-mutable-static-variable/47181804#47181804
// new_settings = match Settings::init() {
// Ok(c) => c,
// Err(e) => panic!("{}", e),
// };
// Ok(())
// }
} }

View file

@ -7,13 +7,16 @@ use diesel::r2d2::{ConnectionManager, Pool, PooledConnection};
use diesel::PgConnection; use diesel::PgConnection;
use failure::Error; use failure::Error;
use log::{error, info, warn}; use log::{error, info, warn};
use rand::{rngs::ThreadRng, Rng}; use rand::{Rng};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::str::FromStr; use std::str::FromStr;
use std::time::SystemTime; use std::time::SystemTime;
use std::sync::Mutex;
use std::sync::Arc;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use actix_web::web;
use crate::api::comment::*; use crate::api::comment::*;
use crate::api::community::*; use crate::api::community::*;
@ -80,105 +83,138 @@ pub enum RateLimitType {
Post, Post,
} }
/// `ChatServer` manages chat rooms and responsible for coordinating chat pub struct ChatSharedState {
/// session. /// The Settings
pub struct ChatServer { pub settings: Mutex<Settings>,
/// Connection pool
pub pool: Mutex<Pool<ConnectionManager<PgConnection>>>,
/// A map from generated random ID to session addr /// A map from generated random ID to session addr
sessions: HashMap<ConnectionId, SessionInfo>, sessions: Mutex<HashMap<ConnectionId, SessionInfo>>,
/// A map from post_id to set of connectionIDs /// A map from post_id to set of connectionIDs
post_rooms: HashMap<PostId, HashSet<ConnectionId>>, post_rooms: Mutex<HashMap<PostId, HashSet<ConnectionId>>>,
/// A map from community to set of connectionIDs /// A map from community to set of connectionIDs
community_rooms: HashMap<CommunityId, HashSet<ConnectionId>>, community_rooms: Mutex<HashMap<CommunityId, HashSet<ConnectionId>>>,
/// A map from user id to its connection ID for joined users. Remember a user can have multiple /// A map from user id to its connection ID for joined users. Remember a user can have multiple
/// sessions (IE clients) /// sessions (IE clients)
user_rooms: HashMap<UserId, HashSet<ConnectionId>>, user_rooms: Mutex<HashMap<UserId, HashSet<ConnectionId>>>,
/// Rate limiting based on rate type and IP addr /// Rate limiting based on rate type and IP addr
rate_limit_buckets: HashMap<RateLimitType, HashMap<IPAddr, RateLimitBucket>>, rate_limit_buckets: Mutex<HashMap<RateLimitType, HashMap<IPAddr, RateLimitBucket>>>,
}
rng: ThreadRng, impl ChatSharedState {
db: Pool<ConnectionManager<PgConnection>>, pub fn init() -> Self {
// Setup Settings
let settings = match Settings::init() {
Ok(c) => c,
Err(e) => panic!("{}", e),
};
// Set up the r2d2 connection pool
let manager = ConnectionManager::<PgConnection>::new(&settings.get_database_url());
let pool = Pool::builder()
.max_size(settings.database.pool_size)
.build(manager)
.unwrap_or_else(|_| panic!("Error connecting to {}", settings.get_database_url()));
ChatSharedState {
settings: Mutex::new(settings),
pool: Mutex::new(pool),
sessions: Mutex::new(HashMap::new()),
rate_limit_buckets: Mutex::new(HashMap::new()),
post_rooms: Mutex::new(HashMap::new()),
community_rooms: Mutex::new(HashMap::new()),
user_rooms: Mutex::new(HashMap::new()),
}
}
}
/// `ChatServer` manages chat rooms and responsible for coordinating chat
/// session.
pub struct ChatServer {
state: web::Data<ChatSharedState>,
} }
impl ChatServer { impl ChatServer {
pub fn startup(db: Pool<ConnectionManager<PgConnection>>) -> ChatServer { pub fn init(state: web::Data<ChatSharedState>) -> Self {
ChatServer { ChatServer {
sessions: HashMap::new(), state,
rate_limit_buckets: HashMap::new(),
post_rooms: HashMap::new(),
community_rooms: HashMap::new(),
user_rooms: HashMap::new(),
rng: rand::thread_rng(),
db,
} }
} }
fn join_community_room(&mut self, community_id: CommunityId, id: ConnectionId) { fn join_community_room(&self, community_id: CommunityId, id: ConnectionId) {
// remove session from all rooms // remove session from all rooms
for sessions in self.community_rooms.values_mut() { for sessions in self.state.community_rooms.lock().unwrap().values_mut() {
sessions.remove(&id); sessions.remove(&id);
} }
// Also leave all post rooms // Also leave all post rooms
// This avoids double messages // This avoids double messages
for sessions in self.post_rooms.values_mut() { for sessions in self.state.post_rooms.lock().unwrap().values_mut() {
sessions.remove(&id); sessions.remove(&id);
} }
// If the room doesn't exist yet // If the room doesn't exist yet
if self.community_rooms.get_mut(&community_id).is_none() { if self.state.community_rooms.lock().unwrap().get_mut(&community_id).is_none() {
self.community_rooms.insert(community_id, HashSet::new()); self.state.community_rooms.lock().unwrap().insert(community_id, HashSet::new());
} }
self self
.state
.community_rooms .community_rooms
.lock()
.unwrap()
.get_mut(&community_id) .get_mut(&community_id)
.unwrap() .unwrap()
.insert(id); .insert(id);
} }
fn join_post_room(&mut self, post_id: PostId, id: ConnectionId) { fn join_post_room(&self, post_id: PostId, id: ConnectionId) {
// remove session from all rooms // remove session from all rooms
for sessions in self.post_rooms.values_mut() { for sessions in self.state.post_rooms.lock().unwrap().values_mut() {
sessions.remove(&id); sessions.remove(&id);
} }
// Also leave all communities // Also leave all communities
// This avoids double messages // This avoids double messages
for sessions in self.community_rooms.values_mut() { for sessions in self.state.community_rooms.lock().unwrap().values_mut() {
sessions.remove(&id); sessions.remove(&id);
} }
// If the room doesn't exist yet // If the room doesn't exist yet
if self.post_rooms.get_mut(&post_id).is_none() { if self.state.post_rooms.lock().unwrap().get_mut(&post_id).is_none() {
self.post_rooms.insert(post_id, HashSet::new()); self.state.post_rooms.lock().unwrap().insert(post_id, HashSet::new());
} }
self.post_rooms.get_mut(&post_id).unwrap().insert(id); self.state.post_rooms.lock().unwrap().get_mut(&post_id).unwrap().insert(id);
} }
fn join_user_room(&mut self, user_id: UserId, id: ConnectionId) { fn join_user_room(&self, user_id: UserId, id: ConnectionId) {
// remove session from all rooms // remove session from all rooms
for sessions in self.user_rooms.values_mut() { for sessions in self.state.user_rooms.lock().unwrap().values_mut() {
sessions.remove(&id); sessions.remove(&id);
} }
// If the room doesn't exist yet // If the room doesn't exist yet
if self.user_rooms.get_mut(&user_id).is_none() { if self.state.user_rooms.lock().unwrap().get_mut(&user_id).is_none() {
self.user_rooms.insert(user_id, HashSet::new()); self.state.user_rooms.lock().unwrap().insert(user_id, HashSet::new());
} }
self.user_rooms.get_mut(&user_id).unwrap().insert(id); self.state.user_rooms.lock().unwrap().get_mut(&user_id).unwrap().insert(id);
} }
fn send_post_room_message(&self, post_id: PostId, message: &str, skip_id: ConnectionId) { fn send_post_room_message(&self, post_id: PostId, message: &str, skip_id: ConnectionId) {
if let Some(sessions) = self.post_rooms.get(&post_id) { if let Some(sessions) = self.state.post_rooms.lock().unwrap().get(&post_id) {
for id in sessions { for id in sessions {
if *id != skip_id { if *id != skip_id {
if let Some(info) = self.sessions.get(id) { if let Some(info) = self.state.sessions.lock().unwrap().get(id) {
let _ = info.addr.do_send(WSMessage(message.to_owned())); let _ = info.addr.do_send(WSMessage(message.to_owned()));
} }
} }
@ -192,10 +228,10 @@ impl ChatServer {
message: &str, message: &str,
skip_id: ConnectionId, skip_id: ConnectionId,
) { ) {
if let Some(sessions) = self.community_rooms.get(&community_id) { if let Some(sessions) = self.state.community_rooms.lock().unwrap().get(&community_id) {
for id in sessions { for id in sessions {
if *id != skip_id { if *id != skip_id {
if let Some(info) = self.sessions.get(id) { if let Some(info) = self.state.sessions.lock().unwrap().get(id) {
let _ = info.addr.do_send(WSMessage(message.to_owned())); let _ = info.addr.do_send(WSMessage(message.to_owned()));
} }
} }
@ -204,10 +240,10 @@ impl ChatServer {
} }
fn send_user_room_message(&self, user_id: UserId, message: &str, skip_id: ConnectionId) { fn send_user_room_message(&self, user_id: UserId, message: &str, skip_id: ConnectionId) {
if let Some(sessions) = self.user_rooms.get(&user_id) { if let Some(sessions) = self.state.user_rooms.lock().unwrap().get(&user_id) {
for id in sessions { for id in sessions {
if *id != skip_id { if *id != skip_id {
if let Some(info) = self.sessions.get(id) { if let Some(info) = self.state.sessions.lock().unwrap().get(id) {
let _ = info.addr.do_send(WSMessage(message.to_owned())); let _ = info.addr.do_send(WSMessage(message.to_owned()));
} }
} }
@ -216,9 +252,9 @@ impl ChatServer {
} }
fn send_all_message(&self, message: &str, skip_id: ConnectionId) { fn send_all_message(&self, message: &str, skip_id: ConnectionId) {
for id in self.sessions.keys() { for id in self.state.sessions.lock().unwrap().keys() {
if *id != skip_id { if *id != skip_id {
if let Some(info) = self.sessions.get(id) { if let Some(info) = self.state.sessions.lock().unwrap().get(id) {
let _ = info.addr.do_send(WSMessage(message.to_owned())); let _ = info.addr.do_send(WSMessage(message.to_owned()));
} }
} }
@ -287,47 +323,47 @@ impl ChatServer {
to_json_string(&user_operation, post) to_json_string(&user_operation, post)
} }
fn check_rate_limit_register(&mut self, id: usize, check_only: bool) -> Result<(), Error> { fn check_rate_limit_register(&self, id: usize, check_only: bool) -> Result<(), Error> {
self.check_rate_limit_full( self.check_rate_limit_full(
RateLimitType::Register, RateLimitType::Register,
id, id,
Settings::get().rate_limit.register, self.state.settings.lock().unwrap().rate_limit.register,
Settings::get().rate_limit.register_per_second, self.state.settings.lock().unwrap().rate_limit.register_per_second,
check_only, check_only,
) )
} }
fn check_rate_limit_post(&mut self, id: usize, check_only: bool) -> Result<(), Error> { fn check_rate_limit_post(&self, id: usize, check_only: bool) -> Result<(), Error> {
self.check_rate_limit_full( self.check_rate_limit_full(
RateLimitType::Post, RateLimitType::Post,
id, id,
Settings::get().rate_limit.post, self.state.settings.lock().unwrap().rate_limit.post,
Settings::get().rate_limit.post_per_second, self.state.settings.lock().unwrap().rate_limit.post_per_second,
check_only, check_only,
) )
} }
fn check_rate_limit_message(&mut self, id: usize, check_only: bool) -> Result<(), Error> { fn check_rate_limit_message(&self, id: usize, check_only: bool) -> Result<(), Error> {
self.check_rate_limit_full( self.check_rate_limit_full(
RateLimitType::Message, RateLimitType::Message,
id, id,
Settings::get().rate_limit.message, self.state.settings.lock().unwrap().rate_limit.message,
Settings::get().rate_limit.message_per_second, self.state.settings.lock().unwrap().rate_limit.message_per_second,
check_only, check_only,
) )
} }
#[allow(clippy::float_cmp)] #[allow(clippy::float_cmp)]
fn check_rate_limit_full( fn check_rate_limit_full(
&mut self, &self,
type_: RateLimitType, type_: RateLimitType,
id: usize, id: usize,
rate: i32, rate: i32,
per: i32, per: i32,
check_only: bool, check_only: bool,
) -> Result<(), Error> { ) -> Result<(), Error> {
if let Some(info) = self.sessions.get(&id) { if let Some(info) = self.state.sessions.lock().unwrap().get(&id) {
if let Some(bucket) = self.rate_limit_buckets.get_mut(&type_) { if let Some(bucket) = self.state.rate_limit_buckets.lock().unwrap().get_mut(&type_) {
if let Some(rate_limit) = bucket.get_mut(&info.ip) { if let Some(rate_limit) = bucket.get_mut(&info.ip) {
let current = SystemTime::now(); let current = SystemTime::now();
let time_passed = current.duration_since(rate_limit.last_checked)?.as_secs() as f64; let time_passed = current.duration_since(rate_limit.last_checked)?.as_secs() as f64;
@ -376,7 +412,7 @@ impl ChatServer {
impl Actor for ChatServer { impl Actor for ChatServer {
/// We are going to use simple Context, we just need ability to communicate /// We are going to use simple Context, we just need ability to communicate
/// with other actors. /// with other actors.
type Context = Context<Self>; type Context = SyncContext<Self>;
} }
/// Handler for Connect message. /// Handler for Connect message.
@ -385,12 +421,12 @@ impl Actor for ChatServer {
impl Handler<Connect> for ChatServer { impl Handler<Connect> for ChatServer {
type Result = usize; type Result = usize;
fn handle(&mut self, msg: Connect, _ctx: &mut Context<Self>) -> Self::Result { fn handle(&mut self, msg: Connect, _ctx: &mut SyncContext<Self>) -> Self::Result {
// register session with random id // register session with random id
let id = self.rng.gen::<usize>(); let id = rand::thread_rng().gen::<usize>();
info!("{} joined", &msg.ip); info!("{} joined", &msg.ip);
self.sessions.insert( self.state.sessions.lock().unwrap().insert(
id, id,
SessionInfo { SessionInfo {
addr: msg.addr, addr: msg.addr,
@ -399,13 +435,16 @@ impl Handler<Connect> for ChatServer {
); );
for rate_limit_type in RateLimitType::iter() { for rate_limit_type in RateLimitType::iter() {
if self.rate_limit_buckets.get(&rate_limit_type).is_none() { if self.state.rate_limit_buckets.lock().unwrap().get(&rate_limit_type).is_none() {
self self
.state
.rate_limit_buckets .rate_limit_buckets
.lock()
.unwrap()
.insert(rate_limit_type, HashMap::new()); .insert(rate_limit_type, HashMap::new());
} }
if let Some(bucket) = self.rate_limit_buckets.get_mut(&rate_limit_type) { if let Some(bucket) = self.state.rate_limit_buckets.lock().unwrap().get_mut(&rate_limit_type) {
if bucket.get(&msg.ip).is_none() { if bucket.get(&msg.ip).is_none() {
bucket.insert( bucket.insert(
msg.ip.to_owned(), msg.ip.to_owned(),
@ -426,18 +465,18 @@ impl Handler<Connect> for ChatServer {
impl Handler<Disconnect> for ChatServer { impl Handler<Disconnect> for ChatServer {
type Result = (); type Result = ();
fn handle(&mut self, msg: Disconnect, _: &mut Context<Self>) { fn handle(&mut self, msg: Disconnect, _: &mut SyncContext<Self>) {
// Remove connections from sessions and all 3 scopes // Remove connections from sessions and all 3 scopes
if self.sessions.remove(&msg.id).is_some() { if self.state.sessions.lock().unwrap().remove(&msg.id).is_some() {
for sessions in self.user_rooms.values_mut() { for sessions in self.state.user_rooms.lock().unwrap().values_mut() {
sessions.remove(&msg.id); sessions.remove(&msg.id);
} }
for sessions in self.post_rooms.values_mut() { for sessions in self.state.post_rooms.lock().unwrap().values_mut() {
sessions.remove(&msg.id); sessions.remove(&msg.id);
} }
for sessions in self.community_rooms.values_mut() { for sessions in self.state.community_rooms.lock().unwrap().values_mut() {
sessions.remove(&msg.id); sessions.remove(&msg.id);
} }
} }
@ -448,7 +487,7 @@ impl Handler<Disconnect> for ChatServer {
impl Handler<StandardMessage> for ChatServer { impl Handler<StandardMessage> for ChatServer {
type Result = MessageResult<StandardMessage>; type Result = MessageResult<StandardMessage>;
fn handle(&mut self, msg: StandardMessage, _: &mut Context<Self>) -> Self::Result { fn handle(&mut self, msg: StandardMessage, _: &mut SyncContext<Self>) -> Self::Result {
match parse_json_message(self, msg) { match parse_json_message(self, msg) {
Ok(m) => { Ok(m) => {
info!("Message Sent: {}", m); info!("Message Sent: {}", m);
@ -483,6 +522,7 @@ fn do_user_operation<'a, Data, Response>(
op: UserOperation, op: UserOperation,
data: &str, data: &str,
conn: &PooledConnection<ConnectionManager<PgConnection>>, conn: &PooledConnection<ConnectionManager<PgConnection>>,
settings: &Settings,
) -> Result<String, Error> ) -> Result<String, Error>
where where
for<'de> Data: Deserialize<'de> + 'a, for<'de> Data: Deserialize<'de> + 'a,
@ -490,7 +530,7 @@ where
Oper<Data>: Perform<Response>, Oper<Data>: Perform<Response>,
{ {
let parsed_data: Data = serde_json::from_str(data)?; let parsed_data: Data = serde_json::from_str(data)?;
let res = Oper::new(parsed_data).perform(&conn)?; let res = Oper::new(parsed_data).perform(&conn, &settings)?;
to_json_string(&op, &res) to_json_string(&op, &res)
} }
@ -501,7 +541,8 @@ fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<Str
message: "Unknown op type".to_string(), message: "Unknown op type".to_string(),
})?; })?;
let conn = chat.db.get()?; let conn = chat.state.pool.lock().unwrap().get()?;
let settings = chat.state.settings.lock().unwrap();
let user_operation: UserOperation = UserOperation::from_str(&op)?; let user_operation: UserOperation = UserOperation::from_str(&op)?;
@ -512,54 +553,54 @@ fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<Str
chat.check_rate_limit_message(msg.id, false)?; chat.check_rate_limit_message(msg.id, false)?;
match user_operation { match user_operation {
UserOperation::Login => do_user_operation::<Login, LoginResponse>(user_operation, data, &conn), UserOperation::Login => do_user_operation::<Login, LoginResponse>(user_operation, data, &conn, &settings),
UserOperation::Register => { UserOperation::Register => {
chat.check_rate_limit_register(msg.id, true)?; chat.check_rate_limit_register(msg.id, true)?;
let register: Register = serde_json::from_str(data)?; let register: Register = serde_json::from_str(data)?;
let res = Oper::new(register).perform(&conn)?; let res = Oper::new(register).perform(&conn, &settings)?;
chat.check_rate_limit_register(msg.id, false)?; chat.check_rate_limit_register(msg.id, false)?;
to_json_string(&user_operation, &res) to_json_string(&user_operation, &res)
} }
UserOperation::GetUserDetails => { UserOperation::GetUserDetails => {
do_user_operation::<GetUserDetails, GetUserDetailsResponse>(user_operation, data, &conn) do_user_operation::<GetUserDetails, GetUserDetailsResponse>(user_operation, data, &conn, &settings)
} }
UserOperation::SaveUserSettings => { UserOperation::SaveUserSettings => {
do_user_operation::<SaveUserSettings, LoginResponse>(user_operation, data, &conn) do_user_operation::<SaveUserSettings, LoginResponse>(user_operation, data, &conn, &settings)
} }
UserOperation::AddAdmin => { UserOperation::AddAdmin => {
let add_admin: AddAdmin = serde_json::from_str(data)?; let add_admin: AddAdmin = serde_json::from_str(data)?;
let res = Oper::new(add_admin).perform(&conn)?; let res = Oper::new(add_admin).perform(&conn, &settings)?;
let res_str = to_json_string(&user_operation, &res)?; let res_str = to_json_string(&user_operation, &res)?;
chat.send_all_message(&res_str, msg.id); chat.send_all_message(&res_str, msg.id);
Ok(res_str) Ok(res_str)
} }
UserOperation::BanUser => { UserOperation::BanUser => {
let ban_user: BanUser = serde_json::from_str(data)?; let ban_user: BanUser = serde_json::from_str(data)?;
let res = Oper::new(ban_user).perform(&conn)?; let res = Oper::new(ban_user).perform(&conn, &settings)?;
let res_str = to_json_string(&user_operation, &res)?; let res_str = to_json_string(&user_operation, &res)?;
chat.send_all_message(&res_str, msg.id); chat.send_all_message(&res_str, msg.id);
Ok(res_str) Ok(res_str)
} }
UserOperation::GetReplies => { UserOperation::GetReplies => {
do_user_operation::<GetReplies, GetRepliesResponse>(user_operation, data, &conn) do_user_operation::<GetReplies, GetRepliesResponse>(user_operation, data, &conn, &settings)
} }
UserOperation::GetUserMentions => { UserOperation::GetUserMentions => {
do_user_operation::<GetUserMentions, GetUserMentionsResponse>(user_operation, data, &conn) do_user_operation::<GetUserMentions, GetUserMentionsResponse>(user_operation, data, &conn, &settings)
} }
UserOperation::EditUserMention => { UserOperation::EditUserMention => {
do_user_operation::<EditUserMention, UserMentionResponse>(user_operation, data, &conn) do_user_operation::<EditUserMention, UserMentionResponse>(user_operation, data, &conn, &settings)
} }
UserOperation::MarkAllAsRead => { UserOperation::MarkAllAsRead => {
do_user_operation::<MarkAllAsRead, GetRepliesResponse>(user_operation, data, &conn) do_user_operation::<MarkAllAsRead, GetRepliesResponse>(user_operation, data, &conn, &settings)
} }
UserOperation::GetCommunity => { UserOperation::GetCommunity => {
let get_community: GetCommunity = serde_json::from_str(data)?; let get_community: GetCommunity = serde_json::from_str(data)?;
let mut res = Oper::new(get_community).perform(&conn)?; let mut res = Oper::new(get_community).perform(&conn, &settings)?;
let community_id = res.community.id; let community_id = res.community.id;
chat.join_community_room(community_id, msg.id); chat.join_community_room(community_id, msg.id);
res.online = if let Some(community_users) = chat.community_rooms.get(&community_id) { res.online = if let Some(community_users) = chat.state.community_rooms.lock().unwrap().get(&community_id) {
community_users.len() community_users.len()
} else { } else {
0 0
@ -568,18 +609,18 @@ fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<Str
to_json_string(&user_operation, &res) to_json_string(&user_operation, &res)
} }
UserOperation::ListCommunities => { UserOperation::ListCommunities => {
do_user_operation::<ListCommunities, ListCommunitiesResponse>(user_operation, data, &conn) do_user_operation::<ListCommunities, ListCommunitiesResponse>(user_operation, data, &conn, &settings)
} }
UserOperation::CreateCommunity => { UserOperation::CreateCommunity => {
chat.check_rate_limit_register(msg.id, true)?; chat.check_rate_limit_register(msg.id, true)?;
let create_community: CreateCommunity = serde_json::from_str(data)?; let create_community: CreateCommunity = serde_json::from_str(data)?;
let res = Oper::new(create_community).perform(&conn)?; let res = Oper::new(create_community).perform(&conn, &settings)?;
chat.check_rate_limit_register(msg.id, false)?; chat.check_rate_limit_register(msg.id, false)?;
to_json_string(&user_operation, &res) to_json_string(&user_operation, &res)
} }
UserOperation::EditCommunity => { UserOperation::EditCommunity => {
let edit_community: EditCommunity = serde_json::from_str(data)?; let edit_community: EditCommunity = serde_json::from_str(data)?;
let res = Oper::new(edit_community).perform(&conn)?; let res = Oper::new(edit_community).perform(&conn, &settings)?;
let mut community_sent: CommunityResponse = res.clone(); let mut community_sent: CommunityResponse = res.clone();
community_sent.community.user_id = None; community_sent.community.user_id = None;
community_sent.community.subscribed = None; community_sent.community.subscribed = None;
@ -588,16 +629,16 @@ fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<Str
to_json_string(&user_operation, &res) to_json_string(&user_operation, &res)
} }
UserOperation::FollowCommunity => { UserOperation::FollowCommunity => {
do_user_operation::<FollowCommunity, CommunityResponse>(user_operation, data, &conn) do_user_operation::<FollowCommunity, CommunityResponse>(user_operation, data, &conn, &settings)
} }
UserOperation::GetFollowedCommunities => do_user_operation::< UserOperation::GetFollowedCommunities => do_user_operation::<
GetFollowedCommunities, GetFollowedCommunities,
GetFollowedCommunitiesResponse, GetFollowedCommunitiesResponse,
>(user_operation, data, &conn), >(user_operation, data, &conn, &settings),
UserOperation::BanFromCommunity => { UserOperation::BanFromCommunity => {
let ban_from_community: BanFromCommunity = serde_json::from_str(data)?; let ban_from_community: BanFromCommunity = serde_json::from_str(data)?;
let community_id = ban_from_community.community_id; let community_id = ban_from_community.community_id;
let res = Oper::new(ban_from_community).perform(&conn)?; let res = Oper::new(ban_from_community).perform(&conn, &settings)?;
let res_str = to_json_string(&user_operation, &res)?; let res_str = to_json_string(&user_operation, &res)?;
chat.send_community_room_message(community_id, &res_str, msg.id); chat.send_community_room_message(community_id, &res_str, msg.id);
Ok(res_str) Ok(res_str)
@ -605,21 +646,21 @@ fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<Str
UserOperation::AddModToCommunity => { UserOperation::AddModToCommunity => {
let mod_add_to_community: AddModToCommunity = serde_json::from_str(data)?; let mod_add_to_community: AddModToCommunity = serde_json::from_str(data)?;
let community_id = mod_add_to_community.community_id; let community_id = mod_add_to_community.community_id;
let res = Oper::new(mod_add_to_community).perform(&conn)?; let res = Oper::new(mod_add_to_community).perform(&conn, &settings)?;
let res_str = to_json_string(&user_operation, &res)?; let res_str = to_json_string(&user_operation, &res)?;
chat.send_community_room_message(community_id, &res_str, msg.id); chat.send_community_room_message(community_id, &res_str, msg.id);
Ok(res_str) Ok(res_str)
} }
UserOperation::ListCategories => { UserOperation::ListCategories => {
do_user_operation::<ListCategories, ListCategoriesResponse>(user_operation, data, &conn) do_user_operation::<ListCategories, ListCategoriesResponse>(user_operation, data, &conn, &settings)
} }
UserOperation::GetPost => { UserOperation::GetPost => {
let get_post: GetPost = serde_json::from_str(data)?; let get_post: GetPost = serde_json::from_str(data)?;
let post_id = get_post.id; let post_id = get_post.id;
chat.join_post_room(post_id, msg.id); chat.join_post_room(post_id, msg.id);
let mut res = Oper::new(get_post).perform(&conn)?; let mut res = Oper::new(get_post).perform(&conn, &settings)?;
res.online = if let Some(post_users) = chat.post_rooms.get(&post_id) { res.online = if let Some(post_users) = chat.state.post_rooms.lock().unwrap().get(&post_id) {
post_users.len() post_users.len()
} else { } else {
0 0
@ -633,7 +674,7 @@ fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<Str
// 0 is the "all" community // 0 is the "all" community
chat.join_community_room(0, msg.id); chat.join_community_room(0, msg.id);
} }
let res = Oper::new(get_posts).perform(&conn)?; let res = Oper::new(get_posts).perform(&conn, &settings)?;
to_json_string(&user_operation, &res) to_json_string(&user_operation, &res)
} }
UserOperation::GetComments => { UserOperation::GetComments => {
@ -642,118 +683,123 @@ fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<Str
// 0 is the "all" community // 0 is the "all" community
chat.join_community_room(0, msg.id); chat.join_community_room(0, msg.id);
} }
let res = Oper::new(get_comments).perform(&conn)?; let res = Oper::new(get_comments).perform(&conn, &settings)?;
to_json_string(&user_operation, &res) to_json_string(&user_operation, &res)
} }
UserOperation::CreatePost => { UserOperation::CreatePost => {
chat.check_rate_limit_post(msg.id, true)?; chat.check_rate_limit_post(msg.id, true)?;
let create_post: CreatePost = serde_json::from_str(data)?; let create_post: CreatePost = serde_json::from_str(data)?;
let res = Oper::new(create_post).perform(&conn)?; let res = Oper::new(create_post).perform(&conn, &settings)?;
chat.check_rate_limit_post(msg.id, false)?; chat.check_rate_limit_post(msg.id, false)?;
chat.post_sends(UserOperation::CreatePost, res, msg.id) chat.post_sends(UserOperation::CreatePost, res, msg.id)
} }
UserOperation::CreatePostLike => { UserOperation::CreatePostLike => {
let create_post_like: CreatePostLike = serde_json::from_str(data)?; let create_post_like: CreatePostLike = serde_json::from_str(data)?;
let res = Oper::new(create_post_like).perform(&conn)?; let res = Oper::new(create_post_like).perform(&conn, &settings)?;
chat.post_sends(UserOperation::CreatePostLike, res, msg.id) chat.post_sends(UserOperation::CreatePostLike, res, msg.id)
} }
UserOperation::EditPost => { UserOperation::EditPost => {
let edit_post: EditPost = serde_json::from_str(data)?; let edit_post: EditPost = serde_json::from_str(data)?;
let res = Oper::new(edit_post).perform(&conn)?; let res = Oper::new(edit_post).perform(&conn, &settings)?;
chat.post_sends(UserOperation::EditPost, res, msg.id) chat.post_sends(UserOperation::EditPost, res, msg.id)
} }
UserOperation::SavePost => { UserOperation::SavePost => {
do_user_operation::<SavePost, PostResponse>(user_operation, data, &conn) do_user_operation::<SavePost, PostResponse>(user_operation, data, &conn, &settings)
} }
UserOperation::CreateComment => { UserOperation::CreateComment => {
let create_comment: CreateComment = serde_json::from_str(data)?; let create_comment: CreateComment = serde_json::from_str(data)?;
let res = Oper::new(create_comment).perform(&conn)?; let res = Oper::new(create_comment).perform(&conn, &settings)?;
chat.comment_sends(UserOperation::CreateComment, res, msg.id) chat.comment_sends(UserOperation::CreateComment, res, msg.id)
} }
UserOperation::EditComment => { UserOperation::EditComment => {
let edit_comment: EditComment = serde_json::from_str(data)?; let edit_comment: EditComment = serde_json::from_str(data)?;
let res = Oper::new(edit_comment).perform(&conn)?; let res = Oper::new(edit_comment).perform(&conn, &settings)?;
chat.comment_sends(UserOperation::EditComment, res, msg.id) chat.comment_sends(UserOperation::EditComment, res, msg.id)
} }
UserOperation::SaveComment => { UserOperation::SaveComment => {
do_user_operation::<SaveComment, CommentResponse>(user_operation, data, &conn) do_user_operation::<SaveComment, CommentResponse>(user_operation, data, &conn, &settings)
} }
UserOperation::CreateCommentLike => { UserOperation::CreateCommentLike => {
let create_comment_like: CreateCommentLike = serde_json::from_str(data)?; let create_comment_like: CreateCommentLike = serde_json::from_str(data)?;
let res = Oper::new(create_comment_like).perform(&conn)?; let res = Oper::new(create_comment_like).perform(&conn, &settings)?;
chat.comment_sends(UserOperation::CreateCommentLike, res, msg.id) chat.comment_sends(UserOperation::CreateCommentLike, res, msg.id)
} }
UserOperation::GetModlog => { UserOperation::GetModlog => {
do_user_operation::<GetModlog, GetModlogResponse>(user_operation, data, &conn) do_user_operation::<GetModlog, GetModlogResponse>(user_operation, data, &conn, &settings)
} }
UserOperation::CreateSite => { UserOperation::CreateSite => {
do_user_operation::<CreateSite, SiteResponse>(user_operation, data, &conn) do_user_operation::<CreateSite, SiteResponse>(user_operation, data, &conn, &settings)
} }
UserOperation::EditSite => { UserOperation::EditSite => {
let edit_site: EditSite = serde_json::from_str(data)?; let edit_site: EditSite = serde_json::from_str(data)?;
let res = Oper::new(edit_site).perform(&conn)?; let res = Oper::new(edit_site).perform(&conn, &settings)?;
let res_str = to_json_string(&user_operation, &res)?; let res_str = to_json_string(&user_operation, &res)?;
chat.send_all_message(&res_str, msg.id); chat.send_all_message(&res_str, msg.id);
Ok(res_str) Ok(res_str)
} }
UserOperation::GetSite => { UserOperation::GetSite => {
let get_site: GetSite = serde_json::from_str(data)?; let get_site: GetSite = serde_json::from_str(data)?;
let mut res = Oper::new(get_site).perform(&conn)?; let mut res = Oper::new(get_site).perform(&conn, &settings)?;
res.online = chat.sessions.len(); res.online = chat.state.sessions.lock().unwrap().len();
to_json_string(&user_operation, &res) to_json_string(&user_operation, &res)
} }
UserOperation::GetSiteConfig => { UserOperation::GetSiteConfig => {
let get_site_config: GetSiteConfig = serde_json::from_str(data)?; let get_site_config: GetSiteConfig = serde_json::from_str(data)?;
let res = Oper::new(get_site_config).perform(&conn)?; let res = Oper::new(get_site_config).perform(&conn, &settings)?;
to_json_string(&user_operation, &res) to_json_string(&user_operation, &res)
} }
UserOperation::SaveSiteConfig => { UserOperation::SaveSiteConfig => {
let save_site_config: SaveSiteConfig = serde_json::from_str(data)?; let save_site_config: SaveSiteConfig = serde_json::from_str(data)?;
let res = Oper::new(save_site_config).perform(&conn)?; let res = Oper::new(save_site_config).perform(&conn, &settings)?;
let mut new_settings = chat.state.settings.lock().unwrap();
*new_settings = match Settings::init() {
Ok(c) => c,
Err(e) => panic!("{}", e),
};
to_json_string(&user_operation, &res) to_json_string(&user_operation, &res)
} }
UserOperation::Search => { UserOperation::Search => {
do_user_operation::<Search, SearchResponse>(user_operation, data, &conn) do_user_operation::<Search, SearchResponse>(user_operation, data, &conn, &settings)
} }
UserOperation::TransferCommunity => { UserOperation::TransferCommunity => {
do_user_operation::<TransferCommunity, GetCommunityResponse>(user_operation, data, &conn) do_user_operation::<TransferCommunity, GetCommunityResponse>(user_operation, data, &conn, &settings)
} }
UserOperation::TransferSite => { UserOperation::TransferSite => {
do_user_operation::<TransferSite, GetSiteResponse>(user_operation, data, &conn) do_user_operation::<TransferSite, GetSiteResponse>(user_operation, data, &conn, &settings)
} }
UserOperation::DeleteAccount => { UserOperation::DeleteAccount => {
do_user_operation::<DeleteAccount, LoginResponse>(user_operation, data, &conn) do_user_operation::<DeleteAccount, LoginResponse>(user_operation, data, &conn, &settings)
} }
UserOperation::PasswordReset => { UserOperation::PasswordReset => {
do_user_operation::<PasswordReset, PasswordResetResponse>(user_operation, data, &conn) do_user_operation::<PasswordReset, PasswordResetResponse>(user_operation, data, &conn, &settings)
} }
UserOperation::PasswordChange => { UserOperation::PasswordChange => {
do_user_operation::<PasswordChange, LoginResponse>(user_operation, data, &conn) do_user_operation::<PasswordChange, LoginResponse>(user_operation, data, &conn, &settings)
} }
UserOperation::CreatePrivateMessage => { UserOperation::CreatePrivateMessage => {
let create_private_message: CreatePrivateMessage = serde_json::from_str(data)?; let create_private_message: CreatePrivateMessage = serde_json::from_str(data)?;
let recipient_id = create_private_message.recipient_id; let recipient_id = create_private_message.recipient_id;
let res = Oper::new(create_private_message).perform(&conn)?; let res = Oper::new(create_private_message).perform(&conn, &settings)?;
let res_str = to_json_string(&user_operation, &res)?; let res_str = to_json_string(&user_operation, &res)?;
chat.send_user_room_message(recipient_id, &res_str, msg.id); chat.send_user_room_message(recipient_id, &res_str, msg.id);
Ok(res_str) Ok(res_str)
} }
UserOperation::EditPrivateMessage => { UserOperation::EditPrivateMessage => {
do_user_operation::<EditPrivateMessage, PrivateMessageResponse>(user_operation, data, &conn) do_user_operation::<EditPrivateMessage, PrivateMessageResponse>(user_operation, data, &conn, &settings)
} }
UserOperation::GetPrivateMessages => { UserOperation::GetPrivateMessages => {
do_user_operation::<GetPrivateMessages, PrivateMessagesResponse>(user_operation, data, &conn) do_user_operation::<GetPrivateMessages, PrivateMessagesResponse>(user_operation, data, &conn, &settings)
} }
UserOperation::UserJoin => { UserOperation::UserJoin => {
let user_join: UserJoin = serde_json::from_str(data)?; let user_join: UserJoin = serde_json::from_str(data)?;
let res = Oper::new(user_join).perform(&conn)?; let res = Oper::new(user_join).perform(&conn, &settings)?;
chat.join_user_room(res.user_id, msg.id); chat.join_user_room(res.user_id, msg.id);
to_json_string(&user_operation, &res) to_json_string(&user_operation, &res)
} }