Running cargo fmt on server code.

- Adding a .rustfmt.toml for the 2 space indent.
This commit is contained in:
Dessalines 2019-09-07 08:35:05 -07:00
parent 7db64f631e
commit b634061b87
24 changed files with 1697 additions and 1583 deletions

1
server/.rustfmt.toml vendored Normal file
View file

@ -0,0 +1 @@
tab_spaces = 2

View file

@ -6,7 +6,7 @@ pub struct CreateComment {
parent_id: Option<i32>, parent_id: Option<i32>,
edit_id: Option<i32>, edit_id: Option<i32>,
pub post_id: i32, pub post_id: i32,
auth: String auth: String,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -20,20 +20,20 @@ pub struct EditComment {
deleted: Option<bool>, deleted: Option<bool>,
reason: Option<String>, reason: Option<String>,
read: Option<bool>, read: Option<bool>,
auth: String auth: String,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct SaveComment { pub struct SaveComment {
comment_id: i32, comment_id: i32,
save: bool, save: bool,
auth: String auth: String,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
pub struct CommentResponse { pub struct CommentResponse {
op: String, op: String,
pub comment: CommentView pub comment: CommentView,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -41,10 +41,9 @@ pub struct CreateCommentLike {
comment_id: i32, comment_id: i32,
pub post_id: i32, pub post_id: i32,
score: i16, score: i16,
auth: String auth: String,
} }
impl Perform<CommentResponse> for Oper<CreateComment> { impl Perform<CommentResponse> for Oper<CreateComment> {
fn perform(&self) -> Result<CommentResponse, Error> { fn perform(&self) -> Result<CommentResponse, Error> {
let data: &CreateComment = &self.data; let data: &CreateComment = &self.data;
@ -52,9 +51,7 @@ impl Perform<CommentResponse> for Oper<CreateComment> {
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
let user_id = claims.id; let user_id = claims.id;
@ -62,12 +59,12 @@ impl Perform<CommentResponse> for Oper<CreateComment> {
// 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)?;
if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() { if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() {
return Err(APIError::err(&self.op, "community_ban"))? return Err(APIError::err(&self.op, "community_ban"))?;
} }
// Check for a site ban // Check for a site ban
if UserView::read(&conn, user_id)?.banned { if UserView::read(&conn, user_id)?.banned {
return Err(APIError::err(&self.op, "site_ban"))? return Err(APIError::err(&self.op, "site_ban"))?;
} }
let content_slurs_removed = remove_slurs(&data.content.to_owned()); let content_slurs_removed = remove_slurs(&data.content.to_owned());
@ -80,14 +77,12 @@ impl Perform<CommentResponse> for Oper<CreateComment> {
removed: None, removed: None,
deleted: None, deleted: None,
read: None, read: None,
updated: None updated: None,
}; };
let inserted_comment = match Comment::create(&conn, &comment_form) { let inserted_comment = match Comment::create(&conn, &comment_form) {
Ok(comment) => comment, Ok(comment) => comment,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_create_comment"))?,
return Err(APIError::err(&self.op, "couldnt_create_comment"))?
}
}; };
// You like your own comment by default // You like your own comment by default
@ -95,24 +90,20 @@ impl Perform<CommentResponse> for Oper<CreateComment> {
comment_id: inserted_comment.id, comment_id: inserted_comment.id,
post_id: data.post_id, post_id: data.post_id,
user_id: user_id, user_id: user_id,
score: 1 score: 1,
}; };
let _inserted_like = match CommentLike::like(&conn, &like_form) { let _inserted_like = match CommentLike::like(&conn, &like_form) {
Ok(like) => like, Ok(like) => like,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_like_comment"))?,
return Err(APIError::err(&self.op, "couldnt_like_comment"))?
}
}; };
let comment_view = CommentView::read(&conn, inserted_comment.id, Some(user_id))?; let comment_view = CommentView::read(&conn, inserted_comment.id, Some(user_id))?;
Ok( Ok(CommentResponse {
CommentResponse {
op: self.op.to_string(), op: self.op.to_string(),
comment: comment_view comment: comment_view,
} })
)
} }
} }
@ -123,9 +114,7 @@ impl Perform<CommentResponse> for Oper<EditComment> {
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
let user_id = claims.id; let user_id = claims.id;
@ -134,38 +123,29 @@ impl Perform<CommentResponse> for Oper<EditComment> {
// You are allowed to mark the comment as read even if you're banned. // You are allowed to mark the comment as read even if you're banned.
if data.read.is_none() { if data.read.is_none() {
// Verify its the creator or a mod, or an admin // Verify its the creator or a mod, or an admin
let mut editors: Vec<i32> = vec![data.creator_id]; let mut editors: Vec<i32> = vec![data.creator_id];
editors.append( editors.append(
&mut CommunityModeratorView::for_community(&conn, orig_comment.community_id) &mut CommunityModeratorView::for_community(&conn, orig_comment.community_id)?
?
.into_iter() .into_iter()
.map(|m| m.user_id) .map(|m| m.user_id)
.collect() .collect(),
);
editors.append(
&mut UserView::admins(&conn)
?
.into_iter()
.map(|a| a.id)
.collect()
); );
editors.append(&mut UserView::admins(&conn)?.into_iter().map(|a| a.id).collect());
if !editors.contains(&user_id) { if !editors.contains(&user_id) {
return Err(APIError::err(&self.op, "no_comment_edit_allowed"))? return Err(APIError::err(&self.op, "no_comment_edit_allowed"))?;
} }
// Check for a community ban // Check for a community ban
if CommunityUserBanView::get(&conn, user_id, orig_comment.community_id).is_ok() { if CommunityUserBanView::get(&conn, user_id, orig_comment.community_id).is_ok() {
return Err(APIError::err(&self.op, "community_ban"))? return Err(APIError::err(&self.op, "community_ban"))?;
} }
// Check for a site ban // Check for a site ban
if UserView::read(&conn, user_id)?.banned { if UserView::read(&conn, user_id)?.banned {
return Err(APIError::err(&self.op, "site_ban"))? return Err(APIError::err(&self.op, "site_ban"))?;
} }
} }
let content_slurs_removed = remove_slurs(&data.content.to_owned()); let content_slurs_removed = remove_slurs(&data.content.to_owned());
@ -178,14 +158,16 @@ impl Perform<CommentResponse> for Oper<EditComment> {
removed: data.removed.to_owned(), removed: data.removed.to_owned(),
deleted: data.deleted.to_owned(), deleted: data.deleted.to_owned(),
read: data.read.to_owned(), read: data.read.to_owned(),
updated: if data.read.is_some() { orig_comment.updated } else {Some(naive_now())} updated: if data.read.is_some() {
orig_comment.updated
} else {
Some(naive_now())
},
}; };
let _updated_comment = match Comment::update(&conn, data.edit_id, &comment_form) { let _updated_comment = match Comment::update(&conn, data.edit_id, &comment_form) {
Ok(comment) => comment, Ok(comment) => comment,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_comment"))?,
return Err(APIError::err(&self.op, "couldnt_update_comment"))?
}
}; };
// Mod tables // Mod tables
@ -199,16 +181,12 @@ impl Perform<CommentResponse> for Oper<EditComment> {
ModRemoveComment::create(&conn, &form)?; ModRemoveComment::create(&conn, &form)?;
} }
let comment_view = CommentView::read(&conn, data.edit_id, Some(user_id))?; let comment_view = CommentView::read(&conn, data.edit_id, Some(user_id))?;
Ok( Ok(CommentResponse {
CommentResponse {
op: self.op.to_string(), op: self.op.to_string(),
comment: comment_view comment: comment_view,
} })
)
} }
} }
@ -219,9 +197,7 @@ impl Perform<CommentResponse> for Oper<SaveComment> {
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
let user_id = claims.id; let user_id = claims.id;
@ -234,27 +210,21 @@ impl Perform<CommentResponse> for Oper<SaveComment> {
if data.save { if data.save {
match CommentSaved::save(&conn, &comment_saved_form) { match CommentSaved::save(&conn, &comment_saved_form) {
Ok(comment) => comment, Ok(comment) => comment,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_save_comment"))?,
return Err(APIError::err(&self.op, "couldnt_save_comment"))?
}
}; };
} else { } else {
match CommentSaved::unsave(&conn, &comment_saved_form) { match CommentSaved::unsave(&conn, &comment_saved_form) {
Ok(comment) => comment, Ok(comment) => comment,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_save_comment"))?,
return Err(APIError::err(&self.op, "couldnt_save_comment"))?
}
}; };
} }
let comment_view = CommentView::read(&conn, data.comment_id, Some(user_id))?; let comment_view = CommentView::read(&conn, data.comment_id, Some(user_id))?;
Ok( Ok(CommentResponse {
CommentResponse {
op: self.op.to_string(), op: self.op.to_string(),
comment: comment_view comment: comment_view,
} })
)
} }
} }
@ -265,9 +235,7 @@ impl Perform<CommentResponse> for Oper<CreateCommentLike> {
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
let user_id = claims.id; let user_id = claims.id;
@ -275,19 +243,19 @@ impl Perform<CommentResponse> for Oper<CreateCommentLike> {
// 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)?;
if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() { if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() {
return Err(APIError::err(&self.op, "community_ban"))? return Err(APIError::err(&self.op, "community_ban"))?;
} }
// Check for a site ban // Check for a site ban
if UserView::read(&conn, user_id)?.banned { if UserView::read(&conn, user_id)?.banned {
return Err(APIError::err(&self.op, "site_ban"))? return Err(APIError::err(&self.op, "site_ban"))?;
} }
let like_form = CommentLikeForm { let like_form = CommentLikeForm {
comment_id: data.comment_id, comment_id: data.comment_id,
post_id: data.post_id, post_id: data.post_id,
user_id: user_id, user_id: user_id,
score: data.score score: data.score,
}; };
// Remove any likes first // Remove any likes first
@ -298,20 +266,16 @@ impl Perform<CommentResponse> for Oper<CreateCommentLike> {
if do_add { if do_add {
let _inserted_like = match CommentLike::like(&conn, &like_form) { let _inserted_like = match CommentLike::like(&conn, &like_form) {
Ok(like) => like, Ok(like) => like,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_like_comment"))?,
return Err(APIError::err(&self.op, "couldnt_like_comment"))?
}
}; };
} }
// Have to refetch the comment to get the current state // Have to refetch the comment to get the current state
let liked_comment = CommentView::read(&conn, data.comment_id, Some(user_id))?; let liked_comment = CommentView::read(&conn, data.comment_id, Some(user_id))?;
Ok( Ok(CommentResponse {
CommentResponse {
op: self.op.to_string(), op: self.op.to_string(),
comment: liked_comment comment: liked_comment,
} })
)
} }
} }

View file

@ -5,7 +5,7 @@ use std::str::FromStr;
pub struct GetCommunity { pub struct GetCommunity {
id: Option<i32>, id: Option<i32>,
name: Option<String>, name: Option<String>,
auth: Option<String> auth: Option<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -16,7 +16,6 @@ pub struct GetCommunityResponse {
admins: Vec<UserView>, admins: Vec<UserView>,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct CreateCommunity { pub struct CreateCommunity {
name: String, name: String,
@ -24,13 +23,13 @@ pub struct CreateCommunity {
description: Option<String>, description: Option<String>,
category_id: i32, category_id: i32,
nsfw: bool, nsfw: bool,
auth: String auth: String,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
pub struct CommunityResponse { pub struct CommunityResponse {
op: String, op: String,
pub community: CommunityView pub community: CommunityView,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -38,13 +37,13 @@ pub struct ListCommunities {
sort: String, sort: String,
page: Option<i64>, page: Option<i64>,
limit: Option<i64>, limit: Option<i64>,
auth: Option<String> auth: Option<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct ListCommunitiesResponse { pub struct ListCommunitiesResponse {
op: String, op: String,
communities: Vec<CommunityView> communities: Vec<CommunityView>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
@ -54,7 +53,7 @@ pub struct BanFromCommunity {
ban: bool, ban: bool,
reason: Option<String>, reason: Option<String>,
expires: Option<i64>, expires: Option<i64>,
auth: String auth: String,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -69,7 +68,7 @@ pub struct AddModToCommunity {
pub community_id: i32, pub community_id: i32,
user_id: i32, user_id: i32,
added: bool, added: bool,
auth: String auth: String,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -90,32 +89,32 @@ pub struct EditCommunity {
nsfw: bool, nsfw: bool,
reason: Option<String>, reason: Option<String>,
expires: Option<i64>, expires: Option<i64>,
auth: String auth: String,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct FollowCommunity { pub struct FollowCommunity {
community_id: i32, community_id: i32,
follow: bool, follow: bool,
auth: String auth: String,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct GetFollowedCommunities { pub struct GetFollowedCommunities {
auth: String auth: String,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct GetFollowedCommunitiesResponse { pub struct GetFollowedCommunitiesResponse {
op: String, op: String,
communities: Vec<CommunityFollowerView> communities: Vec<CommunityFollowerView>,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct TransferCommunity { pub struct TransferCommunity {
community_id: i32, community_id: i32,
user_id: i32, user_id: i32,
auth: String auth: String,
} }
impl Perform<GetCommunityResponse> for Oper<GetCommunity> { impl Perform<GetCommunityResponse> for Oper<GetCommunity> {
@ -124,35 +123,31 @@ impl Perform<GetCommunityResponse> for Oper<GetCommunity> {
let conn = establish_connection(); let conn = establish_connection();
let user_id: Option<i32> = match &data.auth { let user_id: Option<i32> = match &data.auth {
Some(auth) => { Some(auth) => match Claims::decode(&auth) {
match Claims::decode(&auth) {
Ok(claims) => { Ok(claims) => {
let user_id = claims.claims.id; let user_id = claims.claims.id;
Some(user_id) Some(user_id)
} }
Err(_e) => None Err(_e) => None,
} },
} None => None,
None => None
}; };
let community_id = match data.id { let community_id = match data.id {
Some(id) => id, Some(id) => id,
None => Community::read_from_name(&conn, data.name.to_owned().unwrap_or("main".to_string()))?.id None => {
Community::read_from_name(&conn, data.name.to_owned().unwrap_or("main".to_string()))?.id
}
}; };
let community_view = match CommunityView::read(&conn, community_id, user_id) { let community_view = match CommunityView::read(&conn, community_id, user_id) {
Ok(community) => community, Ok(community) => community,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_community"))?,
return Err(APIError::err(&self.op, "couldnt_find_community"))?
}
}; };
let moderators = match CommunityModeratorView::for_community(&conn, community_id) { let moderators = match CommunityModeratorView::for_community(&conn, community_id) {
Ok(moderators) => moderators, Ok(moderators) => moderators,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_community"))?,
return Err(APIError::err(&self.op, "couldnt_find_community"))?
}
}; };
let site_creator_id = Site::read(&conn, 1)?.creator_id; let site_creator_id = Site::read(&conn, 1)?.creator_id;
@ -162,14 +157,12 @@ impl Perform<GetCommunityResponse> for Oper<GetCommunity> {
admins.insert(0, creator_user); admins.insert(0, creator_user);
// Return the jwt // Return the jwt
Ok( Ok(GetCommunityResponse {
GetCommunityResponse {
op: self.op.to_string(), op: self.op.to_string(),
community: community_view, community: community_view,
moderators: moderators, moderators: moderators,
admins: admins, admins: admins,
} })
)
} }
} }
@ -180,22 +173,21 @@ impl Perform<CommunityResponse> for Oper<CreateCommunity> {
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
if has_slurs(&data.name) || if has_slurs(&data.name)
has_slurs(&data.title) || || has_slurs(&data.title)
(data.description.is_some() && has_slurs(&data.description.to_owned().unwrap())) { || (data.description.is_some() && has_slurs(&data.description.to_owned().unwrap()))
return Err(APIError::err(&self.op, "no_slurs"))? {
return Err(APIError::err(&self.op, "no_slurs"))?;
} }
let user_id = claims.id; let user_id = claims.id;
// Check for a site ban // Check for a site ban
if UserView::read(&conn, user_id)?.banned { if UserView::read(&conn, user_id)?.banned {
return Err(APIError::err(&self.op, "site_ban"))? return Err(APIError::err(&self.op, "site_ban"))?;
} }
// When you create a community, make sure the user becomes a moderator and a follower // When you create a community, make sure the user becomes a moderator and a follower
@ -213,43 +205,42 @@ impl Perform<CommunityResponse> for Oper<CreateCommunity> {
let inserted_community = match Community::create(&conn, &community_form) { let inserted_community = match Community::create(&conn, &community_form) {
Ok(community) => community, Ok(community) => community,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "community_already_exists"))?,
return Err(APIError::err(&self.op, "community_already_exists"))?
}
}; };
let community_moderator_form = CommunityModeratorForm { let community_moderator_form = CommunityModeratorForm {
community_id: inserted_community.id, community_id: inserted_community.id,
user_id: user_id user_id: user_id,
}; };
let _inserted_community_moderator = match CommunityModerator::join(&conn, &community_moderator_form) { let _inserted_community_moderator =
match CommunityModerator::join(&conn, &community_moderator_form) {
Ok(user) => user, Ok(user) => user,
Err(_e) => { Err(_e) => {
return Err(APIError::err(&self.op, "community_moderator_already_exists"))? return Err(APIError::err(
&self.op,
"community_moderator_already_exists",
))?
} }
}; };
let community_follower_form = CommunityFollowerForm { let community_follower_form = CommunityFollowerForm {
community_id: inserted_community.id, community_id: inserted_community.id,
user_id: user_id user_id: user_id,
}; };
let _inserted_community_follower = match CommunityFollower::follow(&conn, &community_follower_form) { let _inserted_community_follower =
match CommunityFollower::follow(&conn, &community_follower_form) {
Ok(user) => user, Ok(user) => user,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "community_follower_already_exists"))?,
return Err(APIError::err(&self.op, "community_follower_already_exists"))?
}
}; };
let community_view = CommunityView::read(&conn, inserted_community.id, Some(user_id))?; let community_view = CommunityView::read(&conn, inserted_community.id, Some(user_id))?;
Ok( Ok(CommunityResponse {
CommunityResponse {
op: self.op.to_string(), op: self.op.to_string(),
community: community_view community: community_view,
} })
)
} }
} }
@ -258,43 +249,34 @@ impl Perform<CommunityResponse> for Oper<EditCommunity> {
let data: &EditCommunity = &self.data; let data: &EditCommunity = &self.data;
if has_slurs(&data.name) || has_slurs(&data.title) { if has_slurs(&data.name) || has_slurs(&data.title) {
return Err(APIError::err(&self.op, "no_slurs"))? return Err(APIError::err(&self.op, "no_slurs"))?;
} }
let conn = establish_connection(); let conn = establish_connection();
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
let user_id = claims.id; let user_id = claims.id;
// Check for a site ban // Check for a site ban
if UserView::read(&conn, user_id)?.banned { if UserView::read(&conn, user_id)?.banned {
return Err(APIError::err(&self.op, "site_ban"))? return Err(APIError::err(&self.op, "site_ban"))?;
} }
// Verify its a mod // Verify its a mod
let mut editors: Vec<i32> = Vec::new(); let mut editors: Vec<i32> = Vec::new();
editors.append( editors.append(
&mut CommunityModeratorView::for_community(&conn, data.edit_id) &mut CommunityModeratorView::for_community(&conn, data.edit_id)?
?
.into_iter() .into_iter()
.map(|m| m.user_id) .map(|m| m.user_id)
.collect() .collect(),
);
editors.append(
&mut UserView::admins(&conn)
?
.into_iter()
.map(|a| a.id)
.collect()
); );
editors.append(&mut UserView::admins(&conn)?.into_iter().map(|a| a.id).collect());
if !editors.contains(&user_id) { if !editors.contains(&user_id) {
return Err(APIError::err(&self.op, "no_community_edit_allowed"))? return Err(APIError::err(&self.op, "no_community_edit_allowed"))?;
} }
let community_form = CommunityForm { let community_form = CommunityForm {
@ -306,40 +288,36 @@ impl Perform<CommunityResponse> for Oper<EditCommunity> {
removed: data.removed.to_owned(), removed: data.removed.to_owned(),
deleted: data.deleted.to_owned(), deleted: data.deleted.to_owned(),
nsfw: data.nsfw, nsfw: data.nsfw,
updated: Some(naive_now()) updated: Some(naive_now()),
}; };
let _updated_community = match Community::update(&conn, data.edit_id, &community_form) { let _updated_community = match Community::update(&conn, data.edit_id, &community_form) {
Ok(community) => community, Ok(community) => community,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_community"))?,
return Err(APIError::err(&self.op, "couldnt_update_community"))?
}
}; };
// Mod tables // Mod tables
if let Some(removed) = data.removed.to_owned() { if let Some(removed) = data.removed.to_owned() {
let expires = match data.expires { let expires = match data.expires {
Some(time) => Some(naive_from_unix(time)), Some(time) => Some(naive_from_unix(time)),
None => None None => None,
}; };
let form = ModRemoveCommunityForm { let form = ModRemoveCommunityForm {
mod_user_id: user_id, mod_user_id: user_id,
community_id: data.edit_id, community_id: data.edit_id,
removed: Some(removed), removed: Some(removed),
reason: data.reason.to_owned(), reason: data.reason.to_owned(),
expires: expires expires: expires,
}; };
ModRemoveCommunity::create(&conn, &form)?; ModRemoveCommunity::create(&conn, &form)?;
} }
let community_view = CommunityView::read(&conn, data.edit_id, Some(user_id))?; let community_view = CommunityView::read(&conn, data.edit_id, Some(user_id))?;
Ok( Ok(CommunityResponse {
CommunityResponse {
op: self.op.to_string(), op: self.op.to_string(),
community: community_view community: community_view,
} })
)
} }
} }
@ -349,49 +327,37 @@ impl Perform<ListCommunitiesResponse> for Oper<ListCommunities> {
let conn = establish_connection(); let conn = establish_connection();
let user_claims: Option<Claims> = match &data.auth { let user_claims: Option<Claims> = match &data.auth {
Some(auth) => { Some(auth) => match Claims::decode(&auth) {
match Claims::decode(&auth) { Ok(claims) => Some(claims.claims),
Ok(claims) => { Err(_e) => None,
Some(claims.claims) },
} None => None,
Err(_e) => None
}
}
None => None
}; };
let user_id = match &user_claims { let user_id = match &user_claims {
Some(claims) => Some(claims.id), Some(claims) => Some(claims.id),
None => None None => None,
}; };
let show_nsfw = match &user_claims { let show_nsfw = match &user_claims {
Some(claims) => claims.show_nsfw, Some(claims) => claims.show_nsfw,
None => false None => false,
}; };
let sort = SortType::from_str(&data.sort)?; let sort = SortType::from_str(&data.sort)?;
let communities: Vec<CommunityView> = CommunityView::list( let communities: Vec<CommunityView> = CommunityView::list(
&conn, &conn, &sort, user_id, show_nsfw, None, data.page, data.limit,
&sort, )?;
user_id,
show_nsfw,
None,
data.page,
data.limit)?;
// Return the jwt // Return the jwt
Ok( Ok(ListCommunitiesResponse {
ListCommunitiesResponse {
op: self.op.to_string(), op: self.op.to_string(),
communities: communities communities: communities,
} })
)
} }
} }
impl Perform<CommunityResponse> for Oper<FollowCommunity> { impl Perform<CommunityResponse> for Oper<FollowCommunity> {
fn perform(&self) -> Result<CommunityResponse, Error> { fn perform(&self) -> Result<CommunityResponse, Error> {
let data: &FollowCommunity = &self.data; let data: &FollowCommunity = &self.data;
@ -399,46 +365,37 @@ impl Perform<CommunityResponse> for Oper<FollowCommunity> {
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
let user_id = claims.id; let user_id = claims.id;
let community_follower_form = CommunityFollowerForm { let community_follower_form = CommunityFollowerForm {
community_id: data.community_id, community_id: data.community_id,
user_id: user_id user_id: user_id,
}; };
if data.follow { if data.follow {
match CommunityFollower::follow(&conn, &community_follower_form) { match CommunityFollower::follow(&conn, &community_follower_form) {
Ok(user) => user, Ok(user) => user,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "community_follower_already_exists"))?,
return Err(APIError::err(&self.op, "community_follower_already_exists"))?
}
}; };
} else { } else {
match CommunityFollower::ignore(&conn, &community_follower_form) { match CommunityFollower::ignore(&conn, &community_follower_form) {
Ok(user) => user, Ok(user) => user,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "community_follower_already_exists"))?,
return Err(APIError::err(&self.op, "community_follower_already_exists"))?
}
}; };
} }
let community_view = CommunityView::read(&conn, data.community_id, Some(user_id))?; let community_view = CommunityView::read(&conn, data.community_id, Some(user_id))?;
Ok( Ok(CommunityResponse {
CommunityResponse {
op: self.op.to_string(), op: self.op.to_string(),
community: community_view community: community_view,
} })
)
} }
} }
impl Perform<GetFollowedCommunitiesResponse> for Oper<GetFollowedCommunities> { impl Perform<GetFollowedCommunitiesResponse> for Oper<GetFollowedCommunities> {
fn perform(&self) -> Result<GetFollowedCommunitiesResponse, Error> { fn perform(&self) -> Result<GetFollowedCommunitiesResponse, Error> {
let data: &GetFollowedCommunities = &self.data; let data: &GetFollowedCommunities = &self.data;
@ -446,31 +403,25 @@ impl Perform<GetFollowedCommunitiesResponse> for Oper<GetFollowedCommunities> {
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
let user_id = claims.id; let user_id = claims.id;
let communities: Vec<CommunityFollowerView> = match CommunityFollowerView::for_user(&conn, user_id) { let communities: Vec<CommunityFollowerView> =
match CommunityFollowerView::for_user(&conn, user_id) {
Ok(communities) => communities, Ok(communities) => communities,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "system_err_login"))?,
return Err(APIError::err(&self.op, "system_err_login"))?
}
}; };
// Return the jwt // Return the jwt
Ok( Ok(GetFollowedCommunitiesResponse {
GetFollowedCommunitiesResponse {
op: self.op.to_string(), op: self.op.to_string(),
communities: communities communities: communities,
} })
)
} }
} }
impl Perform<BanFromCommunityResponse> for Oper<BanFromCommunity> { impl Perform<BanFromCommunityResponse> for Oper<BanFromCommunity> {
fn perform(&self) -> Result<BanFromCommunityResponse, Error> { fn perform(&self) -> Result<BanFromCommunityResponse, Error> {
let data: &BanFromCommunity = &self.data; let data: &BanFromCommunity = &self.data;
@ -478,9 +429,7 @@ impl Perform<BanFromCommunityResponse> for Oper<BanFromCommunity> {
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
let user_id = claims.id; let user_id = claims.id;
@ -493,23 +442,19 @@ impl Perform<BanFromCommunityResponse> for Oper<BanFromCommunity> {
if data.ban { if data.ban {
match CommunityUserBan::ban(&conn, &community_user_ban_form) { match CommunityUserBan::ban(&conn, &community_user_ban_form) {
Ok(user) => user, Ok(user) => user,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "community_user_already_banned"))?,
return Err(APIError::err(&self.op, "community_user_already_banned"))?
}
}; };
} else { } else {
match CommunityUserBan::unban(&conn, &community_user_ban_form) { match CommunityUserBan::unban(&conn, &community_user_ban_form) {
Ok(user) => user, Ok(user) => user,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "community_user_already_banned"))?,
return Err(APIError::err(&self.op, "community_user_already_banned"))?
}
}; };
} }
// Mod tables // Mod tables
let expires = match data.expires { let expires = match data.expires {
Some(time) => Some(naive_from_unix(time)), Some(time) => Some(naive_from_unix(time)),
None => None None => None,
}; };
let form = ModBanFromCommunityForm { let form = ModBanFromCommunityForm {
@ -524,13 +469,11 @@ impl Perform<BanFromCommunityResponse> for Oper<BanFromCommunity> {
let user_view = UserView::read(&conn, data.user_id)?; let user_view = UserView::read(&conn, data.user_id)?;
Ok( Ok(BanFromCommunityResponse {
BanFromCommunityResponse {
op: self.op.to_string(), op: self.op.to_string(),
user: user_view, user: user_view,
banned: data.ban banned: data.ban,
} })
)
} }
} }
@ -541,30 +484,34 @@ impl Perform<AddModToCommunityResponse> for Oper<AddModToCommunity> {
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
let user_id = claims.id; let user_id = claims.id;
let community_moderator_form = CommunityModeratorForm { let community_moderator_form = CommunityModeratorForm {
community_id: data.community_id, community_id: data.community_id,
user_id: data.user_id user_id: data.user_id,
}; };
if data.added { if data.added {
match CommunityModerator::join(&conn, &community_moderator_form) { match CommunityModerator::join(&conn, &community_moderator_form) {
Ok(user) => user, Ok(user) => user,
Err(_e) => { Err(_e) => {
return Err(APIError::err(&self.op, "community_moderator_already_exists"))? return Err(APIError::err(
&self.op,
"community_moderator_already_exists",
))?
} }
}; };
} else { } else {
match CommunityModerator::leave(&conn, &community_moderator_form) { match CommunityModerator::leave(&conn, &community_moderator_form) {
Ok(user) => user, Ok(user) => user,
Err(_e) => { Err(_e) => {
return Err(APIError::err(&self.op, "community_moderator_already_exists"))? return Err(APIError::err(
&self.op,
"community_moderator_already_exists",
))?
} }
}; };
} }
@ -580,12 +527,10 @@ impl Perform<AddModToCommunityResponse> for Oper<AddModToCommunity> {
let moderators = CommunityModeratorView::for_community(&conn, data.community_id)?; let moderators = CommunityModeratorView::for_community(&conn, data.community_id)?;
Ok( Ok(AddModToCommunityResponse {
AddModToCommunityResponse {
op: self.op.to_string(), op: self.op.to_string(),
moderators: moderators, moderators: moderators,
} })
)
} }
} }
@ -596,9 +541,7 @@ impl Perform<GetCommunityResponse> for Oper<TransferCommunity> {
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
let user_id = claims.id; let user_id = claims.id;
@ -611,10 +554,15 @@ impl Perform<GetCommunityResponse> for Oper<TransferCommunity> {
let creator_user = admins.remove(creator_index); let creator_user = admins.remove(creator_index);
admins.insert(0, creator_user); admins.insert(0, creator_user);
// Make sure user is the creator, or an admin // Make sure user is the creator, or an admin
if user_id != read_community.creator_id && !admins.iter().map(|a| a.id).collect::<Vec<i32>>().contains(&user_id) { if user_id != read_community.creator_id
return Err(APIError::err(&self.op, "not_an_admin"))? && !admins
.iter()
.map(|a| a.id)
.collect::<Vec<i32>>()
.contains(&user_id)
{
return Err(APIError::err(&self.op, "not_an_admin"))?;
} }
let community_form = CommunityForm { let community_form = CommunityForm {
@ -626,35 +574,39 @@ impl Perform<GetCommunityResponse> for Oper<TransferCommunity> {
removed: None, removed: None,
deleted: None, deleted: None,
nsfw: read_community.nsfw, nsfw: read_community.nsfw,
updated: Some(naive_now()) updated: Some(naive_now()),
}; };
let _updated_community = match Community::update(&conn, data.community_id, &community_form) { let _updated_community = match Community::update(&conn, data.community_id, &community_form) {
Ok(community) => community, Ok(community) => community,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_community"))?,
return Err(APIError::err(&self.op, "couldnt_update_community"))?
}
}; };
// You also have to re-do the community_moderator table, reordering it. // You also have to re-do the community_moderator table, reordering it.
let mut community_mods = CommunityModeratorView::for_community(&conn, data.community_id)?; let mut community_mods = CommunityModeratorView::for_community(&conn, data.community_id)?;
let creator_index = community_mods.iter().position(|r| r.user_id == data.user_id).unwrap(); let creator_index = community_mods
.iter()
.position(|r| r.user_id == data.user_id)
.unwrap();
let creator_user = community_mods.remove(creator_index); let creator_user = community_mods.remove(creator_index);
community_mods.insert(0, creator_user); community_mods.insert(0, creator_user);
CommunityModerator::delete_for_community(&conn, data.community_id)?; CommunityModerator::delete_for_community(&conn, data.community_id)?;
for cmod in &community_mods { for cmod in &community_mods {
let community_moderator_form = CommunityModeratorForm { let community_moderator_form = CommunityModeratorForm {
community_id: cmod.community_id, community_id: cmod.community_id,
user_id: cmod.user_id user_id: cmod.user_id,
}; };
let _inserted_community_moderator = match CommunityModerator::join(&conn, &community_moderator_form) { let _inserted_community_moderator =
match CommunityModerator::join(&conn, &community_moderator_form) {
Ok(user) => user, Ok(user) => user,
Err(_e) => { Err(_e) => {
return Err(APIError::err(&self.op, "community_moderator_already_exists"))? return Err(APIError::err(
&self.op,
"community_moderator_already_exists",
))?
} }
}; };
} }
@ -670,27 +622,20 @@ impl Perform<GetCommunityResponse> for Oper<TransferCommunity> {
let community_view = match CommunityView::read(&conn, data.community_id, Some(user_id)) { let community_view = match CommunityView::read(&conn, data.community_id, Some(user_id)) {
Ok(community) => community, Ok(community) => community,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_community"))?,
return Err(APIError::err(&self.op, "couldnt_find_community"))?
}
}; };
let moderators = match CommunityModeratorView::for_community(&conn, data.community_id) { let moderators = match CommunityModeratorView::for_community(&conn, data.community_id) {
Ok(moderators) => moderators, Ok(moderators) => moderators,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_community"))?,
return Err(APIError::err(&self.op, "couldnt_find_community"))?
}
}; };
// Return the jwt // Return the jwt
Ok( Ok(GetCommunityResponse {
GetCommunityResponse {
op: self.op.to_string(), op: self.op.to_string(),
community: community_view, community: community_view,
moderators: moderators, moderators: moderators,
admins: admins, admins: admins,
} })
)
} }
} }

View file

@ -1,28 +1,61 @@
use serde::{Deserialize, Serialize};
use failure::Error;
use crate::db::*;
use crate::db::community::*;
use crate::db::user::*;
use crate::db::post::*;
use crate::db::comment::*;
use crate::db::post_view::*;
use crate::db::comment_view::*;
use crate::db::category::*; use crate::db::category::*;
use crate::db::comment::*;
use crate::db::comment_view::*;
use crate::db::community::*;
use crate::db::community_view::*; use crate::db::community_view::*;
use crate::db::user_view::*;
use crate::db::moderator_views::*;
use crate::db::moderator::*; use crate::db::moderator::*;
use crate::{has_slurs, remove_slurs, Settings, naive_now, naive_from_unix}; use crate::db::moderator_views::*;
use crate::db::post::*;
use crate::db::post_view::*;
use crate::db::user::*;
use crate::db::user_view::*;
use crate::db::*;
use crate::{has_slurs, naive_from_unix, naive_now, remove_slurs, Settings};
use failure::Error;
use serde::{Deserialize, Serialize};
pub mod user; pub mod comment;
pub mod community; pub mod community;
pub mod post; pub mod post;
pub mod comment;
pub mod site; pub mod site;
pub mod user;
#[derive(EnumString, ToString, Debug)] #[derive(EnumString, ToString, Debug)]
pub enum UserOperation { pub enum UserOperation {
Login, Register, CreateCommunity, CreatePost, ListCommunities, ListCategories, GetPost, GetCommunity, CreateComment, EditComment, SaveComment, CreateCommentLike, GetPosts, CreatePostLike, EditPost, SavePost, EditCommunity, FollowCommunity, GetFollowedCommunities, GetUserDetails, GetReplies, GetModlog, BanFromCommunity, AddModToCommunity, CreateSite, EditSite, GetSite, AddAdmin, BanUser, Search, MarkAllAsRead, SaveUserSettings, TransferCommunity, TransferSite Login,
Register,
CreateCommunity,
CreatePost,
ListCommunities,
ListCategories,
GetPost,
GetCommunity,
CreateComment,
EditComment,
SaveComment,
CreateCommentLike,
GetPosts,
CreatePostLike,
EditPost,
SavePost,
EditCommunity,
FollowCommunity,
GetFollowedCommunities,
GetUserDetails,
GetReplies,
GetModlog,
BanFromCommunity,
AddModToCommunity,
CreateSite,
EditSite,
GetSite,
AddAdmin,
BanUser,
Search,
MarkAllAsRead,
SaveUserSettings,
TransferCommunity,
TransferSite,
} }
#[derive(Fail, Debug)] #[derive(Fail, Debug)]
@ -43,18 +76,17 @@ impl APIError {
pub struct Oper<T> { pub struct Oper<T> {
op: UserOperation, op: UserOperation,
data: T data: T,
} }
impl<T> Oper<T> { impl<T> Oper<T> {
pub fn new(op: UserOperation, data: T) -> Oper<T> { pub fn new(op: UserOperation, data: T) -> Oper<T> {
Oper { Oper { op: op, data: data }
op: op,
data: data
}
} }
} }
pub trait Perform<T> { pub trait Perform<T> {
fn perform(&self) -> Result<T, Error> where T: Sized; fn perform(&self) -> Result<T, Error>
where
T: Sized;
} }

View file

@ -8,20 +8,19 @@ pub struct CreatePost {
body: Option<String>, body: Option<String>,
nsfw: bool, nsfw: bool,
community_id: i32, community_id: i32,
auth: String auth: String,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
pub struct PostResponse { pub struct PostResponse {
op: String, op: String,
pub post: PostView pub post: PostView,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct GetPost { pub struct GetPost {
pub id: i32, pub id: i32,
auth: Option<String> auth: Option<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -41,7 +40,7 @@ pub struct GetPosts {
page: Option<i64>, page: Option<i64>,
limit: Option<i64>, limit: Option<i64>,
community_id: Option<i32>, community_id: Option<i32>,
auth: Option<String> auth: Option<String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -54,16 +53,15 @@ pub struct GetPostsResponse {
pub struct CreatePostLike { pub struct CreatePostLike {
post_id: i32, post_id: i32,
score: i16, score: i16,
auth: String auth: String,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct CreatePostLikeResponse { pub struct CreatePostLikeResponse {
op: String, op: String,
post: PostView post: PostView,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct EditPost { pub struct EditPost {
pub edit_id: i32, pub edit_id: i32,
@ -77,14 +75,14 @@ pub struct EditPost {
nsfw: bool, nsfw: bool,
locked: Option<bool>, locked: Option<bool>,
reason: Option<String>, reason: Option<String>,
auth: String auth: String,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct SavePost { pub struct SavePost {
post_id: i32, post_id: i32,
save: bool, save: bool,
auth: String auth: String,
} }
impl Perform<PostResponse> for Oper<CreatePost> { impl Perform<PostResponse> for Oper<CreatePost> {
@ -92,29 +90,25 @@ impl Perform<PostResponse> for Oper<CreatePost> {
let data: &CreatePost = &self.data; let data: &CreatePost = &self.data;
let conn = establish_connection(); let conn = establish_connection();
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
if has_slurs(&data.name) || if has_slurs(&data.name) || (data.body.is_some() && has_slurs(&data.body.to_owned().unwrap())) {
(data.body.is_some() && has_slurs(&data.body.to_owned().unwrap())) { return Err(APIError::err(&self.op, "no_slurs"))?;
return Err(APIError::err(&self.op, "no_slurs"))?
} }
let user_id = claims.id; let user_id = claims.id;
// Check for a community ban // Check for a community ban
if CommunityUserBanView::get(&conn, user_id, data.community_id).is_ok() { if CommunityUserBanView::get(&conn, user_id, data.community_id).is_ok() {
return Err(APIError::err(&self.op, "community_ban"))? return Err(APIError::err(&self.op, "community_ban"))?;
} }
// Check for a site ban // Check for a site ban
if UserView::read(&conn, user_id)?.banned { if UserView::read(&conn, user_id)?.banned {
return Err(APIError::err(&self.op, "site_ban"))? return Err(APIError::err(&self.op, "site_ban"))?;
} }
let post_form = PostForm { let post_form = PostForm {
@ -127,45 +121,37 @@ impl Perform<PostResponse> for Oper<CreatePost> {
deleted: None, deleted: None,
nsfw: data.nsfw, nsfw: data.nsfw,
locked: None, locked: None,
updated: None updated: None,
}; };
let inserted_post = match Post::create(&conn, &post_form) { let inserted_post = match Post::create(&conn, &post_form) {
Ok(post) => post, Ok(post) => post,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_create_post"))?,
return Err(APIError::err(&self.op, "couldnt_create_post"))?
}
}; };
// They like their own post by default // They like their own post by default
let like_form = PostLikeForm { let like_form = PostLikeForm {
post_id: inserted_post.id, post_id: inserted_post.id,
user_id: user_id, user_id: user_id,
score: 1 score: 1,
}; };
// Only add the like if the score isnt 0 // Only add the like if the score isnt 0
let _inserted_like = match PostLike::like(&conn, &like_form) { let _inserted_like = match PostLike::like(&conn, &like_form) {
Ok(like) => like, Ok(like) => like,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_like_post"))?,
return Err(APIError::err(&self.op, "couldnt_like_post"))?
}
}; };
// Refetch the view // Refetch the view
let post_view = match PostView::read(&conn, inserted_post.id, Some(user_id)) { let post_view = match PostView::read(&conn, inserted_post.id, Some(user_id)) {
Ok(post) => post, Ok(post) => post,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_post"))?,
return Err(APIError::err(&self.op, "couldnt_find_post"))?
}
}; };
Ok( Ok(PostResponse {
PostResponse {
op: self.op.to_string(), op: self.op.to_string(),
post: post_view post: post_view,
} })
)
} }
} }
@ -175,26 +161,32 @@ impl Perform<GetPostResponse> for Oper<GetPost> {
let conn = establish_connection(); let conn = establish_connection();
let user_id: Option<i32> = match &data.auth { let user_id: Option<i32> = match &data.auth {
Some(auth) => { Some(auth) => match Claims::decode(&auth) {
match Claims::decode(&auth) {
Ok(claims) => { Ok(claims) => {
let user_id = claims.claims.id; let user_id = claims.claims.id;
Some(user_id) Some(user_id)
} }
Err(_e) => None Err(_e) => None,
} },
} None => None,
None => None
}; };
let post_view = match PostView::read(&conn, data.id, user_id) { let post_view = match PostView::read(&conn, data.id, user_id) {
Ok(post) => post, Ok(post) => post,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_post"))?,
return Err(APIError::err(&self.op, "couldnt_find_post"))?
}
}; };
let comments = CommentView::list(&conn, &SortType::New, Some(data.id), None, None, user_id, false, None, Some(9999))?; let comments = CommentView::list(
&conn,
&SortType::New,
Some(data.id),
None,
None,
user_id,
false,
None,
Some(9999),
)?;
let community = CommunityView::read(&conn, post_view.community_id, user_id)?; let community = CommunityView::read(&conn, post_view.community_id, user_id)?;
@ -207,45 +199,38 @@ impl Perform<GetPostResponse> for Oper<GetPost> {
admins.insert(0, creator_user); admins.insert(0, creator_user);
// Return the jwt // Return the jwt
Ok( Ok(GetPostResponse {
GetPostResponse {
op: self.op.to_string(), op: self.op.to_string(),
post: post_view, post: post_view,
comments: comments, comments: comments,
community: community, community: community,
moderators: moderators, moderators: moderators,
admins: admins, admins: admins,
} })
)
} }
} }
impl Perform<GetPostsResponse> for Oper<GetPosts> { impl Perform<GetPostsResponse> for Oper<GetPosts> {
fn perform(&self) -> Result<GetPostsResponse, Error> { fn perform(&self) -> Result<GetPostsResponse, Error> {
let data: &GetPosts = &self.data; let data: &GetPosts = &self.data;
let conn = establish_connection(); let conn = establish_connection();
let user_claims: Option<Claims> = match &data.auth { let user_claims: Option<Claims> = match &data.auth {
Some(auth) => { Some(auth) => match Claims::decode(&auth) {
match Claims::decode(&auth) { Ok(claims) => Some(claims.claims),
Ok(claims) => { Err(_e) => None,
Some(claims.claims) },
} None => None,
Err(_e) => None
}
}
None => None
}; };
let user_id = match &user_claims { let user_id = match &user_claims {
Some(claims) => Some(claims.id), Some(claims) => Some(claims.id),
None => None None => None,
}; };
let show_nsfw = match &user_claims { let show_nsfw = match &user_claims {
Some(claims) => claims.show_nsfw, Some(claims) => claims.show_nsfw,
None => false None => false,
}; };
let type_ = PostListingType::from_str(&data.type_)?; let type_ = PostListingType::from_str(&data.type_)?;
@ -264,19 +249,16 @@ impl Perform<GetPostsResponse> for Oper<GetPosts> {
false, false,
false, false,
data.page, data.page,
data.limit) { data.limit,
) {
Ok(posts) => posts, Ok(posts) => posts,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_get_posts"))?,
return Err(APIError::err(&self.op, "couldnt_get_posts"))?
}
}; };
Ok( Ok(GetPostsResponse {
GetPostsResponse {
op: self.op.to_string(), op: self.op.to_string(),
posts: posts posts: posts,
} })
)
} }
} }
@ -287,9 +269,7 @@ impl Perform<CreatePostLikeResponse> for Oper<CreatePostLike> {
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
let user_id = claims.id; let user_id = claims.id;
@ -297,18 +277,18 @@ impl Perform<CreatePostLikeResponse> for Oper<CreatePostLike> {
// 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)?;
if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() { if CommunityUserBanView::get(&conn, user_id, post.community_id).is_ok() {
return Err(APIError::err(&self.op, "community_ban"))? return Err(APIError::err(&self.op, "community_ban"))?;
} }
// Check for a site ban // Check for a site ban
if UserView::read(&conn, user_id)?.banned { if UserView::read(&conn, user_id)?.banned {
return Err(APIError::err(&self.op, "site_ban"))? return Err(APIError::err(&self.op, "site_ban"))?;
} }
let like_form = PostLikeForm { let like_form = PostLikeForm {
post_id: data.post_id, post_id: data.post_id,
user_id: user_id, user_id: user_id,
score: data.score score: data.score,
}; };
// Remove any likes first // Remove any likes first
@ -319,44 +299,35 @@ impl Perform<CreatePostLikeResponse> for Oper<CreatePostLike> {
if do_add { if do_add {
let _inserted_like = match PostLike::like(&conn, &like_form) { let _inserted_like = match PostLike::like(&conn, &like_form) {
Ok(like) => like, Ok(like) => like,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_like_post"))?,
return Err(APIError::err(&self.op, "couldnt_like_post"))?
}
}; };
} }
let post_view = match PostView::read(&conn, data.post_id, Some(user_id)) { let post_view = match PostView::read(&conn, data.post_id, Some(user_id)) {
Ok(post) => post, Ok(post) => post,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_post"))?,
return Err(APIError::err(&self.op, "couldnt_find_post"))?
}
}; };
// just output the score // just output the score
Ok( Ok(CreatePostLikeResponse {
CreatePostLikeResponse {
op: self.op.to_string(), op: self.op.to_string(),
post: post_view post: post_view,
} })
)
} }
} }
impl Perform<PostResponse> for Oper<EditPost> { impl Perform<PostResponse> for Oper<EditPost> {
fn perform(&self) -> Result<PostResponse, Error> { fn perform(&self) -> Result<PostResponse, Error> {
let data: &EditPost = &self.data; let data: &EditPost = &self.data;
if has_slurs(&data.name) || if has_slurs(&data.name) || (data.body.is_some() && has_slurs(&data.body.to_owned().unwrap())) {
(data.body.is_some() && has_slurs(&data.body.to_owned().unwrap())) { return Err(APIError::err(&self.op, "no_slurs"))?;
return Err(APIError::err(&self.op, "no_slurs"))?
} }
let conn = establish_connection(); let conn = establish_connection();
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
let user_id = claims.id; let user_id = claims.id;
@ -364,31 +335,24 @@ impl Perform<PostResponse> for Oper<EditPost> {
// Verify its the creator or a mod or admin // Verify its the creator or a mod or admin
let mut editors: Vec<i32> = vec![data.creator_id]; let mut editors: Vec<i32> = vec![data.creator_id];
editors.append( editors.append(
&mut CommunityModeratorView::for_community(&conn, data.community_id) &mut CommunityModeratorView::for_community(&conn, data.community_id)?
?
.into_iter() .into_iter()
.map(|m| m.user_id) .map(|m| m.user_id)
.collect() .collect(),
);
editors.append(
&mut UserView::admins(&conn)
?
.into_iter()
.map(|a| a.id)
.collect()
); );
editors.append(&mut UserView::admins(&conn)?.into_iter().map(|a| a.id).collect());
if !editors.contains(&user_id) { if !editors.contains(&user_id) {
return Err(APIError::err(&self.op, "no_post_edit_allowed"))? return Err(APIError::err(&self.op, "no_post_edit_allowed"))?;
} }
// Check for a community ban // Check for a community ban
if CommunityUserBanView::get(&conn, user_id, data.community_id).is_ok() { if CommunityUserBanView::get(&conn, user_id, data.community_id).is_ok() {
return Err(APIError::err(&self.op, "community_ban"))? return Err(APIError::err(&self.op, "community_ban"))?;
} }
// Check for a site ban // Check for a site ban
if UserView::read(&conn, user_id)?.banned { if UserView::read(&conn, user_id)?.banned {
return Err(APIError::err(&self.op, "site_ban"))? return Err(APIError::err(&self.op, "site_ban"))?;
} }
let post_form = PostForm { let post_form = PostForm {
@ -401,14 +365,12 @@ impl Perform<PostResponse> for Oper<EditPost> {
deleted: data.deleted.to_owned(), deleted: data.deleted.to_owned(),
nsfw: data.nsfw, nsfw: data.nsfw,
locked: data.locked.to_owned(), locked: data.locked.to_owned(),
updated: Some(naive_now()) updated: Some(naive_now()),
}; };
let _updated_post = match Post::update(&conn, data.edit_id, &post_form) { let _updated_post = match Post::update(&conn, data.edit_id, &post_form) {
Ok(post) => post, Ok(post) => post,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_post"))?,
return Err(APIError::err(&self.op, "couldnt_update_post"))?
}
}; };
// Mod tables // Mod tables
@ -433,12 +395,10 @@ impl Perform<PostResponse> for Oper<EditPost> {
let post_view = PostView::read(&conn, data.edit_id, Some(user_id))?; let post_view = PostView::read(&conn, data.edit_id, Some(user_id))?;
Ok( Ok(PostResponse {
PostResponse {
op: self.op.to_string(), op: self.op.to_string(),
post: post_view post: post_view,
} })
)
} }
} }
@ -449,9 +409,7 @@ impl Perform<PostResponse> for Oper<SavePost> {
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
let user_id = claims.id; let user_id = claims.id;
@ -464,26 +422,20 @@ impl Perform<PostResponse> for Oper<SavePost> {
if data.save { if data.save {
match PostSaved::save(&conn, &post_saved_form) { match PostSaved::save(&conn, &post_saved_form) {
Ok(post) => post, Ok(post) => post,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_save_post"))?,
return Err(APIError::err(&self.op, "couldnt_save_post"))?
}
}; };
} else { } else {
match PostSaved::unsave(&conn, &post_saved_form) { match PostSaved::unsave(&conn, &post_saved_form) {
Ok(post) => post, Ok(post) => post,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_save_post"))?,
return Err(APIError::err(&self.op, "couldnt_save_post"))?
}
}; };
} }
let post_view = PostView::read(&conn, data.post_id, Some(user_id))?; let post_view = PostView::read(&conn, data.post_id, Some(user_id))?;
Ok( Ok(PostResponse {
PostResponse {
op: self.op.to_string(), op: self.op.to_string(),
post: post_view post: post_view,
} })
)
} }
} }

View file

@ -7,7 +7,7 @@ pub struct ListCategories;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct ListCategoriesResponse { pub struct ListCategoriesResponse {
op: String, op: String,
categories: Vec<Category> categories: Vec<Category>,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -51,19 +51,18 @@ pub struct GetModlogResponse {
added: Vec<ModAddView>, added: Vec<ModAddView>,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct CreateSite { pub struct CreateSite {
name: String, name: String,
description: Option<String>, description: Option<String>,
auth: String auth: String,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct EditSite { pub struct EditSite {
name: String, name: String,
description: Option<String>, description: Option<String>,
auth: String auth: String,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -86,7 +85,7 @@ pub struct GetSiteResponse {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct TransferSite { pub struct TransferSite {
user_id: i32, user_id: i32,
auth: String auth: String,
} }
impl Perform<ListCategoriesResponse> for Oper<ListCategories> { impl Perform<ListCategoriesResponse> for Oper<ListCategories> {
@ -97,12 +96,10 @@ impl Perform<ListCategoriesResponse> for Oper<ListCategories> {
let categories: Vec<Category> = Category::list_all(&conn)?; let categories: Vec<Category> = Category::list_all(&conn)?;
// Return the jwt // Return the jwt
Ok( Ok(ListCategoriesResponse {
ListCategoriesResponse {
op: self.op.to_string(), op: self.op.to_string(),
categories: categories categories: categories,
} })
)
} }
} }
@ -111,11 +108,41 @@ impl Perform<GetModlogResponse> for Oper<GetModlog> {
let data: &GetModlog = &self.data; let data: &GetModlog = &self.data;
let conn = establish_connection(); let conn = establish_connection();
let removed_posts = ModRemovePostView::list(&conn, data.community_id, data.mod_user_id, data.page, data.limit)?; let removed_posts = ModRemovePostView::list(
let locked_posts = ModLockPostView::list(&conn, data.community_id, data.mod_user_id, data.page, data.limit)?; &conn,
let removed_comments = ModRemoveCommentView::list(&conn, data.community_id, data.mod_user_id, data.page, data.limit)?; data.community_id,
let banned_from_community = ModBanFromCommunityView::list(&conn, data.community_id, data.mod_user_id, data.page, data.limit)?; data.mod_user_id,
let added_to_community = ModAddCommunityView::list(&conn, data.community_id, data.mod_user_id, data.page, data.limit)?; data.page,
data.limit,
)?;
let locked_posts = ModLockPostView::list(
&conn,
data.community_id,
data.mod_user_id,
data.page,
data.limit,
)?;
let removed_comments = ModRemoveCommentView::list(
&conn,
data.community_id,
data.mod_user_id,
data.page,
data.limit,
)?;
let banned_from_community = ModBanFromCommunityView::list(
&conn,
data.community_id,
data.mod_user_id,
data.page,
data.limit,
)?;
let added_to_community = ModAddCommunityView::list(
&conn,
data.community_id,
data.mod_user_id,
data.page,
data.limit,
)?;
// These arrays are only for the full modlog, when a community isn't given // These arrays are only for the full modlog, when a community isn't given
let mut removed_communities = Vec::new(); let mut removed_communities = Vec::new();
@ -123,14 +150,14 @@ impl Perform<GetModlogResponse> for Oper<GetModlog> {
let mut added = Vec::new(); let mut added = Vec::new();
if data.community_id.is_none() { if data.community_id.is_none() {
removed_communities = ModRemoveCommunityView::list(&conn, data.mod_user_id, data.page, data.limit)?; removed_communities =
ModRemoveCommunityView::list(&conn, data.mod_user_id, data.page, data.limit)?;
banned = ModBanView::list(&conn, data.mod_user_id, data.page, data.limit)?; banned = ModBanView::list(&conn, data.mod_user_id, data.page, data.limit)?;
added = ModAddView::list(&conn, data.mod_user_id, data.page, data.limit)?; added = ModAddView::list(&conn, data.mod_user_id, data.page, data.limit)?;
} }
// Return the jwt // Return the jwt
Ok( Ok(GetModlogResponse {
GetModlogResponse {
op: self.op.to_string(), op: self.op.to_string(),
removed_posts: removed_posts, removed_posts: removed_posts,
locked_posts: locked_posts, locked_posts: locked_posts,
@ -140,8 +167,7 @@ impl Perform<GetModlogResponse> for Oper<GetModlog> {
banned: banned, banned: banned,
added_to_community: added_to_community, added_to_community: added_to_community,
added: added, added: added,
} })
)
} }
} }
@ -152,21 +178,20 @@ impl Perform<SiteResponse> for Oper<CreateSite> {
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
if has_slurs(&data.name) || if has_slurs(&data.name)
(data.description.is_some() && has_slurs(&data.description.to_owned().unwrap())) { || (data.description.is_some() && has_slurs(&data.description.to_owned().unwrap()))
return Err(APIError::err(&self.op, "no_slurs"))? {
return Err(APIError::err(&self.op, "no_slurs"))?;
} }
let user_id = claims.id; let user_id = claims.id;
// Make sure user is an admin // Make sure user is an admin
if !UserView::read(&conn, user_id)?.admin { if !UserView::read(&conn, user_id)?.admin {
return Err(APIError::err(&self.op, "not_an_admin"))? return Err(APIError::err(&self.op, "not_an_admin"))?;
} }
let site_form = SiteForm { let site_form = SiteForm {
@ -178,23 +203,18 @@ impl Perform<SiteResponse> for Oper<CreateSite> {
match Site::create(&conn, &site_form) { match Site::create(&conn, &site_form) {
Ok(site) => site, Ok(site) => site,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "site_already_exists"))?,
return Err(APIError::err(&self.op, "site_already_exists"))?
}
}; };
let site_view = SiteView::read(&conn)?; let site_view = SiteView::read(&conn)?;
Ok( Ok(SiteResponse {
SiteResponse {
op: self.op.to_string(), op: self.op.to_string(),
site: site_view, site: site_view,
} })
)
} }
} }
impl Perform<SiteResponse> for Oper<EditSite> { impl Perform<SiteResponse> for Oper<EditSite> {
fn perform(&self) -> Result<SiteResponse, Error> { fn perform(&self) -> Result<SiteResponse, Error> {
let data: &EditSite = &self.data; let data: &EditSite = &self.data;
@ -202,21 +222,20 @@ impl Perform<SiteResponse> for Oper<EditSite> {
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
if has_slurs(&data.name) || if has_slurs(&data.name)
(data.description.is_some() && has_slurs(&data.description.to_owned().unwrap())) { || (data.description.is_some() && has_slurs(&data.description.to_owned().unwrap()))
return Err(APIError::err(&self.op, "no_slurs"))? {
return Err(APIError::err(&self.op, "no_slurs"))?;
} }
let user_id = claims.id; let user_id = claims.id;
// Make sure user is an admin // Make sure user is an admin
if UserView::read(&conn, user_id)?.admin == false { if UserView::read(&conn, user_id)?.admin == false {
return Err(APIError::err(&self.op, "not_an_admin"))? return Err(APIError::err(&self.op, "not_an_admin"))?;
} }
let found_site = Site::read(&conn, 1)?; let found_site = Site::read(&conn, 1)?;
@ -230,19 +249,15 @@ impl Perform<SiteResponse> for Oper<EditSite> {
match Site::update(&conn, 1, &site_form) { match Site::update(&conn, 1, &site_form) {
Ok(site) => site, Ok(site) => site,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_site"))?,
return Err(APIError::err(&self.op, "couldnt_update_site"))?
}
}; };
let site_view = SiteView::read(&conn)?; let site_view = SiteView::read(&conn)?;
Ok( Ok(SiteResponse {
SiteResponse {
op: self.op.to_string(), op: self.op.to_string(),
site: site_view, site: site_view,
} })
)
} }
} }
@ -254,7 +269,7 @@ impl Perform<GetSiteResponse> for Oper<GetSite> {
// It can return a null site in order to redirect // It can return a null site in order to redirect
let site_view = match Site::read(&conn, 1) { let site_view = match Site::read(&conn, 1) {
Ok(_site) => Some(SiteView::read(&conn)?), Ok(_site) => Some(SiteView::read(&conn)?),
Err(_e) => None Err(_e) => None,
}; };
let mut admins = UserView::admins(&conn)?; let mut admins = UserView::admins(&conn)?;
@ -267,14 +282,12 @@ impl Perform<GetSiteResponse> for Oper<GetSite> {
let banned = UserView::banned(&conn)?; let banned = UserView::banned(&conn)?;
Ok( Ok(GetSiteResponse {
GetSiteResponse {
op: self.op.to_string(), op: self.op.to_string(),
site: site_view, site: site_view,
admins: admins, admins: admins,
banned: banned, banned: banned,
} })
)
} }
} }
@ -308,8 +321,9 @@ impl Perform<SearchResponse> for Oper<Search> {
false, false,
false, false,
data.page, data.page,
data.limit)?; data.limit,
}, )?;
}
SearchType::Comments => { SearchType::Comments => {
comments = CommentView::list( comments = CommentView::list(
&conn, &conn,
@ -320,8 +334,9 @@ impl Perform<SearchResponse> for Oper<Search> {
None, None,
false, false,
data.page, data.page,
data.limit)?; data.limit,
}, )?;
}
SearchType::Communities => { SearchType::Communities => {
communities = CommunityView::list( communities = CommunityView::list(
&conn, &conn,
@ -330,16 +345,12 @@ impl Perform<SearchResponse> for Oper<Search> {
true, true,
Some(data.q.to_owned()), Some(data.q.to_owned()),
data.page, data.page,
data.limit)?; data.limit,
}, )?;
}
SearchType::Users => { SearchType::Users => {
users = UserView::list( users = UserView::list(&conn, &sort, Some(data.q.to_owned()), data.page, data.limit)?;
&conn, }
&sort,
Some(data.q.to_owned()),
data.page,
data.limit)?;
},
SearchType::All => { SearchType::All => {
posts = PostView::list( posts = PostView::list(
&conn, &conn,
@ -354,7 +365,8 @@ impl Perform<SearchResponse> for Oper<Search> {
false, false,
false, false,
data.page, data.page,
data.limit)?; data.limit,
)?;
comments = CommentView::list( comments = CommentView::list(
&conn, &conn,
&sort, &sort,
@ -364,7 +376,8 @@ impl Perform<SearchResponse> for Oper<Search> {
None, None,
false, false,
data.page, data.page,
data.limit)?; data.limit,
)?;
communities = CommunityView::list( communities = CommunityView::list(
&conn, &conn,
&sort, &sort,
@ -372,14 +385,10 @@ impl Perform<SearchResponse> for Oper<Search> {
true, true,
Some(data.q.to_owned()), Some(data.q.to_owned()),
data.page, data.page,
data.limit)?; data.limit,
users = UserView::list( )?;
&conn, users = UserView::list(&conn, &sort, Some(data.q.to_owned()), data.page, data.limit)?;
&sort, }
Some(data.q.to_owned()),
data.page,
data.limit)?;
},
SearchType::Url => { SearchType::Url => {
posts = PostView::list( posts = PostView::list(
&conn, &conn,
@ -394,22 +403,20 @@ impl Perform<SearchResponse> for Oper<Search> {
false, false,
false, false,
data.page, data.page,
data.limit)?; data.limit,
)?;
} }
}; };
// Return the jwt // Return the jwt
Ok( Ok(SearchResponse {
SearchResponse {
op: self.op.to_string(), op: self.op.to_string(),
type_: data.type_.to_owned(), type_: data.type_.to_owned(),
comments: comments, comments: comments,
posts: posts, posts: posts,
communities: communities, communities: communities,
users: users, users: users,
} })
)
} }
} }
@ -420,9 +427,7 @@ impl Perform<GetSiteResponse> for Oper<TransferSite> {
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
let user_id = claims.id; let user_id = claims.id;
@ -431,7 +436,7 @@ impl Perform<GetSiteResponse> for Oper<TransferSite> {
// Make sure user is the creator // Make sure user is the creator
if read_site.creator_id != user_id { if read_site.creator_id != user_id {
return Err(APIError::err(&self.op, "not_an_admin"))? return Err(APIError::err(&self.op, "not_an_admin"))?;
} }
let site_form = SiteForm { let site_form = SiteForm {
@ -443,9 +448,7 @@ impl Perform<GetSiteResponse> for Oper<TransferSite> {
match Site::update(&conn, 1, &site_form) { match Site::update(&conn, 1, &site_form) {
Ok(site) => site, Ok(site) => site,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_site"))?,
return Err(APIError::err(&self.op, "couldnt_update_site"))?
}
}; };
// Mod tables // Mod tables
@ -460,20 +463,20 @@ impl Perform<GetSiteResponse> for Oper<TransferSite> {
let site_view = SiteView::read(&conn)?; let site_view = SiteView::read(&conn)?;
let mut admins = UserView::admins(&conn)?; let mut admins = UserView::admins(&conn)?;
let creator_index = admins.iter().position(|r| r.id == site_view.creator_id).unwrap(); let creator_index = admins
.iter()
.position(|r| r.id == site_view.creator_id)
.unwrap();
let creator_user = admins.remove(creator_index); let creator_user = admins.remove(creator_index);
admins.insert(0, creator_user); admins.insert(0, creator_user);
let banned = UserView::banned(&conn)?; let banned = UserView::banned(&conn)?;
Ok( Ok(GetSiteResponse {
GetSiteResponse {
op: self.op.to_string(), op: self.op.to_string(),
site: Some(site_view), site: Some(site_view),
admins: admins, admins: admins,
banned: banned, banned: banned,
} })
)
} }
} }

View file

@ -1,11 +1,11 @@
use super::*; use super::*;
use bcrypt::verify;
use std::str::FromStr; use std::str::FromStr;
use bcrypt::{verify};
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct Login { pub struct Login {
username_or_email: String, username_or_email: String,
password: String password: String,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -27,7 +27,7 @@ pub struct SaveUserSettings {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct LoginResponse { pub struct LoginResponse {
op: String, op: String,
jwt: String jwt: String,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -60,14 +60,14 @@ pub struct GetRepliesResponse {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct MarkAllAsRead { pub struct MarkAllAsRead {
auth: String auth: String,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct AddAdmin { pub struct AddAdmin {
user_id: i32, user_id: i32,
added: bool, added: bool,
auth: String auth: String,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -82,7 +82,7 @@ pub struct BanUser {
ban: bool, ban: bool,
reason: Option<String>, reason: Option<String>,
expires: Option<i64>, expires: Option<i64>,
auth: String auth: String,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -98,7 +98,7 @@ pub struct GetReplies {
page: Option<i64>, page: Option<i64>,
limit: Option<i64>, limit: Option<i64>,
unread_only: bool, unread_only: bool,
auth: String auth: String,
} }
impl Perform<LoginResponse> for Oper<Login> { impl Perform<LoginResponse> for Oper<Login> {
@ -109,26 +109,28 @@ impl Perform<LoginResponse> for Oper<Login> {
// Fetch that username / email // Fetch that username / email
let user: User_ = match User_::find_by_email_or_username(&conn, &data.username_or_email) { let user: User_ = match User_::find_by_email_or_username(&conn, &data.username_or_email) {
Ok(user) => user, Ok(user) => user,
Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_that_username_or_email"))? Err(_e) => {
return Err(APIError::err(
&self.op,
"couldnt_find_that_username_or_email",
))?
}
}; };
// Verify the password // Verify the password
let valid: bool = verify(&data.password, &user.password_encrypted).unwrap_or(false); let valid: bool = verify(&data.password, &user.password_encrypted).unwrap_or(false);
if !valid { if !valid {
return Err(APIError::err(&self.op, "password_incorrect"))? return Err(APIError::err(&self.op, "password_incorrect"))?;
} }
// Return the jwt // Return the jwt
Ok( Ok(LoginResponse {
LoginResponse {
op: self.op.to_string(), op: self.op.to_string(),
jwt: user.jwt() jwt: user.jwt(),
} })
)
} }
} }
impl Perform<LoginResponse> for Oper<Register> { impl Perform<LoginResponse> for Oper<Register> {
fn perform(&self) -> Result<LoginResponse, Error> { fn perform(&self) -> Result<LoginResponse, Error> {
let data: &Register = &self.data; let data: &Register = &self.data;
@ -136,16 +138,16 @@ impl Perform<LoginResponse> for Oper<Register> {
// Make sure passwords match // Make sure passwords match
if &data.password != &data.password_verify { if &data.password != &data.password_verify {
return Err(APIError::err(&self.op, "passwords_dont_match"))? return Err(APIError::err(&self.op, "passwords_dont_match"))?;
} }
if has_slurs(&data.username) { if has_slurs(&data.username) {
return Err(APIError::err(&self.op, "no_slurs"))? return Err(APIError::err(&self.op, "no_slurs"))?;
} }
// Make sure there are no admins // Make sure there are no admins
if data.admin && UserView::admins(&conn)?.len() > 0 { if data.admin && UserView::admins(&conn)?.len() > 0 {
return Err(APIError::err(&self.op, "admin_already_created"))? return Err(APIError::err(&self.op, "admin_already_created"))?;
} }
// Register the new user // Register the new user
@ -164,9 +166,7 @@ impl Perform<LoginResponse> for Oper<Register> {
// Create the user // Create the user
let inserted_user = match User_::register(&conn, &user_form) { let inserted_user = match User_::register(&conn, &user_form) {
Ok(user) => user, Ok(user) => user,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "user_already_exists"))?,
return Err(APIError::err(&self.op, "user_already_exists"))?
}
}; };
// Create the main community if it doesn't exist // Create the main community if it doesn't exist
@ -194,11 +194,10 @@ impl Perform<LoginResponse> for Oper<Register> {
user_id: inserted_user.id, user_id: inserted_user.id,
}; };
let _inserted_community_follower = match CommunityFollower::follow(&conn, &community_follower_form) { let _inserted_community_follower =
match CommunityFollower::follow(&conn, &community_follower_form) {
Ok(user) => user, Ok(user) => user,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "community_follower_already_exists"))?,
return Err(APIError::err(&self.op, "community_follower_already_exists"))?
}
}; };
// If its an admin, add them as a mod and follower to main // If its an admin, add them as a mod and follower to main
@ -208,22 +207,23 @@ impl Perform<LoginResponse> for Oper<Register> {
user_id: inserted_user.id, user_id: inserted_user.id,
}; };
let _inserted_community_moderator = match CommunityModerator::join(&conn, &community_moderator_form) { let _inserted_community_moderator =
match CommunityModerator::join(&conn, &community_moderator_form) {
Ok(user) => user, Ok(user) => user,
Err(_e) => { Err(_e) => {
return Err(APIError::err(&self.op, "community_moderator_already_exists"))? return Err(APIError::err(
&self.op,
"community_moderator_already_exists",
))?
} }
}; };
} }
// Return the jwt // Return the jwt
Ok( Ok(LoginResponse {
LoginResponse {
op: self.op.to_string(), op: self.op.to_string(),
jwt: inserted_user.jwt() jwt: inserted_user.jwt(),
} })
)
} }
} }
@ -234,9 +234,7 @@ impl Perform<LoginResponse> for Oper<SaveUserSettings> {
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
let user_id = claims.id; let user_id = claims.id;
@ -257,18 +255,14 @@ impl Perform<LoginResponse> for Oper<SaveUserSettings> {
let updated_user = match User_::update(&conn, user_id, &user_form) { let updated_user = match User_::update(&conn, user_id, &user_form) {
Ok(user) => user, Ok(user) => user,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_user"))?,
return Err(APIError::err(&self.op, "couldnt_update_user"))?
}
}; };
// Return the jwt // Return the jwt
Ok( Ok(LoginResponse {
LoginResponse {
op: self.op.to_string(), op: self.op.to_string(),
jwt: updated_user.jwt() jwt: updated_user.jwt(),
} })
)
} }
} }
@ -278,25 +272,21 @@ impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
let conn = establish_connection(); let conn = establish_connection();
let user_claims: Option<Claims> = match &data.auth { let user_claims: Option<Claims> = match &data.auth {
Some(auth) => { Some(auth) => match Claims::decode(&auth) {
match Claims::decode(&auth) { Ok(claims) => Some(claims.claims),
Ok(claims) => { Err(_e) => None,
Some(claims.claims) },
} None => None,
Err(_e) => None
}
}
None => None
}; };
let user_id = match &user_claims { let user_id = match &user_claims {
Some(claims) => Some(claims.id), Some(claims) => Some(claims.id),
None => None None => None,
}; };
let show_nsfw = match &user_claims { let show_nsfw = match &user_claims {
Some(claims) => claims.show_nsfw, Some(claims) => claims.show_nsfw,
None => false None => false,
}; };
//TODO add save //TODO add save
@ -304,7 +294,13 @@ impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
let user_details_id = match data.user_id { let user_details_id = match data.user_id {
Some(id) => id, Some(id) => id,
None => User_::read_from_name(&conn, data.username.to_owned().unwrap_or("admin".to_string()))?.id None => {
User_::read_from_name(
&conn,
data.username.to_owned().unwrap_or("admin".to_string()),
)?
.id
}
}; };
let user_view = UserView::read(&conn, user_details_id)?; let user_view = UserView::read(&conn, user_details_id)?;
@ -324,7 +320,8 @@ impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
data.saved_only, data.saved_only,
false, false,
data.page, data.page,
data.limit)? data.limit,
)?
} else { } else {
PostView::list( PostView::list(
&conn, &conn,
@ -339,7 +336,8 @@ impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
data.saved_only, data.saved_only,
false, false,
data.page, data.page,
data.limit)? data.limit,
)?
}; };
let comments = if data.saved_only { let comments = if data.saved_only {
CommentView::list( CommentView::list(
@ -351,7 +349,8 @@ impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
Some(user_details_id), Some(user_details_id),
data.saved_only, data.saved_only,
data.page, data.page,
data.limit)? data.limit,
)?
} else { } else {
CommentView::list( CommentView::list(
&conn, &conn,
@ -362,27 +361,25 @@ impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
user_id, user_id,
data.saved_only, data.saved_only,
data.page, data.page,
data.limit)? data.limit,
)?
}; };
let follows = CommunityFollowerView::for_user(&conn, user_details_id)?; let follows = CommunityFollowerView::for_user(&conn, user_details_id)?;
let moderates = CommunityModeratorView::for_user(&conn, user_details_id)?; let moderates = CommunityModeratorView::for_user(&conn, user_details_id)?;
// Return the jwt // Return the jwt
Ok( Ok(GetUserDetailsResponse {
GetUserDetailsResponse {
op: self.op.to_string(), op: self.op.to_string(),
user: user_view, user: user_view,
follows: follows, follows: follows,
moderates: moderates, moderates: moderates,
comments: comments, comments: comments,
posts: posts, posts: posts,
} })
)
} }
} }
impl Perform<AddAdminResponse> for Oper<AddAdmin> { impl Perform<AddAdminResponse> for Oper<AddAdmin> {
fn perform(&self) -> Result<AddAdminResponse, Error> { fn perform(&self) -> Result<AddAdminResponse, Error> {
let data: &AddAdmin = &self.data; let data: &AddAdmin = &self.data;
@ -390,16 +387,14 @@ impl Perform<AddAdminResponse> for Oper<AddAdmin> {
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
let user_id = claims.id; let user_id = claims.id;
// Make sure user is an admin // Make sure user is an admin
if UserView::read(&conn, user_id)?.admin == false { if UserView::read(&conn, user_id)?.admin == false {
return Err(APIError::err(&self.op, "not_an_admin"))? return Err(APIError::err(&self.op, "not_an_admin"))?;
} }
let read_user = User_::read(&conn, data.user_id)?; let read_user = User_::read(&conn, data.user_id)?;
@ -418,9 +413,7 @@ impl Perform<AddAdminResponse> for Oper<AddAdmin> {
match User_::update(&conn, data.user_id, &user_form) { match User_::update(&conn, data.user_id, &user_form) {
Ok(user) => user, Ok(user) => user,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_user"))?,
return Err(APIError::err(&self.op, "couldnt_update_user"))?
}
}; };
// Mod tables // Mod tables
@ -438,12 +431,10 @@ impl Perform<AddAdminResponse> for Oper<AddAdmin> {
let creator_user = admins.remove(creator_index); let creator_user = admins.remove(creator_index);
admins.insert(0, creator_user); admins.insert(0, creator_user);
Ok( Ok(AddAdminResponse {
AddAdminResponse {
op: self.op.to_string(), op: self.op.to_string(),
admins: admins, admins: admins,
} })
)
} }
} }
@ -454,16 +445,14 @@ impl Perform<BanUserResponse> for Oper<BanUser> {
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
let user_id = claims.id; let user_id = claims.id;
// Make sure user is an admin // Make sure user is an admin
if UserView::read(&conn, user_id)?.admin == false { if UserView::read(&conn, user_id)?.admin == false {
return Err(APIError::err(&self.op, "not_an_admin"))? return Err(APIError::err(&self.op, "not_an_admin"))?;
} }
let read_user = User_::read(&conn, data.user_id)?; let read_user = User_::read(&conn, data.user_id)?;
@ -482,15 +471,13 @@ impl Perform<BanUserResponse> for Oper<BanUser> {
match User_::update(&conn, data.user_id, &user_form) { match User_::update(&conn, data.user_id, &user_form) {
Ok(user) => user, Ok(user) => user,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_user"))?,
return Err(APIError::err(&self.op, "couldnt_update_user"))?
}
}; };
// Mod tables // Mod tables
let expires = match data.expires { let expires = match data.expires {
Some(time) => Some(naive_from_unix(time)), Some(time) => Some(naive_from_unix(time)),
None => None None => None,
}; };
let form = ModBanForm { let form = ModBanForm {
@ -505,14 +492,11 @@ impl Perform<BanUserResponse> for Oper<BanUser> {
let user_view = UserView::read(&conn, data.user_id)?; let user_view = UserView::read(&conn, data.user_id)?;
Ok( Ok(BanUserResponse {
BanUserResponse {
op: self.op.to_string(), op: self.op.to_string(),
user: user_view, user: user_view,
banned: data.ban banned: data.ban,
} })
)
} }
} }
@ -523,24 +507,27 @@ impl Perform<GetRepliesResponse> for Oper<GetReplies> {
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
let user_id = claims.id; let user_id = claims.id;
let sort = SortType::from_str(&data.sort)?; let sort = SortType::from_str(&data.sort)?;
let replies = ReplyView::get_replies(&conn, user_id, &sort, data.unread_only, data.page, data.limit)?; let replies = ReplyView::get_replies(
&conn,
user_id,
&sort,
data.unread_only,
data.page,
data.limit,
)?;
// Return the jwt // Return the jwt
Ok( Ok(GetRepliesResponse {
GetRepliesResponse {
op: self.op.to_string(), op: self.op.to_string(),
replies: replies, replies: replies,
} })
)
} }
} }
@ -551,9 +538,7 @@ impl Perform<GetRepliesResponse> for Oper<MarkAllAsRead> {
let claims = match Claims::decode(&data.auth) { let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims, Ok(claims) => claims.claims,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
return Err(APIError::err(&self.op, "not_logged_in"))?
}
}; };
let user_id = claims.id; let user_id = claims.id;
@ -569,24 +554,20 @@ impl Perform<GetRepliesResponse> for Oper<MarkAllAsRead> {
removed: None, removed: None,
deleted: None, deleted: None,
read: Some(true), read: Some(true),
updated: reply.to_owned().updated updated: reply.to_owned().updated,
}; };
let _updated_comment = match Comment::update(&conn, reply.id, &comment_form) { let _updated_comment = match Comment::update(&conn, reply.id, &comment_form) {
Ok(comment) => comment, Ok(comment) => comment,
Err(_e) => { Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_comment"))?,
return Err(APIError::err(&self.op, "couldnt_update_comment"))?
}
}; };
} }
let replies = ReplyView::get_replies(&conn, user_id, &SortType::New, true, Some(1), Some(999))?; let replies = ReplyView::get_replies(&conn, user_id, &SortType::New, true, Some(1), Some(999))?;
Ok( Ok(GetRepliesResponse {
GetRepliesResponse {
op: self.op.to_string(), op: self.op.to_string(),
replies: replies, replies: replies,
} })
)
} }
} }

View file

@ -1,27 +1,51 @@
extern crate activitypub; extern crate activitypub;
use self::activitypub::{context, actor::Person}; use self::activitypub::{actor::Person, context};
use crate::db::user::User_; use crate::db::user::User_;
impl User_ { impl User_ {
pub fn person(&self) -> Person { pub fn person(&self) -> Person {
use crate::{Settings, to_datetime_utc}; use crate::{to_datetime_utc, Settings};
let base_url = &format!("{}/user/{}", Settings::get().api_endpoint(), self.name); let base_url = &format!("{}/user/{}", Settings::get().api_endpoint(), self.name);
let mut person = Person::default(); let mut person = Person::default();
person.object_props.set_context_object(context()).ok(); person.object_props.set_context_object(context()).ok();
person.object_props.set_id_string(base_url.to_string()).ok(); person.object_props.set_id_string(base_url.to_string()).ok();
person.object_props.set_name_string(self.name.to_owned()).ok(); person
person.object_props.set_published_utctime(to_datetime_utc(self.published)).ok(); .object_props
.set_name_string(self.name.to_owned())
.ok();
person
.object_props
.set_published_utctime(to_datetime_utc(self.published))
.ok();
if let Some(i) = self.updated { if let Some(i) = self.updated {
person.object_props.set_updated_utctime(to_datetime_utc(i)).ok(); person
.object_props
.set_updated_utctime(to_datetime_utc(i))
.ok();
} }
// person.object_props.summary = self.summary; // person.object_props.summary = self.summary;
person.ap_actor_props.set_inbox_string(format!("{}/inbox", &base_url)).ok(); person
person.ap_actor_props.set_outbox_string(format!("{}/outbox", &base_url)).ok(); .ap_actor_props
person.ap_actor_props.set_following_string(format!("{}/following", &base_url)).ok(); .set_inbox_string(format!("{}/inbox", &base_url))
person.ap_actor_props.set_liked_string(format!("{}/liked", &base_url)).ok(); .ok();
person
.ap_actor_props
.set_outbox_string(format!("{}/outbox", &base_url))
.ok();
person
.ap_actor_props
.set_following_string(format!("{}/following", &base_url))
.ok();
person
.ap_actor_props
.set_liked_string(format!("{}/liked", &base_url))
.ok();
if let Some(i) = &self.preferred_username { if let Some(i) = &self.preferred_username {
person.ap_actor_props.set_preferred_username_string(i.to_string()).ok(); person
.ap_actor_props
.set_preferred_username_string(i.to_string())
.ok();
} }
person person
@ -51,10 +75,11 @@ mod tests {
}; };
let person = expected_user.person(); let person = expected_user.person();
assert_eq!("rrr/api/v1/user/thom", person.object_props.id_string().unwrap()); assert_eq!(
"rrr/api/v1/user/thom",
person.object_props.id_string().unwrap()
);
let json = serde_json::to_string_pretty(&person).unwrap(); let json = serde_json::to_string_pretty(&person).unwrap();
println!("{}", json); println!("{}", json);
} }
} }

View file

@ -1,12 +1,12 @@
use crate::schema::{category};
use crate::schema::category::dsl::*;
use super::*; use super::*;
use crate::schema::category;
use crate::schema::category::dsl::*;
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)] #[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
#[table_name = "category"] #[table_name = "category"]
pub struct Category { pub struct Category {
pub id: i32, pub id: i32,
pub name: String pub name: String,
} }
#[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize)] #[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize)]
@ -17,13 +17,11 @@ pub struct CategoryForm {
impl Crud<CategoryForm> for Category { impl Crud<CategoryForm> for Category {
fn read(conn: &PgConnection, category_id: i32) -> Result<Self, Error> { fn read(conn: &PgConnection, category_id: i32) -> Result<Self, Error> {
category.find(category_id) category.find(category_id).first::<Self>(conn)
.first::<Self>(conn)
} }
fn delete(conn: &PgConnection, category_id: i32) -> Result<usize, Error> { fn delete(conn: &PgConnection, category_id: i32) -> Result<usize, Error> {
diesel::delete(category.find(category_id)) diesel::delete(category.find(category_id)).execute(conn)
.execute(conn)
} }
fn create(conn: &PgConnection, new_category: &CategoryForm) -> Result<Self, Error> { fn create(conn: &PgConnection, new_category: &CategoryForm) -> Result<Self, Error> {
@ -32,7 +30,11 @@ impl Crud<CategoryForm> for Category {
.get_result::<Self>(conn) .get_result::<Self>(conn)
} }
fn update(conn: &PgConnection, category_id: i32, new_category: &CategoryForm) -> Result<Self, Error> { fn update(
conn: &PgConnection,
category_id: i32,
new_category: &CategoryForm,
) -> Result<Self, Error> {
diesel::update(category.find(category_id)) diesel::update(category.find(category_id))
.set(new_category) .set(new_category)
.get_result::<Self>(conn) .get_result::<Self>(conn)
@ -55,7 +57,7 @@ mod tests {
let categories = Category::list_all(&conn).unwrap(); let categories = Category::list_all(&conn).unwrap();
let expected_first_category = Category { let expected_first_category = Category {
id: 1, id: 1,
name: "Discussion".into() name: "Discussion".into(),
}; };
assert_eq!(expected_first_category, categories[0]); assert_eq!(expected_first_category, categories[0]);

View file

@ -1,6 +1,6 @@
use crate::schema::{comment, comment_like, comment_saved};
use super::*;
use super::post::Post; use super::post::Post;
use super::*;
use crate::schema::{comment, comment_like, comment_saved};
// WITH RECURSIVE MyTree AS ( // WITH RECURSIVE MyTree AS (
// SELECT * FROM comment WHERE parent_id IS NULL // SELECT * FROM comment WHERE parent_id IS NULL
@ -41,14 +41,12 @@ pub struct CommentForm {
impl Crud<CommentForm> for Comment { impl Crud<CommentForm> for Comment {
fn read(conn: &PgConnection, comment_id: i32) -> Result<Self, Error> { fn read(conn: &PgConnection, comment_id: i32) -> Result<Self, Error> {
use crate::schema::comment::dsl::*; use crate::schema::comment::dsl::*;
comment.find(comment_id) comment.find(comment_id).first::<Self>(conn)
.first::<Self>(conn)
} }
fn delete(conn: &PgConnection, comment_id: i32) -> Result<usize, Error> { fn delete(conn: &PgConnection, comment_id: i32) -> Result<usize, Error> {
use crate::schema::comment::dsl::*; use crate::schema::comment::dsl::*;
diesel::delete(comment.find(comment_id)) diesel::delete(comment.find(comment_id)).execute(conn)
.execute(conn)
} }
fn create(conn: &PgConnection, comment_form: &CommentForm) -> Result<Self, Error> { fn create(conn: &PgConnection, comment_form: &CommentForm) -> Result<Self, Error> {
@ -58,7 +56,11 @@ impl Crud<CommentForm> for Comment {
.get_result::<Self>(conn) .get_result::<Self>(conn)
} }
fn update(conn: &PgConnection, comment_id: i32, comment_form: &CommentForm) -> Result<Self, Error> { fn update(
conn: &PgConnection,
comment_id: i32,
comment_form: &CommentForm,
) -> Result<Self, Error> {
use crate::schema::comment::dsl::*; use crate::schema::comment::dsl::*;
diesel::update(comment.find(comment_id)) diesel::update(comment.find(comment_id))
.set(comment_form) .set(comment_form)
@ -84,7 +86,7 @@ pub struct CommentLikeForm {
pub user_id: i32, pub user_id: i32,
pub comment_id: i32, pub comment_id: i32,
pub post_id: i32, pub post_id: i32,
pub score: i16 pub score: i16,
} }
impl Likeable<CommentLikeForm> for CommentLike { impl Likeable<CommentLikeForm> for CommentLike {
@ -106,7 +108,8 @@ impl Likeable <CommentLikeForm> for CommentLike {
diesel::delete( diesel::delete(
comment_like comment_like
.filter(comment_id.eq(comment_like_form.comment_id)) .filter(comment_id.eq(comment_like_form.comment_id))
.filter(user_id.eq(comment_like_form.user_id))) .filter(user_id.eq(comment_like_form.user_id)),
)
.execute(conn) .execute(conn)
} }
} }
@ -146,19 +149,21 @@ impl Saveable <CommentSavedForm> for CommentSaved {
} }
fn unsave(conn: &PgConnection, comment_saved_form: &CommentSavedForm) -> Result<usize, Error> { fn unsave(conn: &PgConnection, comment_saved_form: &CommentSavedForm) -> Result<usize, Error> {
use crate::schema::comment_saved::dsl::*; use crate::schema::comment_saved::dsl::*;
diesel::delete(comment_saved diesel::delete(
comment_saved
.filter(comment_id.eq(comment_saved_form.comment_id)) .filter(comment_id.eq(comment_saved_form.comment_id))
.filter(user_id.eq(comment_saved_form.user_id))) .filter(user_id.eq(comment_saved_form.user_id)),
)
.execute(conn) .execute(conn)
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
use super::super::post::*;
use super::super::community::*; use super::super::community::*;
use super::super::post::*;
use super::super::user::*; use super::super::user::*;
use super::*;
#[test] #[test]
fn test_crud() { fn test_crud() {
let conn = establish_connection(); let conn = establish_connection();
@ -214,7 +219,7 @@ mod tests {
deleted: None, deleted: None,
read: None, read: None,
parent_id: None, parent_id: None,
updated: None updated: None,
}; };
let inserted_comment = Comment::create(&conn, &comment_form).unwrap(); let inserted_comment = Comment::create(&conn, &comment_form).unwrap();
@ -229,7 +234,7 @@ mod tests {
read: false, read: false,
parent_id: None, parent_id: None,
published: inserted_comment.published, published: inserted_comment.published,
updated: None updated: None,
}; };
let child_comment_form = CommentForm { let child_comment_form = CommentForm {
@ -240,7 +245,7 @@ mod tests {
removed: None, removed: None,
deleted: None, deleted: None,
read: None, read: None,
updated: None updated: None,
}; };
let inserted_child_comment = Comment::create(&conn, &child_comment_form).unwrap(); let inserted_child_comment = Comment::create(&conn, &child_comment_form).unwrap();
@ -250,7 +255,7 @@ mod tests {
comment_id: inserted_comment.id, comment_id: inserted_comment.id,
post_id: inserted_post.id, post_id: inserted_post.id,
user_id: inserted_user.id, user_id: inserted_user.id,
score: 1 score: 1,
}; };
let inserted_comment_like = CommentLike::like(&conn, &comment_like_form).unwrap(); let inserted_comment_like = CommentLike::like(&conn, &comment_like_form).unwrap();
@ -261,7 +266,7 @@ mod tests {
post_id: inserted_post.id, post_id: inserted_post.id,
user_id: inserted_user.id, user_id: inserted_user.id,
published: inserted_comment_like.published, published: inserted_comment_like.published,
score: 1 score: 1,
}; };
// Comment Saved // Comment Saved
@ -294,10 +299,12 @@ mod tests {
assert_eq!(expected_comment, updated_comment); assert_eq!(expected_comment, updated_comment);
assert_eq!(expected_comment_like, inserted_comment_like); assert_eq!(expected_comment_like, inserted_comment_like);
assert_eq!(expected_comment_saved, inserted_comment_saved); assert_eq!(expected_comment_saved, inserted_comment_saved);
assert_eq!(expected_comment.id, inserted_child_comment.parent_id.unwrap()); assert_eq!(
expected_comment.id,
inserted_child_comment.parent_id.unwrap()
);
assert_eq!(1, like_removed); assert_eq!(1, like_removed);
assert_eq!(1, saved_removed); assert_eq!(1, saved_removed);
assert_eq!(1, num_deleted); assert_eq!(1, num_deleted);
} }
} }

View file

@ -26,7 +26,9 @@ table! {
} }
} }
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)] #[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "comment_view"] #[table_name = "comment_view"]
pub struct CommentView { pub struct CommentView {
pub id: i32, pub id: i32,
@ -52,8 +54,8 @@ pub struct CommentView {
} }
impl CommentView { impl CommentView {
pub fn list(
pub fn list(conn: &PgConnection, conn: &PgConnection,
sort: &SortType, sort: &SortType,
for_post_id: Option<i32>, for_post_id: Option<i32>,
for_creator_id: Option<i32>, for_creator_id: Option<i32>,
@ -109,17 +111,18 @@ impl CommentView {
SortType::TopDay => query SortType::TopDay => query
.filter(published.gt(now - 1.days())) .filter(published.gt(now - 1.days()))
.order_by(score.desc()), .order_by(score.desc()),
_ => query.order_by(published.desc()) _ => query.order_by(published.desc()),
}; };
// Note: deleted and removed comments are done on the front side // Note: deleted and removed comments are done on the front side
query query.limit(limit).offset(offset).load::<Self>(conn)
.limit(limit)
.offset(offset)
.load::<Self>(conn)
} }
pub fn read(conn: &PgConnection, from_comment_id: i32, my_user_id: Option<i32>) -> Result<Self, Error> { pub fn read(
conn: &PgConnection,
from_comment_id: i32,
my_user_id: Option<i32>,
) -> Result<Self, Error> {
use super::comment_view::comment_view::dsl::*; use super::comment_view::comment_view::dsl::*;
let mut query = comment_view.into_boxed(); let mut query = comment_view.into_boxed();
@ -131,14 +134,14 @@ impl CommentView {
query = query.filter(user_id.is_null()); query = query.filter(user_id.is_null());
} }
query = query.filter(id.eq(from_comment_id)).order_by(published.desc()); query = query
.filter(id.eq(from_comment_id))
.order_by(published.desc());
query.first::<Self>(conn) query.first::<Self>(conn)
} }
} }
// The faked schema since diesel doesn't do views // The faked schema since diesel doesn't do views
table! { table! {
reply_view (id) { reply_view (id) {
@ -166,7 +169,9 @@ table! {
} }
} }
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)] #[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "reply_view"] #[table_name = "reply_view"]
pub struct ReplyView { pub struct ReplyView {
pub id: i32, pub id: i32,
@ -193,8 +198,8 @@ pub struct ReplyView {
} }
impl ReplyView { impl ReplyView {
pub fn get_replies(
pub fn get_replies(conn: &PgConnection, conn: &PgConnection,
for_user_id: i32, for_user_id: i32,
sort: &SortType, sort: &SortType,
unread_only: bool, unread_only: bool,
@ -231,24 +236,20 @@ impl ReplyView {
SortType::TopDay => query SortType::TopDay => query
.filter(published.gt(now - 1.days())) .filter(published.gt(now - 1.days()))
.order_by(score.desc()), .order_by(score.desc()),
_ => query.order_by(published.desc()) _ => query.order_by(published.desc()),
}; };
query query.limit(limit).offset(offset).load::<Self>(conn)
.limit(limit)
.offset(offset)
.load::<Self>(conn)
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
use super::super::post::*;
use super::super::community::*;
use super::super::user::*;
use super::super::comment::*; use super::super::comment::*;
use super::super::community::*;
use super::super::post::*;
use super::super::user::*;
use super::*;
#[test] #[test]
fn test_crud() { fn test_crud() {
let conn = establish_connection(); let conn = establish_connection();
@ -304,7 +305,7 @@ mod tests {
removed: None, removed: None,
deleted: None, deleted: None,
read: None, read: None,
updated: None updated: None,
}; };
let inserted_comment = Comment::create(&conn, &comment_form).unwrap(); let inserted_comment = Comment::create(&conn, &comment_form).unwrap();
@ -313,7 +314,7 @@ mod tests {
comment_id: inserted_comment.id, comment_id: inserted_comment.id,
post_id: inserted_post.id, post_id: inserted_post.id,
user_id: inserted_user.id, user_id: inserted_user.id,
score: 1 score: 1,
}; };
let _inserted_comment_like = CommentLike::like(&conn, &comment_like_form).unwrap(); let _inserted_comment_like = CommentLike::like(&conn, &comment_like_form).unwrap();
@ -373,7 +374,9 @@ mod tests {
None, None,
false, false,
None, None,
None).unwrap(); None,
)
.unwrap();
let read_comment_views_with_user = CommentView::list( let read_comment_views_with_user = CommentView::list(
&conn, &conn,
&SortType::New, &SortType::New,
@ -383,7 +386,9 @@ mod tests {
Some(inserted_user.id), Some(inserted_user.id),
false, false,
None, None,
None).unwrap(); None,
)
.unwrap();
let like_removed = CommentLike::remove(&conn, &comment_like_form).unwrap(); let like_removed = CommentLike::remove(&conn, &comment_like_form).unwrap();
let num_deleted = Comment::delete(&conn, inserted_comment.id).unwrap(); let num_deleted = Comment::delete(&conn, inserted_comment.id).unwrap();
Post::delete(&conn, inserted_post.id).unwrap(); Post::delete(&conn, inserted_post.id).unwrap();
@ -391,9 +396,11 @@ mod tests {
User_::delete(&conn, inserted_user.id).unwrap(); User_::delete(&conn, inserted_user.id).unwrap();
assert_eq!(expected_comment_view_no_user, read_comment_views_no_user[0]); assert_eq!(expected_comment_view_no_user, read_comment_views_no_user[0]);
assert_eq!(expected_comment_view_with_user, read_comment_views_with_user[0]); assert_eq!(
expected_comment_view_with_user,
read_comment_views_with_user[0]
);
assert_eq!(1, num_deleted); assert_eq!(1, num_deleted);
assert_eq!(1, like_removed); assert_eq!(1, like_removed);
} }
} }

View file

@ -1,5 +1,5 @@
use crate::schema::{community, community_moderator, community_follower, community_user_ban, site};
use super::*; use super::*;
use crate::schema::{community, community_follower, community_moderator, community_user_ban, site};
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)] #[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
#[table_name = "community"] #[table_name = "community"]
@ -34,14 +34,12 @@ pub struct CommunityForm {
impl Crud<CommunityForm> for Community { impl Crud<CommunityForm> for Community {
fn read(conn: &PgConnection, community_id: i32) -> Result<Self, Error> { fn read(conn: &PgConnection, community_id: i32) -> Result<Self, Error> {
use crate::schema::community::dsl::*; use crate::schema::community::dsl::*;
community.find(community_id) community.find(community_id).first::<Self>(conn)
.first::<Self>(conn)
} }
fn delete(conn: &PgConnection, community_id: i32) -> Result<usize, Error> { fn delete(conn: &PgConnection, community_id: i32) -> Result<usize, Error> {
use crate::schema::community::dsl::*; use crate::schema::community::dsl::*;
diesel::delete(community.find(community_id)) diesel::delete(community.find(community_id)).execute(conn)
.execute(conn)
} }
fn create(conn: &PgConnection, new_community: &CommunityForm) -> Result<Self, Error> { fn create(conn: &PgConnection, new_community: &CommunityForm) -> Result<Self, Error> {
@ -51,7 +49,11 @@ impl Crud<CommunityForm> for Community {
.get_result::<Self>(conn) .get_result::<Self>(conn)
} }
fn update(conn: &PgConnection, community_id: i32, new_community: &CommunityForm) -> Result<Self, Error> { fn update(
conn: &PgConnection,
community_id: i32,
new_community: &CommunityForm,
) -> Result<Self, Error> {
use crate::schema::community::dsl::*; use crate::schema::community::dsl::*;
diesel::update(community.find(community_id)) diesel::update(community.find(community_id))
.set(new_community) .set(new_community)
@ -62,7 +64,8 @@ impl Crud<CommunityForm> for Community {
impl Community { impl Community {
pub fn read_from_name(conn: &PgConnection, community_name: String) -> Result<Self, Error> { pub fn read_from_name(conn: &PgConnection, community_name: String) -> Result<Self, Error> {
use crate::schema::community::dsl::*; use crate::schema::community::dsl::*;
community.filter(name.eq(community_name)) community
.filter(name.eq(community_name))
.first::<Self>(conn) .first::<Self>(conn)
} }
} }
@ -85,18 +88,26 @@ pub struct CommunityModeratorForm {
} }
impl Joinable<CommunityModeratorForm> for CommunityModerator { impl Joinable<CommunityModeratorForm> for CommunityModerator {
fn join(conn: &PgConnection, community_user_form: &CommunityModeratorForm) -> Result<Self, Error> { fn join(
conn: &PgConnection,
community_user_form: &CommunityModeratorForm,
) -> Result<Self, Error> {
use crate::schema::community_moderator::dsl::*; use crate::schema::community_moderator::dsl::*;
insert_into(community_moderator) insert_into(community_moderator)
.values(community_user_form) .values(community_user_form)
.get_result::<Self>(conn) .get_result::<Self>(conn)
} }
fn leave(conn: &PgConnection, community_user_form: &CommunityModeratorForm) -> Result<usize, Error> { fn leave(
conn: &PgConnection,
community_user_form: &CommunityModeratorForm,
) -> Result<usize, Error> {
use crate::schema::community_moderator::dsl::*; use crate::schema::community_moderator::dsl::*;
diesel::delete(community_moderator diesel::delete(
community_moderator
.filter(community_id.eq(community_user_form.community_id)) .filter(community_id.eq(community_user_form.community_id))
.filter(user_id.eq(community_user_form.user_id))) .filter(user_id.eq(community_user_form.user_id)),
)
.execute(conn) .execute(conn)
} }
} }
@ -104,10 +115,7 @@ impl Joinable<CommunityModeratorForm> for CommunityModerator {
impl CommunityModerator { impl CommunityModerator {
pub fn delete_for_community(conn: &PgConnection, for_community_id: i32) -> Result<usize, Error> { pub fn delete_for_community(conn: &PgConnection, for_community_id: i32) -> Result<usize, Error> {
use crate::schema::community_moderator::dsl::*; use crate::schema::community_moderator::dsl::*;
diesel::delete( diesel::delete(community_moderator.filter(community_id.eq(for_community_id))).execute(conn)
community_moderator
.filter(community_id.eq(for_community_id)))
.execute(conn)
} }
} }
@ -129,18 +137,26 @@ pub struct CommunityUserBanForm {
} }
impl Bannable<CommunityUserBanForm> for CommunityUserBan { impl Bannable<CommunityUserBanForm> for CommunityUserBan {
fn ban(conn: &PgConnection, community_user_ban_form: &CommunityUserBanForm) -> Result<Self, Error> { fn ban(
conn: &PgConnection,
community_user_ban_form: &CommunityUserBanForm,
) -> Result<Self, Error> {
use crate::schema::community_user_ban::dsl::*; use crate::schema::community_user_ban::dsl::*;
insert_into(community_user_ban) insert_into(community_user_ban)
.values(community_user_ban_form) .values(community_user_ban_form)
.get_result::<Self>(conn) .get_result::<Self>(conn)
} }
fn unban(conn: &PgConnection, community_user_ban_form: &CommunityUserBanForm) -> Result<usize, Error> { fn unban(
conn: &PgConnection,
community_user_ban_form: &CommunityUserBanForm,
) -> Result<usize, Error> {
use crate::schema::community_user_ban::dsl::*; use crate::schema::community_user_ban::dsl::*;
diesel::delete(community_user_ban diesel::delete(
community_user_ban
.filter(community_id.eq(community_user_ban_form.community_id)) .filter(community_id.eq(community_user_ban_form.community_id))
.filter(user_id.eq(community_user_ban_form.user_id))) .filter(user_id.eq(community_user_ban_form.user_id)),
)
.execute(conn) .execute(conn)
} }
} }
@ -163,17 +179,25 @@ pub struct CommunityFollowerForm {
} }
impl Followable<CommunityFollowerForm> for CommunityFollower { impl Followable<CommunityFollowerForm> for CommunityFollower {
fn follow(conn: &PgConnection, community_follower_form: &CommunityFollowerForm) -> Result<Self, Error> { fn follow(
conn: &PgConnection,
community_follower_form: &CommunityFollowerForm,
) -> Result<Self, Error> {
use crate::schema::community_follower::dsl::*; use crate::schema::community_follower::dsl::*;
insert_into(community_follower) insert_into(community_follower)
.values(community_follower_form) .values(community_follower_form)
.get_result::<Self>(conn) .get_result::<Self>(conn)
} }
fn ignore(conn: &PgConnection, community_follower_form: &CommunityFollowerForm) -> Result<usize, Error> { fn ignore(
conn: &PgConnection,
community_follower_form: &CommunityFollowerForm,
) -> Result<usize, Error> {
use crate::schema::community_follower::dsl::*; use crate::schema::community_follower::dsl::*;
diesel::delete(community_follower diesel::delete(
community_follower
.filter(community_id.eq(&community_follower_form.community_id)) .filter(community_id.eq(&community_follower_form.community_id))
.filter(user_id.eq(&community_follower_form.user_id))) .filter(user_id.eq(&community_follower_form.user_id)),
)
.execute(conn) .execute(conn)
} }
} }
@ -186,7 +210,7 @@ pub struct Site {
pub description: Option<String>, pub description: Option<String>,
pub creator_id: i32, pub creator_id: i32,
pub published: chrono::NaiveDateTime, pub published: chrono::NaiveDateTime,
pub updated: Option<chrono::NaiveDateTime> pub updated: Option<chrono::NaiveDateTime>,
} }
#[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize)] #[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize)]
@ -195,7 +219,7 @@ pub struct SiteForm {
pub name: String, pub name: String,
pub description: Option<String>, pub description: Option<String>,
pub creator_id: i32, pub creator_id: i32,
pub updated: Option<chrono::NaiveDateTime> pub updated: Option<chrono::NaiveDateTime>,
} }
impl Crud<SiteForm> for Site { impl Crud<SiteForm> for Site {
@ -206,15 +230,12 @@ impl Crud<SiteForm> for Site {
fn delete(conn: &PgConnection, site_id: i32) -> Result<usize, Error> { fn delete(conn: &PgConnection, site_id: i32) -> Result<usize, Error> {
use crate::schema::site::dsl::*; use crate::schema::site::dsl::*;
diesel::delete(site.find(site_id)) diesel::delete(site.find(site_id)).execute(conn)
.execute(conn)
} }
fn create(conn: &PgConnection, new_site: &SiteForm) -> Result<Self, Error> { fn create(conn: &PgConnection, new_site: &SiteForm) -> Result<Self, Error> {
use crate::schema::site::dsl::*; use crate::schema::site::dsl::*;
insert_into(site) insert_into(site).values(new_site).get_result::<Self>(conn)
.values(new_site)
.get_result::<Self>(conn)
} }
fn update(conn: &PgConnection, site_id: i32, new_site: &SiteForm) -> Result<Self, Error> { fn update(conn: &PgConnection, site_id: i32, new_site: &SiteForm) -> Result<Self, Error> {
@ -227,8 +248,8 @@ impl Crud<SiteForm> for Site {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
use super::super::user::*; use super::super::user::*;
use super::*;
#[test] #[test]
fn test_crud() { fn test_crud() {
let conn = establish_connection(); let conn = establish_connection();
@ -272,27 +293,27 @@ mod tests {
removed: false, removed: false,
deleted: false, deleted: false,
published: inserted_community.published, published: inserted_community.published,
updated: None updated: None,
}; };
let community_follower_form = CommunityFollowerForm { let community_follower_form = CommunityFollowerForm {
community_id: inserted_community.id, community_id: inserted_community.id,
user_id: inserted_user.id user_id: inserted_user.id,
}; };
let inserted_community_follower = CommunityFollower::follow(&conn, &community_follower_form).unwrap(); let inserted_community_follower =
CommunityFollower::follow(&conn, &community_follower_form).unwrap();
let expected_community_follower = CommunityFollower { let expected_community_follower = CommunityFollower {
id: inserted_community_follower.id, id: inserted_community_follower.id,
community_id: inserted_community.id, community_id: inserted_community.id,
user_id: inserted_user.id, user_id: inserted_user.id,
published: inserted_community_follower.published published: inserted_community_follower.published,
}; };
let community_user_form = CommunityModeratorForm { let community_user_form = CommunityModeratorForm {
community_id: inserted_community.id, community_id: inserted_community.id,
user_id: inserted_user.id user_id: inserted_user.id,
}; };
let inserted_community_user = CommunityModerator::join(&conn, &community_user_form).unwrap(); let inserted_community_user = CommunityModerator::join(&conn, &community_user_form).unwrap();
@ -301,25 +322,27 @@ mod tests {
id: inserted_community_user.id, id: inserted_community_user.id,
community_id: inserted_community.id, community_id: inserted_community.id,
user_id: inserted_user.id, user_id: inserted_user.id,
published: inserted_community_user.published published: inserted_community_user.published,
}; };
let community_user_ban_form = CommunityUserBanForm { let community_user_ban_form = CommunityUserBanForm {
community_id: inserted_community.id, community_id: inserted_community.id,
user_id: inserted_user.id user_id: inserted_user.id,
}; };
let inserted_community_user_ban = CommunityUserBan::ban(&conn, &community_user_ban_form).unwrap(); let inserted_community_user_ban =
CommunityUserBan::ban(&conn, &community_user_ban_form).unwrap();
let expected_community_user_ban = CommunityUserBan { let expected_community_user_ban = CommunityUserBan {
id: inserted_community_user_ban.id, id: inserted_community_user_ban.id,
community_id: inserted_community.id, community_id: inserted_community.id,
user_id: inserted_user.id, user_id: inserted_user.id,
published: inserted_community_user_ban.published published: inserted_community_user_ban.published,
}; };
let read_community = Community::read(&conn, inserted_community.id).unwrap(); let read_community = Community::read(&conn, inserted_community.id).unwrap();
let updated_community = Community::update(&conn, inserted_community.id, &new_community).unwrap(); let updated_community =
Community::update(&conn, inserted_community.id, &new_community).unwrap();
let ignored_community = CommunityFollower::ignore(&conn, &community_follower_form).unwrap(); let ignored_community = CommunityFollower::ignore(&conn, &community_follower_form).unwrap();
let left_community = CommunityModerator::leave(&conn, &community_user_form).unwrap(); let left_community = CommunityModerator::leave(&conn, &community_user_form).unwrap();
let unban = CommunityUserBan::unban(&conn, &community_user_ban_form).unwrap(); let unban = CommunityUserBan::unban(&conn, &community_user_ban_form).unwrap();
@ -337,6 +360,5 @@ mod tests {
assert_eq!(1, unban); assert_eq!(1, unban);
// assert_eq!(2, loaded_count); // assert_eq!(2, loaded_count);
assert_eq!(1, num_deleted); assert_eq!(1, num_deleted);
} }
} }

View file

@ -73,7 +73,9 @@ table! {
} }
} }
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)] #[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "community_view"] #[table_name = "community_view"]
pub struct CommunityView { pub struct CommunityView {
pub id: i32, pub id: i32,
@ -98,7 +100,11 @@ pub struct CommunityView {
} }
impl CommunityView { impl CommunityView {
pub fn read(conn: &PgConnection, from_community_id: i32, from_user_id: Option<i32>) -> Result<Self, Error> { pub fn read(
conn: &PgConnection,
from_community_id: i32,
from_user_id: Option<i32>,
) -> Result<Self, Error> {
use super::community_view::community_view::dsl::*; use super::community_view::community_view::dsl::*;
let mut query = community_view.into_boxed(); let mut query = community_view.into_boxed();
@ -135,17 +141,26 @@ impl CommunityView {
// The view lets you pass a null user_id, if you're not logged in // The view lets you pass a null user_id, if you're not logged in
match sort { match sort {
SortType::Hot => query = query.order_by(hot_rank.desc()) SortType::Hot => {
query = query
.order_by(hot_rank.desc())
.then_order_by(number_of_subscribers.desc()) .then_order_by(number_of_subscribers.desc())
.filter(user_id.is_null()), .filter(user_id.is_null())
}
SortType::New => query = query.order_by(published.desc()).filter(user_id.is_null()), SortType::New => query = query.order_by(published.desc()).filter(user_id.is_null()),
SortType::TopAll => { SortType::TopAll => match from_user_id {
match from_user_id { Some(from_user_id) => {
Some(from_user_id) => query = query.filter(user_id.eq(from_user_id)).order_by((subscribed.asc(), number_of_subscribers.desc())), query = query
None => query = query.order_by(number_of_subscribers.desc()).filter(user_id.is_null()) .filter(user_id.eq(from_user_id))
.order_by((subscribed.asc(), number_of_subscribers.desc()))
} }
None => {
query = query
.order_by(number_of_subscribers.desc())
.filter(user_id.is_null())
} }
_ => () },
_ => (),
}; };
if !show_nsfw { if !show_nsfw {
@ -161,8 +176,9 @@ impl CommunityView {
} }
} }
#[derive(
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)] Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "community_moderator_view"] #[table_name = "community_moderator_view"]
pub struct CommunityModeratorView { pub struct CommunityModeratorView {
pub id: i32, pub id: i32,
@ -176,16 +192,22 @@ pub struct CommunityModeratorView {
impl CommunityModeratorView { impl CommunityModeratorView {
pub fn for_community(conn: &PgConnection, from_community_id: i32) -> Result<Vec<Self>, Error> { pub fn for_community(conn: &PgConnection, from_community_id: i32) -> Result<Vec<Self>, Error> {
use super::community_view::community_moderator_view::dsl::*; use super::community_view::community_moderator_view::dsl::*;
community_moderator_view.filter(community_id.eq(from_community_id)).load::<Self>(conn) community_moderator_view
.filter(community_id.eq(from_community_id))
.load::<Self>(conn)
} }
pub fn for_user(conn: &PgConnection, from_user_id: i32) -> Result<Vec<Self>, Error> { pub fn for_user(conn: &PgConnection, from_user_id: i32) -> Result<Vec<Self>, Error> {
use super::community_view::community_moderator_view::dsl::*; use super::community_view::community_moderator_view::dsl::*;
community_moderator_view.filter(user_id.eq(from_user_id)).load::<Self>(conn) community_moderator_view
.filter(user_id.eq(from_user_id))
.load::<Self>(conn)
} }
} }
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)] #[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "community_follower_view"] #[table_name = "community_follower_view"]
pub struct CommunityFollowerView { pub struct CommunityFollowerView {
pub id: i32, pub id: i32,
@ -199,17 +221,22 @@ pub struct CommunityFollowerView {
impl CommunityFollowerView { impl CommunityFollowerView {
pub fn for_community(conn: &PgConnection, from_community_id: i32) -> Result<Vec<Self>, Error> { pub fn for_community(conn: &PgConnection, from_community_id: i32) -> Result<Vec<Self>, Error> {
use super::community_view::community_follower_view::dsl::*; use super::community_view::community_follower_view::dsl::*;
community_follower_view.filter(community_id.eq(from_community_id)).load::<Self>(conn) community_follower_view
.filter(community_id.eq(from_community_id))
.load::<Self>(conn)
} }
pub fn for_user(conn: &PgConnection, from_user_id: i32) -> Result<Vec<Self>, Error> { pub fn for_user(conn: &PgConnection, from_user_id: i32) -> Result<Vec<Self>, Error> {
use super::community_view::community_follower_view::dsl::*; use super::community_view::community_follower_view::dsl::*;
community_follower_view.filter(user_id.eq(from_user_id)).load::<Self>(conn) community_follower_view
.filter(user_id.eq(from_user_id))
.load::<Self>(conn)
} }
} }
#[derive(
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)] Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "community_user_ban_view"] #[table_name = "community_user_ban_view"]
pub struct CommunityUserBanView { pub struct CommunityUserBanView {
pub id: i32, pub id: i32,
@ -223,15 +250,23 @@ pub struct CommunityUserBanView {
impl CommunityUserBanView { impl CommunityUserBanView {
pub fn for_community(conn: &PgConnection, from_community_id: i32) -> Result<Vec<Self>, Error> { pub fn for_community(conn: &PgConnection, from_community_id: i32) -> Result<Vec<Self>, Error> {
use super::community_view::community_user_ban_view::dsl::*; use super::community_view::community_user_ban_view::dsl::*;
community_user_ban_view.filter(community_id.eq(from_community_id)).load::<Self>(conn) community_user_ban_view
.filter(community_id.eq(from_community_id))
.load::<Self>(conn)
} }
pub fn for_user(conn: &PgConnection, from_user_id: i32) -> Result<Vec<Self>, Error> { pub fn for_user(conn: &PgConnection, from_user_id: i32) -> Result<Vec<Self>, Error> {
use super::community_view::community_user_ban_view::dsl::*; use super::community_view::community_user_ban_view::dsl::*;
community_user_ban_view.filter(user_id.eq(from_user_id)).load::<Self>(conn) community_user_ban_view
.filter(user_id.eq(from_user_id))
.load::<Self>(conn)
} }
pub fn get(conn: &PgConnection, from_user_id: i32, from_community_id: i32) -> Result<Self, Error> { pub fn get(
conn: &PgConnection,
from_user_id: i32,
from_community_id: i32,
) -> Result<Self, Error> {
use super::community_view::community_user_ban_view::dsl::*; use super::community_view::community_user_ban_view::dsl::*;
community_user_ban_view community_user_ban_view
.filter(user_id.eq(from_user_id)) .filter(user_id.eq(from_user_id))
@ -240,8 +275,9 @@ impl CommunityUserBanView {
} }
} }
#[derive(
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)] Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "site_view"] #[table_name = "site_view"]
pub struct SiteView { pub struct SiteView {
pub id: i32, pub id: i32,

View file

@ -1,73 +1,117 @@
use diesel::*; use crate::Settings;
use diesel::dsl::*; use diesel::dsl::*;
use diesel::result::Error; use diesel::result::Error;
use crate::{Settings}; use diesel::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub mod user;
pub mod community;
pub mod post;
pub mod comment;
pub mod post_view;
pub mod comment_view;
pub mod category; pub mod category;
pub mod comment;
pub mod comment_view;
pub mod community;
pub mod community_view; pub mod community_view;
pub mod user_view;
pub mod moderator; pub mod moderator;
pub mod moderator_views; pub mod moderator_views;
pub mod post;
pub mod post_view;
pub mod user;
pub mod user_view;
pub trait Crud<T> { pub trait Crud<T> {
fn create(conn: &PgConnection, form: &T) -> Result<Self, Error> where Self: Sized; fn create(conn: &PgConnection, form: &T) -> Result<Self, Error>
fn read(conn: &PgConnection, id: i32) -> Result<Self, Error> where Self: Sized; where
fn update(conn: &PgConnection, id: i32, form: &T) -> Result<Self, Error> where Self: Sized; Self: Sized;
fn delete(conn: &PgConnection, id: i32) -> Result<usize, Error> where Self: Sized; fn read(conn: &PgConnection, id: i32) -> Result<Self, Error>
where
Self: Sized;
fn update(conn: &PgConnection, id: i32, form: &T) -> Result<Self, Error>
where
Self: Sized;
fn delete(conn: &PgConnection, id: i32) -> Result<usize, Error>
where
Self: Sized;
} }
pub trait Followable<T> { pub trait Followable<T> {
fn follow(conn: &PgConnection, form: &T) -> Result<Self, Error> where Self: Sized; fn follow(conn: &PgConnection, form: &T) -> Result<Self, Error>
fn ignore(conn: &PgConnection, form: &T) -> Result<usize, Error> where Self: Sized; where
Self: Sized;
fn ignore(conn: &PgConnection, form: &T) -> Result<usize, Error>
where
Self: Sized;
} }
pub trait Joinable<T> { pub trait Joinable<T> {
fn join(conn: &PgConnection, form: &T) -> Result<Self, Error> where Self: Sized; fn join(conn: &PgConnection, form: &T) -> Result<Self, Error>
fn leave(conn: &PgConnection, form: &T) -> Result<usize, Error> where Self: Sized; where
Self: Sized;
fn leave(conn: &PgConnection, form: &T) -> Result<usize, Error>
where
Self: Sized;
} }
pub trait Likeable<T> { pub trait Likeable<T> {
fn read(conn: &PgConnection, id: i32) -> Result<Vec<Self>, Error> where Self: Sized; fn read(conn: &PgConnection, id: i32) -> Result<Vec<Self>, Error>
fn like(conn: &PgConnection, form: &T) -> Result<Self, Error> where Self: Sized; where
fn remove(conn: &PgConnection, form: &T) -> Result<usize, Error> where Self: Sized; Self: Sized;
fn like(conn: &PgConnection, form: &T) -> Result<Self, Error>
where
Self: Sized;
fn remove(conn: &PgConnection, form: &T) -> Result<usize, Error>
where
Self: Sized;
} }
pub trait Bannable<T> { pub trait Bannable<T> {
fn ban(conn: &PgConnection, form: &T) -> Result<Self, Error> where Self: Sized; fn ban(conn: &PgConnection, form: &T) -> Result<Self, Error>
fn unban(conn: &PgConnection, form: &T) -> Result<usize, Error> where Self: Sized; where
Self: Sized;
fn unban(conn: &PgConnection, form: &T) -> Result<usize, Error>
where
Self: Sized;
} }
pub trait Saveable<T> { pub trait Saveable<T> {
fn save(conn: &PgConnection, form: &T) -> Result<Self, Error> where Self: Sized; fn save(conn: &PgConnection, form: &T) -> Result<Self, Error>
fn unsave(conn: &PgConnection, form: &T) -> Result<usize, Error> where Self: Sized; where
Self: Sized;
fn unsave(conn: &PgConnection, form: &T) -> Result<usize, Error>
where
Self: Sized;
} }
pub trait Readable<T> { pub trait Readable<T> {
fn mark_as_read(conn: &PgConnection, form: &T) -> Result<Self, Error> where Self: Sized; fn mark_as_read(conn: &PgConnection, form: &T) -> Result<Self, Error>
fn mark_as_unread(conn: &PgConnection, form: &T) -> Result<usize, Error> where Self: Sized; where
Self: Sized;
fn mark_as_unread(conn: &PgConnection, form: &T) -> Result<usize, Error>
where
Self: Sized;
} }
pub fn establish_connection() -> PgConnection { pub fn establish_connection() -> PgConnection {
let db_url = Settings::get().db_url; let db_url = Settings::get().db_url;
PgConnection::establish(&db_url) PgConnection::establish(&db_url).expect(&format!("Error connecting to {}", db_url))
.expect(&format!("Error connecting to {}", db_url))
} }
#[derive(EnumString, ToString, Debug, Serialize, Deserialize)] #[derive(EnumString, ToString, Debug, Serialize, Deserialize)]
pub enum SortType { pub enum SortType {
Hot, New, TopDay, TopWeek, TopMonth, TopYear, TopAll Hot,
New,
TopDay,
TopWeek,
TopMonth,
TopYear,
TopAll,
} }
#[derive(EnumString, ToString, Debug, Serialize, Deserialize)] #[derive(EnumString, ToString, Debug, Serialize, Deserialize)]
pub enum SearchType { pub enum SearchType {
All, Comments, Posts, Communities, Users, Url All,
Comments,
Posts,
Communities,
Users,
Url,
} }
pub fn fuzzy_search(q: &str) -> String { pub fn fuzzy_search(q: &str) -> String {
@ -84,9 +128,9 @@ pub fn limit_and_offset(page: Option<i64>, limit: Option<i64>) -> (i64, i64) {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::fuzzy_search; use super::fuzzy_search;
#[test] fn test_fuzzy_search() { #[test]
fn test_fuzzy_search() {
let test = "This is a fuzzy search"; let test = "This is a fuzzy search";
assert_eq!(fuzzy_search(test), "%This%is%a%fuzzy%search%".to_string()); assert_eq!(fuzzy_search(test), "%This%is%a%fuzzy%search%".to_string());
} }
} }

View file

@ -1,5 +1,8 @@
use crate::schema::{mod_remove_post, mod_lock_post, mod_remove_comment, mod_remove_community, mod_ban_from_community, mod_ban, mod_add_community, mod_add};
use super::*; use super::*;
use crate::schema::{
mod_add, mod_add_community, mod_ban, mod_ban_from_community, mod_lock_post, mod_remove_comment,
mod_remove_community, mod_remove_post,
};
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)] #[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
#[table_name = "mod_remove_post"] #[table_name = "mod_remove_post"]
@ -24,14 +27,12 @@ pub struct ModRemovePostForm {
impl Crud<ModRemovePostForm> for ModRemovePost { impl Crud<ModRemovePostForm> for ModRemovePost {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> { fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_remove_post::dsl::*; use crate::schema::mod_remove_post::dsl::*;
mod_remove_post.find(from_id) mod_remove_post.find(from_id).first::<Self>(conn)
.first::<Self>(conn)
} }
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> { fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
use crate::schema::mod_remove_post::dsl::*; use crate::schema::mod_remove_post::dsl::*;
diesel::delete(mod_remove_post.find(from_id)) diesel::delete(mod_remove_post.find(from_id)).execute(conn)
.execute(conn)
} }
fn create(conn: &PgConnection, form: &ModRemovePostForm) -> Result<Self, Error> { fn create(conn: &PgConnection, form: &ModRemovePostForm) -> Result<Self, Error> {
@ -49,8 +50,6 @@ impl Crud<ModRemovePostForm> for ModRemovePost {
} }
} }
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)] #[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
#[table_name = "mod_lock_post"] #[table_name = "mod_lock_post"]
pub struct ModLockPost { pub struct ModLockPost {
@ -72,14 +71,12 @@ pub struct ModLockPostForm {
impl Crud<ModLockPostForm> for ModLockPost { impl Crud<ModLockPostForm> for ModLockPost {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> { fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_lock_post::dsl::*; use crate::schema::mod_lock_post::dsl::*;
mod_lock_post.find(from_id) mod_lock_post.find(from_id).first::<Self>(conn)
.first::<Self>(conn)
} }
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> { fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
use crate::schema::mod_lock_post::dsl::*; use crate::schema::mod_lock_post::dsl::*;
diesel::delete(mod_lock_post.find(from_id)) diesel::delete(mod_lock_post.find(from_id)).execute(conn)
.execute(conn)
} }
fn create(conn: &PgConnection, form: &ModLockPostForm) -> Result<Self, Error> { fn create(conn: &PgConnection, form: &ModLockPostForm) -> Result<Self, Error> {
@ -120,14 +117,12 @@ pub struct ModRemoveCommentForm {
impl Crud<ModRemoveCommentForm> for ModRemoveComment { impl Crud<ModRemoveCommentForm> for ModRemoveComment {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> { fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_remove_comment::dsl::*; use crate::schema::mod_remove_comment::dsl::*;
mod_remove_comment.find(from_id) mod_remove_comment.find(from_id).first::<Self>(conn)
.first::<Self>(conn)
} }
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> { fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
use crate::schema::mod_remove_comment::dsl::*; use crate::schema::mod_remove_comment::dsl::*;
diesel::delete(mod_remove_comment.find(from_id)) diesel::delete(mod_remove_comment.find(from_id)).execute(conn)
.execute(conn)
} }
fn create(conn: &PgConnection, form: &ModRemoveCommentForm) -> Result<Self, Error> { fn create(conn: &PgConnection, form: &ModRemoveCommentForm) -> Result<Self, Error> {
@ -170,14 +165,12 @@ pub struct ModRemoveCommunityForm {
impl Crud<ModRemoveCommunityForm> for ModRemoveCommunity { impl Crud<ModRemoveCommunityForm> for ModRemoveCommunity {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> { fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_remove_community::dsl::*; use crate::schema::mod_remove_community::dsl::*;
mod_remove_community.find(from_id) mod_remove_community.find(from_id).first::<Self>(conn)
.first::<Self>(conn)
} }
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> { fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
use crate::schema::mod_remove_community::dsl::*; use crate::schema::mod_remove_community::dsl::*;
diesel::delete(mod_remove_community.find(from_id)) diesel::delete(mod_remove_community.find(from_id)).execute(conn)
.execute(conn)
} }
fn create(conn: &PgConnection, form: &ModRemoveCommunityForm) -> Result<Self, Error> { fn create(conn: &PgConnection, form: &ModRemoveCommunityForm) -> Result<Self, Error> {
@ -187,7 +180,11 @@ impl Crud<ModRemoveCommunityForm> for ModRemoveCommunity {
.get_result::<Self>(conn) .get_result::<Self>(conn)
} }
fn update(conn: &PgConnection, from_id: i32, form: &ModRemoveCommunityForm) -> Result<Self, Error> { fn update(
conn: &PgConnection,
from_id: i32,
form: &ModRemoveCommunityForm,
) -> Result<Self, Error> {
use crate::schema::mod_remove_community::dsl::*; use crate::schema::mod_remove_community::dsl::*;
diesel::update(mod_remove_community.find(from_id)) diesel::update(mod_remove_community.find(from_id))
.set(form) .set(form)
@ -222,14 +219,12 @@ pub struct ModBanFromCommunityForm {
impl Crud<ModBanFromCommunityForm> for ModBanFromCommunity { impl Crud<ModBanFromCommunityForm> for ModBanFromCommunity {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> { fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_ban_from_community::dsl::*; use crate::schema::mod_ban_from_community::dsl::*;
mod_ban_from_community.find(from_id) mod_ban_from_community.find(from_id).first::<Self>(conn)
.first::<Self>(conn)
} }
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> { fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
use crate::schema::mod_ban_from_community::dsl::*; use crate::schema::mod_ban_from_community::dsl::*;
diesel::delete(mod_ban_from_community.find(from_id)) diesel::delete(mod_ban_from_community.find(from_id)).execute(conn)
.execute(conn)
} }
fn create(conn: &PgConnection, form: &ModBanFromCommunityForm) -> Result<Self, Error> { fn create(conn: &PgConnection, form: &ModBanFromCommunityForm) -> Result<Self, Error> {
@ -239,7 +234,11 @@ impl Crud<ModBanFromCommunityForm> for ModBanFromCommunity {
.get_result::<Self>(conn) .get_result::<Self>(conn)
} }
fn update(conn: &PgConnection, from_id: i32, form: &ModBanFromCommunityForm) -> Result<Self, Error> { fn update(
conn: &PgConnection,
from_id: i32,
form: &ModBanFromCommunityForm,
) -> Result<Self, Error> {
use crate::schema::mod_ban_from_community::dsl::*; use crate::schema::mod_ban_from_community::dsl::*;
diesel::update(mod_ban_from_community.find(from_id)) diesel::update(mod_ban_from_community.find(from_id))
.set(form) .set(form)
@ -247,7 +246,6 @@ impl Crud<ModBanFromCommunityForm> for ModBanFromCommunity {
} }
} }
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)] #[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
#[table_name = "mod_ban"] #[table_name = "mod_ban"]
pub struct ModBan { pub struct ModBan {
@ -273,21 +271,17 @@ pub struct ModBanForm {
impl Crud<ModBanForm> for ModBan { impl Crud<ModBanForm> for ModBan {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> { fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_ban::dsl::*; use crate::schema::mod_ban::dsl::*;
mod_ban.find(from_id) mod_ban.find(from_id).first::<Self>(conn)
.first::<Self>(conn)
} }
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> { fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
use crate::schema::mod_ban::dsl::*; use crate::schema::mod_ban::dsl::*;
diesel::delete(mod_ban.find(from_id)) diesel::delete(mod_ban.find(from_id)).execute(conn)
.execute(conn)
} }
fn create(conn: &PgConnection, form: &ModBanForm) -> Result<Self, Error> { fn create(conn: &PgConnection, form: &ModBanForm) -> Result<Self, Error> {
use crate::schema::mod_ban::dsl::*; use crate::schema::mod_ban::dsl::*;
insert_into(mod_ban) insert_into(mod_ban).values(form).get_result::<Self>(conn)
.values(form)
.get_result::<Self>(conn)
} }
fn update(conn: &PgConnection, from_id: i32, form: &ModBanForm) -> Result<Self, Error> { fn update(conn: &PgConnection, from_id: i32, form: &ModBanForm) -> Result<Self, Error> {
@ -321,14 +315,12 @@ pub struct ModAddCommunityForm {
impl Crud<ModAddCommunityForm> for ModAddCommunity { impl Crud<ModAddCommunityForm> for ModAddCommunity {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> { fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_add_community::dsl::*; use crate::schema::mod_add_community::dsl::*;
mod_add_community.find(from_id) mod_add_community.find(from_id).first::<Self>(conn)
.first::<Self>(conn)
} }
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> { fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
use crate::schema::mod_add_community::dsl::*; use crate::schema::mod_add_community::dsl::*;
diesel::delete(mod_add_community.find(from_id)) diesel::delete(mod_add_community.find(from_id)).execute(conn)
.execute(conn)
} }
fn create(conn: &PgConnection, form: &ModAddCommunityForm) -> Result<Self, Error> { fn create(conn: &PgConnection, form: &ModAddCommunityForm) -> Result<Self, Error> {
@ -367,21 +359,17 @@ pub struct ModAddForm {
impl Crud<ModAddForm> for ModAdd { impl Crud<ModAddForm> for ModAdd {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> { fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_add::dsl::*; use crate::schema::mod_add::dsl::*;
mod_add.find(from_id) mod_add.find(from_id).first::<Self>(conn)
.first::<Self>(conn)
} }
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> { fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
use crate::schema::mod_add::dsl::*; use crate::schema::mod_add::dsl::*;
diesel::delete(mod_add.find(from_id)) diesel::delete(mod_add.find(from_id)).execute(conn)
.execute(conn)
} }
fn create(conn: &PgConnection, form: &ModAddForm) -> Result<Self, Error> { fn create(conn: &PgConnection, form: &ModAddForm) -> Result<Self, Error> {
use crate::schema::mod_add::dsl::*; use crate::schema::mod_add::dsl::*;
insert_into(mod_add) insert_into(mod_add).values(form).get_result::<Self>(conn)
.values(form)
.get_result::<Self>(conn)
} }
fn update(conn: &PgConnection, from_id: i32, form: &ModAddForm) -> Result<Self, Error> { fn update(conn: &PgConnection, from_id: i32, form: &ModAddForm) -> Result<Self, Error> {
@ -394,11 +382,11 @@ impl Crud<ModAddForm> for ModAdd {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
use super::super::user::*;
use super::super::post::*;
use super::super::community::*;
use super::super::comment::*; use super::super::comment::*;
use super::super::community::*;
use super::super::post::*;
use super::super::user::*;
use super::*;
// use Crud; // use Crud;
#[test] #[test]
fn test_crud() { fn test_crud() {
@ -469,7 +457,7 @@ mod tests {
deleted: None, deleted: None,
read: None, read: None,
parent_id: None, parent_id: None,
updated: None updated: None,
}; };
let inserted_comment = Comment::create(&conn, &comment_form).unwrap(); let inserted_comment = Comment::create(&conn, &comment_form).unwrap();
@ -484,7 +472,8 @@ mod tests {
removed: None, removed: None,
}; };
let inserted_mod_remove_post = ModRemovePost::create(&conn, &mod_remove_post_form).unwrap(); let inserted_mod_remove_post = ModRemovePost::create(&conn, &mod_remove_post_form).unwrap();
let read_moderator_remove_post = ModRemovePost::read(&conn, inserted_mod_remove_post.id).unwrap(); let read_moderator_remove_post =
ModRemovePost::read(&conn, inserted_mod_remove_post.id).unwrap();
let expected_moderator_remove_post = ModRemovePost { let expected_moderator_remove_post = ModRemovePost {
id: inserted_mod_remove_post.id, id: inserted_mod_remove_post.id,
post_id: inserted_post.id, post_id: inserted_post.id,
@ -519,8 +508,10 @@ mod tests {
reason: None, reason: None,
removed: None, removed: None,
}; };
let inserted_mod_remove_comment = ModRemoveComment::create(&conn, &mod_remove_comment_form).unwrap(); let inserted_mod_remove_comment =
let read_moderator_remove_comment = ModRemoveComment::read(&conn, inserted_mod_remove_comment.id).unwrap(); ModRemoveComment::create(&conn, &mod_remove_comment_form).unwrap();
let read_moderator_remove_comment =
ModRemoveComment::read(&conn, inserted_mod_remove_comment.id).unwrap();
let expected_moderator_remove_comment = ModRemoveComment { let expected_moderator_remove_comment = ModRemoveComment {
id: inserted_mod_remove_comment.id, id: inserted_mod_remove_comment.id,
comment_id: inserted_comment.id, comment_id: inserted_comment.id,
@ -539,8 +530,10 @@ mod tests {
removed: None, removed: None,
expires: None, expires: None,
}; };
let inserted_mod_remove_community = ModRemoveCommunity::create(&conn, &mod_remove_community_form).unwrap(); let inserted_mod_remove_community =
let read_moderator_remove_community = ModRemoveCommunity::read(&conn, inserted_mod_remove_community.id).unwrap(); ModRemoveCommunity::create(&conn, &mod_remove_community_form).unwrap();
let read_moderator_remove_community =
ModRemoveCommunity::read(&conn, inserted_mod_remove_community.id).unwrap();
let expected_moderator_remove_community = ModRemoveCommunity { let expected_moderator_remove_community = ModRemoveCommunity {
id: inserted_mod_remove_community.id, id: inserted_mod_remove_community.id,
community_id: inserted_community.id, community_id: inserted_community.id,
@ -561,8 +554,10 @@ mod tests {
banned: None, banned: None,
expires: None, expires: None,
}; };
let inserted_mod_ban_from_community = ModBanFromCommunity::create(&conn, &mod_ban_from_community_form).unwrap(); let inserted_mod_ban_from_community =
let read_moderator_ban_from_community = ModBanFromCommunity::read(&conn, inserted_mod_ban_from_community.id).unwrap(); ModBanFromCommunity::create(&conn, &mod_ban_from_community_form).unwrap();
let read_moderator_ban_from_community =
ModBanFromCommunity::read(&conn, inserted_mod_ban_from_community.id).unwrap();
let expected_moderator_ban_from_community = ModBanFromCommunity { let expected_moderator_ban_from_community = ModBanFromCommunity {
id: inserted_mod_ban_from_community.id, id: inserted_mod_ban_from_community.id,
community_id: inserted_community.id, community_id: inserted_community.id,
@ -603,8 +598,10 @@ mod tests {
community_id: inserted_community.id, community_id: inserted_community.id,
removed: None, removed: None,
}; };
let inserted_mod_add_community = ModAddCommunity::create(&conn, &mod_add_community_form).unwrap(); let inserted_mod_add_community =
let read_moderator_add_community = ModAddCommunity::read(&conn, inserted_mod_add_community.id).unwrap(); ModAddCommunity::create(&conn, &mod_add_community_form).unwrap();
let read_moderator_add_community =
ModAddCommunity::read(&conn, inserted_mod_add_community.id).unwrap();
let expected_moderator_add_community = ModAddCommunity { let expected_moderator_add_community = ModAddCommunity {
id: inserted_mod_add_community.id, id: inserted_mod_add_community.id,
community_id: inserted_community.id, community_id: inserted_community.id,
@ -648,11 +645,23 @@ mod tests {
assert_eq!(expected_moderator_remove_post, read_moderator_remove_post); assert_eq!(expected_moderator_remove_post, read_moderator_remove_post);
assert_eq!(expected_moderator_lock_post, read_moderator_lock_post); assert_eq!(expected_moderator_lock_post, read_moderator_lock_post);
assert_eq!(expected_moderator_remove_comment, read_moderator_remove_comment); assert_eq!(
assert_eq!(expected_moderator_remove_community, read_moderator_remove_community); expected_moderator_remove_comment,
assert_eq!(expected_moderator_ban_from_community, read_moderator_ban_from_community); read_moderator_remove_comment
);
assert_eq!(
expected_moderator_remove_community,
read_moderator_remove_community
);
assert_eq!(
expected_moderator_ban_from_community,
read_moderator_ban_from_community
);
assert_eq!(expected_moderator_ban, read_moderator_ban); assert_eq!(expected_moderator_ban, read_moderator_ban);
assert_eq!(expected_moderator_add_community, read_moderator_add_community); assert_eq!(
expected_moderator_add_community,
read_moderator_add_community
);
assert_eq!(expected_moderator_add, read_moderator_add); assert_eq!(expected_moderator_add, read_moderator_add);
} }
} }

View file

@ -15,7 +15,9 @@ table! {
} }
} }
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)] #[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "mod_remove_post_view"] #[table_name = "mod_remove_post_view"]
pub struct ModRemovePostView { pub struct ModRemovePostView {
pub id: i32, pub id: i32,
@ -31,7 +33,8 @@ pub struct ModRemovePostView {
} }
impl ModRemovePostView { impl ModRemovePostView {
pub fn list(conn: &PgConnection, pub fn list(
conn: &PgConnection,
from_community_id: Option<i32>, from_community_id: Option<i32>,
from_mod_user_id: Option<i32>, from_mod_user_id: Option<i32>,
page: Option<i64>, page: Option<i64>,
@ -50,7 +53,11 @@ impl ModRemovePostView {
query = query.filter(mod_user_id.eq(from_mod_user_id)); query = query.filter(mod_user_id.eq(from_mod_user_id));
}; };
query.limit(limit).offset(offset).order_by(when_.desc()).load::<Self>(conn) query
.limit(limit)
.offset(offset)
.order_by(when_.desc())
.load::<Self>(conn)
} }
} }
@ -68,8 +75,9 @@ table! {
} }
} }
#[derive(
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)] Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "mod_lock_post_view"] #[table_name = "mod_lock_post_view"]
pub struct ModLockPostView { pub struct ModLockPostView {
pub id: i32, pub id: i32,
@ -84,7 +92,8 @@ pub struct ModLockPostView {
} }
impl ModLockPostView { impl ModLockPostView {
pub fn list(conn: &PgConnection, pub fn list(
conn: &PgConnection,
from_community_id: Option<i32>, from_community_id: Option<i32>,
from_mod_user_id: Option<i32>, from_mod_user_id: Option<i32>,
page: Option<i64>, page: Option<i64>,
@ -103,7 +112,11 @@ impl ModLockPostView {
query = query.filter(mod_user_id.eq(from_mod_user_id)); query = query.filter(mod_user_id.eq(from_mod_user_id));
}; };
query.limit(limit).offset(offset).order_by(when_.desc()).load::<Self>(conn) query
.limit(limit)
.offset(offset)
.order_by(when_.desc())
.load::<Self>(conn)
} }
} }
@ -126,7 +139,9 @@ table! {
} }
} }
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)] #[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "mod_remove_comment_view"] #[table_name = "mod_remove_comment_view"]
pub struct ModRemoveCommentView { pub struct ModRemoveCommentView {
pub id: i32, pub id: i32,
@ -146,7 +161,8 @@ pub struct ModRemoveCommentView {
} }
impl ModRemoveCommentView { impl ModRemoveCommentView {
pub fn list(conn: &PgConnection, pub fn list(
conn: &PgConnection,
from_community_id: Option<i32>, from_community_id: Option<i32>,
from_mod_user_id: Option<i32>, from_mod_user_id: Option<i32>,
page: Option<i64>, page: Option<i64>,
@ -165,7 +181,11 @@ impl ModRemoveCommentView {
query = query.filter(mod_user_id.eq(from_mod_user_id)); query = query.filter(mod_user_id.eq(from_mod_user_id));
}; };
query.limit(limit).offset(offset).order_by(when_.desc()).load::<Self>(conn) query
.limit(limit)
.offset(offset)
.order_by(when_.desc())
.load::<Self>(conn)
} }
} }
@ -183,7 +203,9 @@ table! {
} }
} }
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)] #[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "mod_remove_community_view"] #[table_name = "mod_remove_community_view"]
pub struct ModRemoveCommunityView { pub struct ModRemoveCommunityView {
pub id: i32, pub id: i32,
@ -198,7 +220,8 @@ pub struct ModRemoveCommunityView {
} }
impl ModRemoveCommunityView { impl ModRemoveCommunityView {
pub fn list(conn: &PgConnection, pub fn list(
conn: &PgConnection,
from_mod_user_id: Option<i32>, from_mod_user_id: Option<i32>,
page: Option<i64>, page: Option<i64>,
limit: Option<i64>, limit: Option<i64>,
@ -212,11 +235,14 @@ impl ModRemoveCommunityView {
query = query.filter(mod_user_id.eq(from_mod_user_id)); query = query.filter(mod_user_id.eq(from_mod_user_id));
}; };
query.limit(limit).offset(offset).order_by(when_.desc()).load::<Self>(conn) query
.limit(limit)
.offset(offset)
.order_by(when_.desc())
.load::<Self>(conn)
} }
} }
table! { table! {
mod_ban_from_community_view (id) { mod_ban_from_community_view (id) {
id -> Int4, id -> Int4,
@ -233,7 +259,9 @@ table! {
} }
} }
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)] #[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "mod_ban_from_community_view"] #[table_name = "mod_ban_from_community_view"]
pub struct ModBanFromCommunityView { pub struct ModBanFromCommunityView {
pub id: i32, pub id: i32,
@ -250,7 +278,8 @@ pub struct ModBanFromCommunityView {
} }
impl ModBanFromCommunityView { impl ModBanFromCommunityView {
pub fn list(conn: &PgConnection, pub fn list(
conn: &PgConnection,
from_community_id: Option<i32>, from_community_id: Option<i32>,
from_mod_user_id: Option<i32>, from_mod_user_id: Option<i32>,
page: Option<i64>, page: Option<i64>,
@ -269,7 +298,11 @@ impl ModBanFromCommunityView {
query = query.filter(mod_user_id.eq(from_mod_user_id)); query = query.filter(mod_user_id.eq(from_mod_user_id));
}; };
query.limit(limit).offset(offset).order_by(when_.desc()).load::<Self>(conn) query
.limit(limit)
.offset(offset)
.order_by(when_.desc())
.load::<Self>(conn)
} }
} }
@ -287,7 +320,9 @@ table! {
} }
} }
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)] #[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "mod_ban_view"] #[table_name = "mod_ban_view"]
pub struct ModBanView { pub struct ModBanView {
pub id: i32, pub id: i32,
@ -302,7 +337,8 @@ pub struct ModBanView {
} }
impl ModBanView { impl ModBanView {
pub fn list(conn: &PgConnection, pub fn list(
conn: &PgConnection,
from_mod_user_id: Option<i32>, from_mod_user_id: Option<i32>,
page: Option<i64>, page: Option<i64>,
limit: Option<i64>, limit: Option<i64>,
@ -316,7 +352,11 @@ impl ModBanView {
query = query.filter(mod_user_id.eq(from_mod_user_id)); query = query.filter(mod_user_id.eq(from_mod_user_id));
}; };
query.limit(limit).offset(offset).order_by(when_.desc()).load::<Self>(conn) query
.limit(limit)
.offset(offset)
.order_by(when_.desc())
.load::<Self>(conn)
} }
} }
@ -334,7 +374,9 @@ table! {
} }
} }
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)] #[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "mod_add_community_view"] #[table_name = "mod_add_community_view"]
pub struct ModAddCommunityView { pub struct ModAddCommunityView {
pub id: i32, pub id: i32,
@ -349,7 +391,8 @@ pub struct ModAddCommunityView {
} }
impl ModAddCommunityView { impl ModAddCommunityView {
pub fn list(conn: &PgConnection, pub fn list(
conn: &PgConnection,
from_community_id: Option<i32>, from_community_id: Option<i32>,
from_mod_user_id: Option<i32>, from_mod_user_id: Option<i32>,
page: Option<i64>, page: Option<i64>,
@ -368,7 +411,11 @@ impl ModAddCommunityView {
query = query.filter(mod_user_id.eq(from_mod_user_id)); query = query.filter(mod_user_id.eq(from_mod_user_id));
}; };
query.limit(limit).offset(offset).order_by(when_.desc()).load::<Self>(conn) query
.limit(limit)
.offset(offset)
.order_by(when_.desc())
.load::<Self>(conn)
} }
} }
@ -384,7 +431,9 @@ table! {
} }
} }
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)] #[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "mod_add_view"] #[table_name = "mod_add_view"]
pub struct ModAddView { pub struct ModAddView {
pub id: i32, pub id: i32,
@ -397,7 +446,8 @@ pub struct ModAddView {
} }
impl ModAddView { impl ModAddView {
pub fn list(conn: &PgConnection, pub fn list(
conn: &PgConnection,
from_mod_user_id: Option<i32>, from_mod_user_id: Option<i32>,
page: Option<i64>, page: Option<i64>,
limit: Option<i64>, limit: Option<i64>,
@ -411,6 +461,10 @@ impl ModAddView {
query = query.filter(mod_user_id.eq(from_mod_user_id)); query = query.filter(mod_user_id.eq(from_mod_user_id));
}; };
query.limit(limit).offset(offset).order_by(when_.desc()).load::<Self>(conn) query
.limit(limit)
.offset(offset)
.order_by(when_.desc())
.load::<Self>(conn)
} }
} }

View file

@ -1,5 +1,5 @@
use crate::schema::{post, post_like, post_saved, post_read};
use super::*; use super::*;
use crate::schema::{post, post_like, post_read, post_saved};
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)] #[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
#[table_name = "post"] #[table_name = "post"]
@ -36,21 +36,17 @@ pub struct PostForm {
impl Crud<PostForm> for Post { impl Crud<PostForm> for Post {
fn read(conn: &PgConnection, post_id: i32) -> Result<Self, Error> { fn read(conn: &PgConnection, post_id: i32) -> Result<Self, Error> {
use crate::schema::post::dsl::*; use crate::schema::post::dsl::*;
post.find(post_id) post.find(post_id).first::<Self>(conn)
.first::<Self>(conn)
} }
fn delete(conn: &PgConnection, post_id: i32) -> Result<usize, Error> { fn delete(conn: &PgConnection, post_id: i32) -> Result<usize, Error> {
use crate::schema::post::dsl::*; use crate::schema::post::dsl::*;
diesel::delete(post.find(post_id)) diesel::delete(post.find(post_id)).execute(conn)
.execute(conn)
} }
fn create(conn: &PgConnection, new_post: &PostForm) -> Result<Self, Error> { fn create(conn: &PgConnection, new_post: &PostForm) -> Result<Self, Error> {
use crate::schema::post::dsl::*; use crate::schema::post::dsl::*;
insert_into(post) insert_into(post).values(new_post).get_result::<Self>(conn)
.values(new_post)
.get_result::<Self>(conn)
} }
fn update(conn: &PgConnection, post_id: i32, new_post: &PostForm) -> Result<Self, Error> { fn update(conn: &PgConnection, post_id: i32, new_post: &PostForm) -> Result<Self, Error> {
@ -77,7 +73,7 @@ pub struct PostLike {
pub struct PostLikeForm { pub struct PostLikeForm {
pub post_id: i32, pub post_id: i32,
pub user_id: i32, pub user_id: i32,
pub score: i16 pub score: i16,
} }
impl Likeable<PostLikeForm> for PostLike { impl Likeable<PostLikeForm> for PostLike {
@ -95,9 +91,11 @@ impl Likeable <PostLikeForm> for PostLike {
} }
fn remove(conn: &PgConnection, post_like_form: &PostLikeForm) -> Result<usize, Error> { fn remove(conn: &PgConnection, post_like_form: &PostLikeForm) -> Result<usize, Error> {
use crate::schema::post_like::dsl::*; use crate::schema::post_like::dsl::*;
diesel::delete(post_like diesel::delete(
post_like
.filter(post_id.eq(post_like_form.post_id)) .filter(post_id.eq(post_like_form.post_id))
.filter(user_id.eq(post_like_form.user_id))) .filter(user_id.eq(post_like_form.user_id)),
)
.execute(conn) .execute(conn)
} }
} }
@ -128,9 +126,11 @@ impl Saveable <PostSavedForm> for PostSaved {
} }
fn unsave(conn: &PgConnection, post_saved_form: &PostSavedForm) -> Result<usize, Error> { fn unsave(conn: &PgConnection, post_saved_form: &PostSavedForm) -> Result<usize, Error> {
use crate::schema::post_saved::dsl::*; use crate::schema::post_saved::dsl::*;
diesel::delete(post_saved diesel::delete(
post_saved
.filter(post_id.eq(post_saved_form.post_id)) .filter(post_id.eq(post_saved_form.post_id))
.filter(user_id.eq(post_saved_form.user_id))) .filter(user_id.eq(post_saved_form.user_id)),
)
.execute(conn) .execute(conn)
} }
} }
@ -161,18 +161,20 @@ impl Readable <PostReadForm> for PostRead {
} }
fn mark_as_unread(conn: &PgConnection, post_read_form: &PostReadForm) -> Result<usize, Error> { fn mark_as_unread(conn: &PgConnection, post_read_form: &PostReadForm) -> Result<usize, Error> {
use crate::schema::post_read::dsl::*; use crate::schema::post_read::dsl::*;
diesel::delete(post_read diesel::delete(
post_read
.filter(post_id.eq(post_read_form.post_id)) .filter(post_id.eq(post_read_form.post_id))
.filter(user_id.eq(post_read_form.user_id))) .filter(user_id.eq(post_read_form.user_id)),
)
.execute(conn) .execute(conn)
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
use super::super::community::*; use super::super::community::*;
use super::super::user::*; use super::super::user::*;
use super::*;
#[test] #[test]
fn test_crud() { fn test_crud() {
let conn = establish_connection(); let conn = establish_connection();
@ -215,7 +217,7 @@ mod tests {
deleted: None, deleted: None,
locked: None, locked: None,
nsfw: false, nsfw: false,
updated: None updated: None,
}; };
let inserted_post = Post::create(&conn, &new_post).unwrap(); let inserted_post = Post::create(&conn, &new_post).unwrap();
@ -232,14 +234,14 @@ mod tests {
locked: false, locked: false,
nsfw: false, nsfw: false,
deleted: false, deleted: false,
updated: None updated: None,
}; };
// Post Like // Post Like
let post_like_form = PostLikeForm { let post_like_form = PostLikeForm {
post_id: inserted_post.id, post_id: inserted_post.id,
user_id: inserted_user.id, user_id: inserted_user.id,
score: 1 score: 1,
}; };
let inserted_post_like = PostLike::like(&conn, &post_like_form).unwrap(); let inserted_post_like = PostLike::like(&conn, &post_like_form).unwrap();
@ -249,7 +251,7 @@ mod tests {
post_id: inserted_post.id, post_id: inserted_post.id,
user_id: inserted_user.id, user_id: inserted_user.id,
published: inserted_post_like.published, published: inserted_post_like.published,
score: 1 score: 1,
}; };
// Post Save // Post Save
@ -301,6 +303,5 @@ mod tests {
assert_eq!(1, saved_removed); assert_eq!(1, saved_removed);
assert_eq!(1, read_removed); assert_eq!(1, read_removed);
assert_eq!(1, num_deleted); assert_eq!(1, num_deleted);
} }
} }

View file

@ -2,7 +2,9 @@ use super::*;
#[derive(EnumString, ToString, Debug, Serialize, Deserialize)] #[derive(EnumString, ToString, Debug, Serialize, Deserialize)]
pub enum PostListingType { pub enum PostListingType {
All, Subscribed, Community All,
Subscribed,
Community,
} }
// The faked schema since diesel doesn't do views // The faked schema since diesel doesn't do views
@ -40,8 +42,9 @@ table! {
} }
} }
#[derive(
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)] Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "post_view"] #[table_name = "post_view"]
pub struct PostView { pub struct PostView {
pub id: i32, pub id: i32,
@ -125,7 +128,7 @@ impl PostView {
match type_ { match type_ {
PostListingType::Subscribed => { PostListingType::Subscribed => {
query = query.filter(subscribed.eq(true)); query = query.filter(subscribed.eq(true));
}, }
_ => {} _ => {}
}; };
@ -143,7 +146,8 @@ impl PostView {
}; };
query = match sort { query = match sort {
SortType::Hot => query.order_by(hot_rank.desc()) SortType::Hot => query
.order_by(hot_rank.desc())
.then_order_by(published.desc()), .then_order_by(published.desc()),
SortType::New => query.order_by(published.desc()), SortType::New => query.order_by(published.desc()),
SortType::TopAll => query.order_by(score.desc()), SortType::TopAll => query.order_by(score.desc()),
@ -158,7 +162,7 @@ impl PostView {
.order_by(score.desc()), .order_by(score.desc()),
SortType::TopDay => query SortType::TopDay => query
.filter(published.gt(now - 1.days())) .filter(published.gt(now - 1.days()))
.order_by(score.desc()) .order_by(score.desc()),
}; };
query = query query = query
@ -172,9 +176,11 @@ impl PostView {
query.load::<Self>(conn) query.load::<Self>(conn)
} }
pub fn read(
pub fn read(conn: &PgConnection, from_post_id: i32, my_user_id: Option<i32>) -> Result<Self, Error> { conn: &PgConnection,
from_post_id: i32,
my_user_id: Option<i32>,
) -> Result<Self, Error> {
use super::post_view::post_view::dsl::*; use super::post_view::post_view::dsl::*;
use diesel::prelude::*; use diesel::prelude::*;
@ -192,14 +198,12 @@ impl PostView {
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
use super::super::community::*; use super::super::community::*;
use super::super::user::*;
use super::super::post::*; use super::super::post::*;
use super::super::user::*;
use super::*;
#[test] #[test]
fn test_crud() { fn test_crud() {
let conn = establish_connection(); let conn = establish_connection();
@ -254,7 +258,7 @@ mod tests {
let post_like_form = PostLikeForm { let post_like_form = PostLikeForm {
post_id: inserted_post.id, post_id: inserted_post.id,
user_id: inserted_user.id, user_id: inserted_user.id,
score: 1 score: 1,
}; };
let inserted_post_like = PostLike::like(&conn, &post_like_form).unwrap(); let inserted_post_like = PostLike::like(&conn, &post_like_form).unwrap();
@ -264,13 +268,13 @@ mod tests {
post_id: inserted_post.id, post_id: inserted_post.id,
user_id: inserted_user.id, user_id: inserted_user.id,
published: inserted_post_like.published, published: inserted_post_like.published,
score: 1 score: 1,
}; };
let post_like_form = PostLikeForm { let post_like_form = PostLikeForm {
post_id: inserted_post.id, post_id: inserted_post.id,
user_id: inserted_user.id, user_id: inserted_user.id,
score: 1 score: 1,
}; };
// the non user version // the non user version
@ -338,7 +342,6 @@ mod tests {
nsfw: false, nsfw: false,
}; };
let read_post_listings_with_user = PostView::list( let read_post_listings_with_user = PostView::list(
&conn, &conn,
PostListingType::Community, PostListingType::Community,
@ -352,7 +355,9 @@ mod tests {
false, false,
false, false,
None, None,
None).unwrap(); None,
)
.unwrap();
let read_post_listings_no_user = PostView::list( let read_post_listings_no_user = PostView::list(
&conn, &conn,
PostListingType::Community, PostListingType::Community,
@ -366,9 +371,12 @@ mod tests {
false, false,
false, false,
None, None,
None).unwrap(); None,
)
.unwrap();
let read_post_listing_no_user = PostView::read(&conn, inserted_post.id, None).unwrap(); let read_post_listing_no_user = PostView::read(&conn, inserted_post.id, None).unwrap();
let read_post_listing_with_user = PostView::read(&conn, inserted_post.id, Some(inserted_user.id)).unwrap(); let read_post_listing_with_user =
PostView::read(&conn, inserted_post.id, Some(inserted_user.id)).unwrap();
let like_removed = PostLike::remove(&conn, &post_like_form).unwrap(); let like_removed = PostLike::remove(&conn, &post_like_form).unwrap();
let num_deleted = Post::delete(&conn, inserted_post.id).unwrap(); let num_deleted = Post::delete(&conn, inserted_post.id).unwrap();
@ -376,7 +384,10 @@ mod tests {
User_::delete(&conn, inserted_user.id).unwrap(); User_::delete(&conn, inserted_user.id).unwrap();
// The with user // The with user
assert_eq!(expected_post_listing_with_user, read_post_listings_with_user[0]); assert_eq!(
expected_post_listing_with_user,
read_post_listings_with_user[0]
);
assert_eq!(expected_post_listing_with_user, read_post_listing_with_user); assert_eq!(expected_post_listing_with_user, read_post_listing_with_user);
assert_eq!(1, read_post_listings_with_user.len()); assert_eq!(1, read_post_listings_with_user.len());

View file

@ -1,9 +1,9 @@
use super::*;
use crate::schema::user_; use crate::schema::user_;
use crate::schema::user_::dsl::*; use crate::schema::user_::dsl::*;
use super::*; use crate::{is_email_regex, Settings};
use crate::{Settings, is_email_regex}; use bcrypt::{hash, DEFAULT_COST};
use jsonwebtoken::{encode, decode, Header, Validation, TokenData}; use jsonwebtoken::{decode, encode, Header, TokenData, Validation};
use bcrypt::{DEFAULT_COST, hash};
#[derive(Queryable, Identifiable, PartialEq, Debug)] #[derive(Queryable, Identifiable, PartialEq, Debug)]
#[table_name = "user_"] #[table_name = "user_"]
@ -39,17 +39,13 @@ pub struct UserForm {
impl Crud<UserForm> for User_ { impl Crud<UserForm> for User_ {
fn read(conn: &PgConnection, user_id: i32) -> Result<Self, Error> { fn read(conn: &PgConnection, user_id: i32) -> Result<Self, Error> {
use crate::schema::user_::dsl::*; use crate::schema::user_::dsl::*;
user_.find(user_id) user_.find(user_id).first::<Self>(conn)
.first::<Self>(conn)
} }
fn delete(conn: &PgConnection, user_id: i32) -> Result<usize, Error> { fn delete(conn: &PgConnection, user_id: i32) -> Result<usize, Error> {
diesel::delete(user_.find(user_id)) diesel::delete(user_.find(user_id)).execute(conn)
.execute(conn)
} }
fn create(conn: &PgConnection, form: &UserForm) -> Result<Self, Error> { fn create(conn: &PgConnection, form: &UserForm) -> Result<Self, Error> {
insert_into(user_) insert_into(user_).values(form).get_result::<Self>(conn)
.values(form)
.get_result::<Self>(conn)
} }
fn update(conn: &PgConnection, user_id: i32, form: &UserForm) -> Result<Self, Error> { fn update(conn: &PgConnection, user_id: i32, form: &UserForm) -> Result<Self, Error> {
diesel::update(user_.find(user_id)) diesel::update(user_.find(user_id))
@ -61,16 +57,14 @@ impl Crud<UserForm> for User_ {
impl User_ { impl User_ {
pub fn register(conn: &PgConnection, form: &UserForm) -> Result<Self, Error> { pub fn register(conn: &PgConnection, form: &UserForm) -> Result<Self, Error> {
let mut edited_user = form.clone(); let mut edited_user = form.clone();
let password_hash = hash(&form.password_encrypted, DEFAULT_COST) let password_hash =
.expect("Couldn't hash password"); hash(&form.password_encrypted, DEFAULT_COST).expect("Couldn't hash password");
edited_user.password_encrypted = password_hash; edited_user.password_encrypted = password_hash;
Self::create(&conn, &edited_user) Self::create(&conn, &edited_user)
} }
pub fn read_from_name(conn: &PgConnection, from_user_name: String) -> Result<Self, Error> { pub fn read_from_name(conn: &PgConnection, from_user_name: String) -> Result<Self, Error> {
user_.filter(name.eq(from_user_name)) user_.filter(name.eq(from_user_name)).first::<Self>(conn)
.first::<Self>(conn)
} }
} }
@ -101,15 +95,25 @@ impl User_ {
iss: self.fedi_name.to_owned(), iss: self.fedi_name.to_owned(),
show_nsfw: self.show_nsfw, show_nsfw: self.show_nsfw,
}; };
encode(&Header::default(), &my_claims, Settings::get().jwt_secret.as_ref()).unwrap() encode(
&Header::default(),
&my_claims,
Settings::get().jwt_secret.as_ref(),
)
.unwrap()
} }
pub fn find_by_email_or_username(conn: &PgConnection, username_or_email: &str) -> Result<Self, Error> { pub fn find_by_email_or_username(
conn: &PgConnection,
username_or_email: &str,
) -> Result<Self, Error> {
if is_email_regex(username_or_email) { if is_email_regex(username_or_email) {
user_.filter(email.eq(username_or_email)) user_
.filter(email.eq(username_or_email))
.first::<User_>(conn) .first::<User_>(conn)
} else { } else {
user_.filter(name.eq(username_or_email)) user_
.filter(name.eq(username_or_email))
.first::<User_>(conn) .first::<User_>(conn)
} }
} }
@ -118,10 +122,8 @@ impl User_ {
let claims: Claims = Claims::decode(&jwt).expect("Invalid token").claims; let claims: Claims = Claims::decode(&jwt).expect("Invalid token").claims;
Self::read(&conn, claims.id) Self::read(&conn, claims.id)
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View file

@ -15,7 +15,9 @@ table! {
} }
} }
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)] #[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "user_view"] #[table_name = "user_view"]
pub struct UserView { pub struct UserView {
pub id: i32, pub id: i32,
@ -31,8 +33,8 @@ pub struct UserView {
} }
impl UserView { impl UserView {
pub fn list(
pub fn list(conn: &PgConnection, conn: &PgConnection,
sort: &SortType, sort: &SortType,
search_term: Option<String>, search_term: Option<String>,
page: Option<i64>, page: Option<i64>,
@ -49,7 +51,8 @@ impl UserView {
}; };
query = match sort { query = match sort {
SortType::Hot => query.order_by(comment_score.desc()) SortType::Hot => query
.order_by(comment_score.desc())
.then_order_by(published.desc()), .then_order_by(published.desc()),
SortType::New => query.order_by(published.desc()), SortType::New => query.order_by(published.desc()),
SortType::TopAll => query.order_by(comment_score.desc()), SortType::TopAll => query.order_by(comment_score.desc()),
@ -64,12 +67,10 @@ impl UserView {
.order_by(comment_score.desc()), .order_by(comment_score.desc()),
SortType::TopDay => query SortType::TopDay => query
.filter(published.gt(now - 1.days())) .filter(published.gt(now - 1.days()))
.order_by(comment_score.desc()) .order_by(comment_score.desc()),
}; };
query = query query = query.limit(limit).offset(offset);
.limit(limit)
.offset(offset);
query.load::<Self>(conn) query.load::<Self>(conn)
} }
@ -77,20 +78,16 @@ impl UserView {
pub fn read(conn: &PgConnection, from_user_id: i32) -> Result<Self, Error> { pub fn read(conn: &PgConnection, from_user_id: i32) -> Result<Self, Error> {
use super::user_view::user_view::dsl::*; use super::user_view::user_view::dsl::*;
user_view.find(from_user_id) user_view.find(from_user_id).first::<Self>(conn)
.first::<Self>(conn)
} }
pub fn admins(conn: &PgConnection) -> Result<Vec<Self>, Error> { pub fn admins(conn: &PgConnection) -> Result<Vec<Self>, Error> {
use super::user_view::user_view::dsl::*; use super::user_view::user_view::dsl::*;
user_view.filter(admin.eq(true)) user_view.filter(admin.eq(true)).load::<Self>(conn)
.load::<Self>(conn)
} }
pub fn banned(conn: &PgConnection) -> Result<Vec<Self>, Error> { pub fn banned(conn: &PgConnection) -> Result<Vec<Self>, Error> {
use super::user_view::user_view::dsl::*; use super::user_view::user_view::dsl::*;
user_view.filter(banned.eq(true)) user_view.filter(banned.eq(true)).load::<Self>(conn)
.load::<Self>(conn)
} }
} }

View file

@ -1,30 +1,34 @@
#![recursion_limit = "512"] #![recursion_limit = "512"]
#[macro_use] pub extern crate strum_macros; #[macro_use]
#[macro_use] pub extern crate lazy_static; pub extern crate strum_macros;
#[macro_use] pub extern crate failure; #[macro_use]
#[macro_use] pub extern crate diesel; pub extern crate lazy_static;
pub extern crate dotenv; #[macro_use]
pub extern crate chrono; pub extern crate failure;
pub extern crate serde; #[macro_use]
pub extern crate serde_json; pub extern crate diesel;
pub extern crate actix; pub extern crate actix;
pub extern crate actix_web; pub extern crate actix_web;
pub extern crate rand;
pub extern crate strum;
pub extern crate jsonwebtoken;
pub extern crate bcrypt; pub extern crate bcrypt;
pub extern crate chrono;
pub extern crate dotenv;
pub extern crate jsonwebtoken;
pub extern crate rand;
pub extern crate regex; pub extern crate regex;
pub extern crate serde;
pub extern crate serde_json;
pub extern crate strum;
pub mod schema;
pub mod api; pub mod api;
pub mod apub; pub mod apub;
pub mod db; pub mod db;
pub mod schema;
pub mod websocket; pub mod websocket;
use dotenv::dotenv;
use std::env;
use regex::Regex;
use chrono::{DateTime, NaiveDateTime, Utc}; use chrono::{DateTime, NaiveDateTime, Utc};
use dotenv::dotenv;
use regex::Regex;
use std::env;
pub struct Settings { pub struct Settings {
db_url: String, db_url: String,
@ -36,8 +40,7 @@ impl Settings {
fn get() -> Self { fn get() -> Self {
dotenv().ok(); dotenv().ok();
Settings { Settings {
db_url: env::var("DATABASE_URL") db_url: env::var("DATABASE_URL").expect("DATABASE_URL must be set"),
.expect("DATABASE_URL must be set"),
hostname: env::var("HOSTNAME").unwrap_or("rrr".to_string()), hostname: env::var("HOSTNAME").unwrap_or("rrr".to_string()),
jwt_secret: env::var("JWT_SECRET").unwrap_or("changeme".to_string()), jwt_secret: env::var("JWT_SECRET").unwrap_or("changeme".to_string()),
} }
@ -73,21 +76,27 @@ pub fn has_slurs(test: &str) -> bool {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{Settings, is_email_regex, remove_slurs, has_slurs}; use crate::{has_slurs, is_email_regex, remove_slurs, Settings};
#[test] #[test]
fn test_api() { fn test_api() {
assert_eq!(Settings::get().api_endpoint(), "rrr/api/v1"); assert_eq!(Settings::get().api_endpoint(), "rrr/api/v1");
} }
#[test] fn test_email() { #[test]
fn test_email() {
assert!(is_email_regex("gush@gmail.com")); assert!(is_email_regex("gush@gmail.com"));
assert!(!is_email_regex("nada_neutho")); assert!(!is_email_regex("nada_neutho"));
} }
#[test] fn test_slur_filter() { #[test]
fn test_slur_filter() {
let test = "coons test dindu ladyboy tranny. This is a bunch of other safe text.".to_string(); let test = "coons test dindu ladyboy tranny. This is a bunch of other safe text.".to_string();
let slur_free = "No slurs here"; let slur_free = "No slurs here";
assert_eq!(remove_slurs(&test), "*removed* test *removed* *removed* *removed*. This is a bunch of other safe text.".to_string()); assert_eq!(
remove_slurs(&test),
"*removed* test *removed* *removed* *removed*. This is a bunch of other safe text."
.to_string()
);
assert!(has_slurs(&test)); assert!(has_slurs(&test));
assert!(!has_slurs(slur_free)); assert!(!has_slurs(slur_free));
} }

View file

@ -67,7 +67,8 @@ impl Actor for WSSession {
// before processing any other events. // before processing any other events.
// across all routes within application // across all routes within application
let addr = ctx.address(); let addr = ctx.address();
self.cs_addr self
.cs_addr
.send(Connect { .send(Connect {
addr: addr.recipient(), addr: addr.recipient(),
ip: self.ip.to_owned(), ip: self.ip.to_owned(),
@ -121,7 +122,8 @@ impl StreamHandler<ws::Message, ws::ProtocolError> for WSSession {
let m = text.trim().to_owned(); let m = text.trim().to_owned();
println!("WEBSOCKET MESSAGE: {:?} from id: {}", &m, self.id); println!("WEBSOCKET MESSAGE: {:?} from id: {}", &m, self.id);
self.cs_addr self
.cs_addr
.send(StandardMessage { .send(StandardMessage {
id: self.id, id: self.id,
msg: m, msg: m,

View file

@ -3,20 +3,20 @@
//! room through `ChatServer`. //! room through `ChatServer`.
use actix::prelude::*; use actix::prelude::*;
use rand::{rngs::ThreadRng, Rng};
use std::collections::{HashMap, HashSet};
use serde::{Deserialize, Serialize};
use serde_json::{Value};
use std::str::FromStr;
use failure::Error; use failure::Error;
use std::time::{SystemTime}; use rand::{rngs::ThreadRng, Rng};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::{HashMap, HashSet};
use std::str::FromStr;
use std::time::SystemTime;
use crate::api::*; use crate::api::comment::*;
use crate::api::user::*;
use crate::api::community::*; use crate::api::community::*;
use crate::api::post::*; use crate::api::post::*;
use crate::api::comment::*;
use crate::api::site::*; use crate::api::site::*;
use crate::api::user::*;
use crate::api::*;
const RATE_LIMIT_MESSAGE: i32 = 30; const RATE_LIMIT_MESSAGE: i32 = 30;
const RATE_LIMIT_MESSAGES_PER_SECOND: i32 = 60; const RATE_LIMIT_MESSAGES_PER_SECOND: i32 = 60;
@ -25,7 +25,6 @@ const RATE_LIMIT_POSTS_PER_SECOND: i32 = 60*10;
const RATE_LIMIT_REGISTER: i32 = 1; const RATE_LIMIT_REGISTER: i32 = 1;
const RATE_LIMIT_REGISTER_PER_SECOND: i32 = 60 * 60; const RATE_LIMIT_REGISTER_PER_SECOND: i32 = 60 * 60;
/// Chat server sends this messages to session /// Chat server sends this messages to session
#[derive(Message)] #[derive(Message)]
pub struct WSMessage(pub String); pub struct WSMessage(pub String);
@ -73,7 +72,7 @@ impl actix::Message for StandardMessage {
#[derive(Debug)] #[derive(Debug)]
pub struct RateLimitBucket { pub struct RateLimitBucket {
last_checked: SystemTime, last_checked: SystemTime,
allowance: f64 allowance: f64,
} }
pub struct SessionInfo { pub struct SessionInfo {
@ -132,9 +131,14 @@ impl ChatServer {
&self.rooms.get_mut(&room_id).unwrap().insert(id); &self.rooms.get_mut(&room_id).unwrap().insert(id);
} }
fn send_community_message(&self, community_id: &i32, message: &str, skip_id: usize) -> Result<(), Error> { fn send_community_message(
use crate::db::*; &self,
community_id: &i32,
message: &str,
skip_id: usize,
) -> Result<(), Error> {
use crate::db::post_view::*; use crate::db::post_view::*;
use crate::db::*;
let conn = establish_connection(); let conn = establish_connection();
let posts = PostView::list( let posts = PostView::list(
&conn, &conn,
@ -149,7 +153,8 @@ impl ChatServer {
false, false,
false, false,
None, None,
Some(9999))?; Some(9999),
)?;
for post in posts { for post in posts {
self.send_room_message(&post.id, message, skip_id); self.send_room_message(&post.id, message, skip_id);
} }
@ -186,7 +191,10 @@ impl ChatServer {
} }
if rate_limit.allowance < 1.0 { if rate_limit.allowance < 1.0 {
println!("Rate limited IP: {}, time_passed: {}, allowance: {}", &info.ip, time_passed, rate_limit.allowance); println!(
"Rate limited IP: {}, time_passed: {}, allowance: {}",
&info.ip, time_passed, rate_limit.allowance
);
Err(APIError { Err(APIError {
op: "Rate Limit".to_string(), op: "Rate Limit".to_string(),
message: format!("Too many requests. {} per {} seconds", rate, per), message: format!("Too many requests. {} per {} seconds", rate, per),
@ -204,7 +212,6 @@ impl ChatServer {
} }
} }
/// Make actor from `ChatServer` /// Make actor from `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
@ -219,7 +226,6 @@ 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 Context<Self>) -> Self::Result {
// notify all users in same room // notify all users in same room
// self.send_room_message(&"Main".to_owned(), "Someone joined", 0); // self.send_room_message(&"Main".to_owned(), "Someone joined", 0);
@ -227,16 +233,22 @@ impl Handler<Connect> for ChatServer {
let id = self.rng.gen::<usize>(); let id = self.rng.gen::<usize>();
println!("{} joined", &msg.ip); println!("{} joined", &msg.ip);
self.sessions.insert(id, SessionInfo { self.sessions.insert(
id,
SessionInfo {
addr: msg.addr, addr: msg.addr,
ip: msg.ip.to_owned(), ip: msg.ip.to_owned(),
}); },
);
if self.rate_limits.get(&msg.ip).is_none() { if self.rate_limits.get(&msg.ip).is_none() {
self.rate_limits.insert(msg.ip, RateLimitBucket { self.rate_limits.insert(
msg.ip,
RateLimitBucket {
last_checked: SystemTime::now(), last_checked: SystemTime::now(),
allowance: -2f64, allowance: -2f64,
}); },
);
} }
id id
@ -248,7 +260,6 @@ 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 Context<Self>) {
// let mut rooms: Vec<i32> = Vec::new(); // let mut rooms: Vec<i32> = Vec::new();
// remove address // remove address
@ -267,12 +278,10 @@ 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 Context<Self>) -> Self::Result {
let msg_out = match parse_json_message(self, msg) { let msg_out = match parse_json_message(self, msg) {
Ok(m) => m, Ok(m) => m,
Err(e) => e.to_string() Err(e) => e.to_string(),
}; };
MessageResult(msg_out) MessageResult(msg_out)
@ -280,7 +289,6 @@ impl Handler<StandardMessage> for ChatServer {
} }
fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<String, Error> { fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<String, Error> {
let json: Value = serde_json::from_str(&msg.msg)?; let json: Value = serde_json::from_str(&msg.msg)?;
let data = &json["data"].to_string(); let data = &json["data"].to_string();
let op = &json["op"].as_str().ok_or(APIError { let op = &json["op"].as_str().ok_or(APIError {
@ -295,59 +303,59 @@ fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<Str
let login: Login = serde_json::from_str(data)?; let login: Login = serde_json::from_str(data)?;
let res = Oper::new(user_operation, login).perform()?; let res = Oper::new(user_operation, login).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::Register => { UserOperation::Register => {
chat.check_rate_limit_register(msg.id)?; chat.check_rate_limit_register(msg.id)?;
let register: Register = serde_json::from_str(data)?; let register: Register = serde_json::from_str(data)?;
let res = Oper::new(user_operation, register).perform()?; let res = Oper::new(user_operation, register).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::GetUserDetails => { UserOperation::GetUserDetails => {
let get_user_details: GetUserDetails = serde_json::from_str(data)?; let get_user_details: GetUserDetails = serde_json::from_str(data)?;
let res = Oper::new(user_operation, get_user_details).perform()?; let res = Oper::new(user_operation, get_user_details).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::SaveUserSettings => { UserOperation::SaveUserSettings => {
let save_user_settings: SaveUserSettings = serde_json::from_str(data)?; let save_user_settings: SaveUserSettings = serde_json::from_str(data)?;
let res = Oper::new(user_operation, save_user_settings).perform()?; let res = Oper::new(user_operation, save_user_settings).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
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(user_operation, add_admin).perform()?; let res = Oper::new(user_operation, add_admin).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
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(user_operation, ban_user).perform()?; let res = Oper::new(user_operation, ban_user).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::GetReplies => { UserOperation::GetReplies => {
let get_replies: GetReplies = serde_json::from_str(data)?; let get_replies: GetReplies = serde_json::from_str(data)?;
let res = Oper::new(user_operation, get_replies).perform()?; let res = Oper::new(user_operation, get_replies).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::MarkAllAsRead => { UserOperation::MarkAllAsRead => {
let mark_all_as_read: MarkAllAsRead = serde_json::from_str(data)?; let mark_all_as_read: MarkAllAsRead = serde_json::from_str(data)?;
let res = Oper::new(user_operation, mark_all_as_read).perform()?; let res = Oper::new(user_operation, mark_all_as_read).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::GetCommunity => { UserOperation::GetCommunity => {
let get_community: GetCommunity = serde_json::from_str(data)?; let get_community: GetCommunity = serde_json::from_str(data)?;
let res = Oper::new(user_operation, get_community).perform()?; let res = Oper::new(user_operation, get_community).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::ListCommunities => { UserOperation::ListCommunities => {
let list_communities: ListCommunities = serde_json::from_str(data)?; let list_communities: ListCommunities = serde_json::from_str(data)?;
let res = Oper::new(user_operation, list_communities).perform()?; let res = Oper::new(user_operation, list_communities).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::CreateCommunity => { UserOperation::CreateCommunity => {
chat.check_rate_limit_register(msg.id)?; chat.check_rate_limit_register(msg.id)?;
let create_community: CreateCommunity = serde_json::from_str(data)?; let create_community: CreateCommunity = serde_json::from_str(data)?;
let res = Oper::new(user_operation, create_community).perform()?; let res = Oper::new(user_operation, create_community).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&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(user_operation, edit_community).perform()?; let res = Oper::new(user_operation, edit_community).perform()?;
@ -357,17 +365,17 @@ fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<Str
let community_sent_str = serde_json::to_string(&community_sent)?; let community_sent_str = serde_json::to_string(&community_sent)?;
chat.send_community_message(&community_sent.community.id, &community_sent_str, msg.id)?; chat.send_community_message(&community_sent.community.id, &community_sent_str, msg.id)?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::FollowCommunity => { UserOperation::FollowCommunity => {
let follow_community: FollowCommunity = serde_json::from_str(data)?; let follow_community: FollowCommunity = serde_json::from_str(data)?;
let res = Oper::new(user_operation, follow_community).perform()?; let res = Oper::new(user_operation, follow_community).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::GetFollowedCommunities => { UserOperation::GetFollowedCommunities => {
let followed_communities: GetFollowedCommunities = serde_json::from_str(data)?; let followed_communities: GetFollowedCommunities = serde_json::from_str(data)?;
let res = Oper::new(user_operation, followed_communities).perform()?; let res = Oper::new(user_operation, followed_communities).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
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;
@ -375,7 +383,7 @@ fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<Str
let res_str = serde_json::to_string(&res)?; let res_str = serde_json::to_string(&res)?;
chat.send_community_message(&community_id, &res_str, msg.id)?; chat.send_community_message(&community_id, &res_str, msg.id)?;
Ok(res_str) Ok(res_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;
@ -383,35 +391,35 @@ fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<Str
let res_str = serde_json::to_string(&res)?; let res_str = serde_json::to_string(&res)?;
chat.send_community_message(&community_id, &res_str, msg.id)?; chat.send_community_message(&community_id, &res_str, msg.id)?;
Ok(res_str) Ok(res_str)
}, }
UserOperation::ListCategories => { UserOperation::ListCategories => {
let list_categories: ListCategories = ListCategories; let list_categories: ListCategories = ListCategories;
let res = Oper::new(user_operation, list_categories).perform()?; let res = Oper::new(user_operation, list_categories).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::CreatePost => { UserOperation::CreatePost => {
chat.check_rate_limit_post(msg.id)?; chat.check_rate_limit_post(msg.id)?;
let create_post: CreatePost = serde_json::from_str(data)?; let create_post: CreatePost = serde_json::from_str(data)?;
let res = Oper::new(user_operation, create_post).perform()?; let res = Oper::new(user_operation, create_post).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::GetPost => { UserOperation::GetPost => {
let get_post: GetPost = serde_json::from_str(data)?; let get_post: GetPost = serde_json::from_str(data)?;
chat.join_room(get_post.id, msg.id); chat.join_room(get_post.id, msg.id);
let res = Oper::new(user_operation, get_post).perform()?; let res = Oper::new(user_operation, get_post).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::GetPosts => { UserOperation::GetPosts => {
let get_posts: GetPosts = serde_json::from_str(data)?; let get_posts: GetPosts = serde_json::from_str(data)?;
let res = Oper::new(user_operation, get_posts).perform()?; let res = Oper::new(user_operation, get_posts).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::CreatePostLike => { UserOperation::CreatePostLike => {
chat.check_rate_limit_message(msg.id)?; chat.check_rate_limit_message(msg.id)?;
let create_post_like: CreatePostLike = serde_json::from_str(data)?; let create_post_like: CreatePostLike = serde_json::from_str(data)?;
let res = Oper::new(user_operation, create_post_like).perform()?; let res = Oper::new(user_operation, create_post_like).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
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(user_operation, edit_post).perform()?; let res = Oper::new(user_operation, edit_post).perform()?;
@ -420,12 +428,12 @@ fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<Str
let post_sent_str = serde_json::to_string(&post_sent)?; let post_sent_str = serde_json::to_string(&post_sent)?;
chat.send_room_message(&post_sent.post.id, &post_sent_str, msg.id); chat.send_room_message(&post_sent.post.id, &post_sent_str, msg.id);
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::SavePost => { UserOperation::SavePost => {
let save_post: SavePost = serde_json::from_str(data)?; let save_post: SavePost = serde_json::from_str(data)?;
let res = Oper::new(user_operation, save_post).perform()?; let res = Oper::new(user_operation, save_post).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::CreateComment => { UserOperation::CreateComment => {
chat.check_rate_limit_message(msg.id)?; chat.check_rate_limit_message(msg.id)?;
let create_comment: CreateComment = serde_json::from_str(data)?; let create_comment: CreateComment = serde_json::from_str(data)?;
@ -437,7 +445,7 @@ fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<Str
let comment_sent_str = serde_json::to_string(&comment_sent)?; let comment_sent_str = serde_json::to_string(&comment_sent)?;
chat.send_room_message(&post_id, &comment_sent_str, msg.id); chat.send_room_message(&post_id, &comment_sent_str, msg.id);
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::EditComment => { UserOperation::EditComment => {
let edit_comment: EditComment = serde_json::from_str(data)?; let edit_comment: EditComment = serde_json::from_str(data)?;
let post_id = edit_comment.post_id; let post_id = edit_comment.post_id;
@ -448,12 +456,12 @@ fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<Str
let comment_sent_str = serde_json::to_string(&comment_sent)?; let comment_sent_str = serde_json::to_string(&comment_sent)?;
chat.send_room_message(&post_id, &comment_sent_str, msg.id); chat.send_room_message(&post_id, &comment_sent_str, msg.id);
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::SaveComment => { UserOperation::SaveComment => {
let save_comment: SaveComment = serde_json::from_str(data)?; let save_comment: SaveComment = serde_json::from_str(data)?;
let res = Oper::new(user_operation, save_comment).perform()?; let res = Oper::new(user_operation, save_comment).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::CreateCommentLike => { UserOperation::CreateCommentLike => {
chat.check_rate_limit_message(msg.id)?; chat.check_rate_limit_message(msg.id)?;
let create_comment_like: CreateCommentLike = serde_json::from_str(data)?; let create_comment_like: CreateCommentLike = serde_json::from_str(data)?;
@ -465,41 +473,41 @@ fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<Str
let comment_sent_str = serde_json::to_string(&comment_sent)?; let comment_sent_str = serde_json::to_string(&comment_sent)?;
chat.send_room_message(&post_id, &comment_sent_str, msg.id); chat.send_room_message(&post_id, &comment_sent_str, msg.id);
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::GetModlog => { UserOperation::GetModlog => {
let get_modlog: GetModlog = serde_json::from_str(data)?; let get_modlog: GetModlog = serde_json::from_str(data)?;
let res = Oper::new(user_operation, get_modlog).perform()?; let res = Oper::new(user_operation, get_modlog).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::CreateSite => { UserOperation::CreateSite => {
let create_site: CreateSite = serde_json::from_str(data)?; let create_site: CreateSite = serde_json::from_str(data)?;
let res = Oper::new(user_operation, create_site).perform()?; let res = Oper::new(user_operation, create_site).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
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(user_operation, edit_site).perform()?; let res = Oper::new(user_operation, edit_site).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::GetSite => { UserOperation::GetSite => {
let get_site: GetSite = serde_json::from_str(data)?; let get_site: GetSite = serde_json::from_str(data)?;
let res = Oper::new(user_operation, get_site).perform()?; let res = Oper::new(user_operation, get_site).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::Search => { UserOperation::Search => {
let search: Search = serde_json::from_str(data)?; let search: Search = serde_json::from_str(data)?;
let res = Oper::new(user_operation, search).perform()?; let res = Oper::new(user_operation, search).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::TransferCommunity => { UserOperation::TransferCommunity => {
let transfer_community: TransferCommunity = serde_json::from_str(data)?; let transfer_community: TransferCommunity = serde_json::from_str(data)?;
let res = Oper::new(user_operation, transfer_community).perform()?; let res = Oper::new(user_operation, transfer_community).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
UserOperation::TransferSite => { UserOperation::TransferSite => {
let transfer_site: TransferSite = serde_json::from_str(data)?; let transfer_site: TransferSite = serde_json::from_str(data)?;
let res = Oper::new(user_operation, transfer_site).perform()?; let res = Oper::new(user_operation, transfer_site).perform()?;
Ok(serde_json::to_string(&res)?) Ok(serde_json::to_string(&res)?)
}, }
} }
} }