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

View file

@ -5,7 +5,7 @@ use std::str::FromStr;
pub struct GetCommunity {
id: Option<i32>,
name: Option<String>,
auth: Option<String>
auth: Option<String>,
}
#[derive(Serialize, Deserialize)]
@ -16,7 +16,6 @@ pub struct GetCommunityResponse {
admins: Vec<UserView>,
}
#[derive(Serialize, Deserialize)]
pub struct CreateCommunity {
name: String,
@ -24,13 +23,13 @@ pub struct CreateCommunity {
description: Option<String>,
category_id: i32,
nsfw: bool,
auth: String
auth: String,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct CommunityResponse {
op: String,
pub community: CommunityView
pub community: CommunityView,
}
#[derive(Serialize, Deserialize)]
@ -38,13 +37,13 @@ pub struct ListCommunities {
sort: String,
page: Option<i64>,
limit: Option<i64>,
auth: Option<String>
auth: Option<String>,
}
#[derive(Serialize, Deserialize)]
pub struct ListCommunitiesResponse {
op: String,
communities: Vec<CommunityView>
communities: Vec<CommunityView>,
}
#[derive(Serialize, Deserialize, Clone)]
@ -54,7 +53,7 @@ pub struct BanFromCommunity {
ban: bool,
reason: Option<String>,
expires: Option<i64>,
auth: String
auth: String,
}
#[derive(Serialize, Deserialize)]
@ -69,7 +68,7 @@ pub struct AddModToCommunity {
pub community_id: i32,
user_id: i32,
added: bool,
auth: String
auth: String,
}
#[derive(Serialize, Deserialize)]
@ -90,32 +89,32 @@ pub struct EditCommunity {
nsfw: bool,
reason: Option<String>,
expires: Option<i64>,
auth: String
auth: String,
}
#[derive(Serialize, Deserialize)]
pub struct FollowCommunity {
community_id: i32,
follow: bool,
auth: String
auth: String,
}
#[derive(Serialize, Deserialize)]
pub struct GetFollowedCommunities {
auth: String
auth: String,
}
#[derive(Serialize, Deserialize)]
pub struct GetFollowedCommunitiesResponse {
op: String,
communities: Vec<CommunityFollowerView>
communities: Vec<CommunityFollowerView>,
}
#[derive(Serialize, Deserialize)]
pub struct TransferCommunity {
community_id: i32,
user_id: i32,
auth: String
auth: String,
}
impl Perform<GetCommunityResponse> for Oper<GetCommunity> {
@ -124,35 +123,31 @@ impl Perform<GetCommunityResponse> for Oper<GetCommunity> {
let conn = establish_connection();
let user_id: Option<i32> = match &data.auth {
Some(auth) => {
match Claims::decode(&auth) {
Some(auth) => match Claims::decode(&auth) {
Ok(claims) => {
let user_id = claims.claims.id;
Some(user_id)
}
Err(_e) => None
}
}
None => None
Err(_e) => None,
},
None => None,
};
let community_id = match data.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) {
Ok(community) => community,
Err(_e) => {
return Err(APIError::err(&self.op, "couldnt_find_community"))?
}
Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_community"))?,
};
let moderators = match CommunityModeratorView::for_community(&conn, community_id) {
Ok(moderators) => moderators,
Err(_e) => {
return Err(APIError::err(&self.op, "couldnt_find_community"))?
}
Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_community"))?,
};
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);
// Return the jwt
Ok(
GetCommunityResponse {
Ok(GetCommunityResponse {
op: self.op.to_string(),
community: community_view,
moderators: moderators,
admins: admins,
}
)
})
}
}
@ -180,22 +173,21 @@ impl Perform<CommunityResponse> for Oper<CreateCommunity> {
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
return Err(APIError::err(&self.op, "not_logged_in"))?
}
Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
};
if has_slurs(&data.name) ||
has_slurs(&data.title) ||
(data.description.is_some() && has_slurs(&data.description.to_owned().unwrap())) {
return Err(APIError::err(&self.op, "no_slurs"))?
if has_slurs(&data.name)
|| has_slurs(&data.title)
|| (data.description.is_some() && has_slurs(&data.description.to_owned().unwrap()))
{
return Err(APIError::err(&self.op, "no_slurs"))?;
}
let user_id = claims.id;
// Check for a site ban
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
@ -213,43 +205,42 @@ impl Perform<CommunityResponse> for Oper<CreateCommunity> {
let inserted_community = match Community::create(&conn, &community_form) {
Ok(community) => community,
Err(_e) => {
return Err(APIError::err(&self.op, "community_already_exists"))?
}
Err(_e) => return Err(APIError::err(&self.op, "community_already_exists"))?,
};
let community_moderator_form = CommunityModeratorForm {
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,
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 {
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,
Err(_e) => {
return Err(APIError::err(&self.op, "community_follower_already_exists"))?
}
Err(_e) => return Err(APIError::err(&self.op, "community_follower_already_exists"))?,
};
let community_view = CommunityView::read(&conn, inserted_community.id, Some(user_id))?;
Ok(
CommunityResponse {
Ok(CommunityResponse {
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;
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 claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
return Err(APIError::err(&self.op, "not_logged_in"))?
}
Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
};
let user_id = claims.id;
// Check for a site ban
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
let mut editors: Vec<i32> = Vec::new();
editors.append(
&mut CommunityModeratorView::for_community(&conn, data.edit_id)
?
&mut CommunityModeratorView::for_community(&conn, data.edit_id)?
.into_iter()
.map(|m| m.user_id)
.collect()
);
editors.append(
&mut UserView::admins(&conn)
?
.into_iter()
.map(|a| a.id)
.collect()
.collect(),
);
editors.append(&mut UserView::admins(&conn)?.into_iter().map(|a| a.id).collect());
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 {
@ -306,40 +288,36 @@ impl Perform<CommunityResponse> for Oper<EditCommunity> {
removed: data.removed.to_owned(),
deleted: data.deleted.to_owned(),
nsfw: data.nsfw,
updated: Some(naive_now())
updated: Some(naive_now()),
};
let _updated_community = match Community::update(&conn, data.edit_id, &community_form) {
Ok(community) => community,
Err(_e) => {
return Err(APIError::err(&self.op, "couldnt_update_community"))?
}
Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_community"))?,
};
// Mod tables
if let Some(removed) = data.removed.to_owned() {
let expires = match data.expires {
Some(time) => Some(naive_from_unix(time)),
None => None
None => None,
};
let form = ModRemoveCommunityForm {
mod_user_id: user_id,
community_id: data.edit_id,
removed: Some(removed),
reason: data.reason.to_owned(),
expires: expires
expires: expires,
};
ModRemoveCommunity::create(&conn, &form)?;
}
let community_view = CommunityView::read(&conn, data.edit_id, Some(user_id))?;
Ok(
CommunityResponse {
Ok(CommunityResponse {
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 user_claims: Option<Claims> = match &data.auth {
Some(auth) => {
match Claims::decode(&auth) {
Ok(claims) => {
Some(claims.claims)
}
Err(_e) => None
}
}
None => None
Some(auth) => match Claims::decode(&auth) {
Ok(claims) => Some(claims.claims),
Err(_e) => None,
},
None => None,
};
let user_id = match &user_claims {
Some(claims) => Some(claims.id),
None => None
None => None,
};
let show_nsfw = match &user_claims {
Some(claims) => claims.show_nsfw,
None => false
None => false,
};
let sort = SortType::from_str(&data.sort)?;
let communities: Vec<CommunityView> = CommunityView::list(
&conn,
&sort,
user_id,
show_nsfw,
None,
data.page,
data.limit)?;
&conn, &sort, user_id, show_nsfw, None, data.page, data.limit,
)?;
// Return the jwt
Ok(
ListCommunitiesResponse {
Ok(ListCommunitiesResponse {
op: self.op.to_string(),
communities: communities
}
)
communities: communities,
})
}
}
impl Perform<CommunityResponse> for Oper<FollowCommunity> {
fn perform(&self) -> Result<CommunityResponse, Error> {
let data: &FollowCommunity = &self.data;
@ -399,46 +365,37 @@ impl Perform<CommunityResponse> for Oper<FollowCommunity> {
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
return Err(APIError::err(&self.op, "not_logged_in"))?
}
Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
};
let user_id = claims.id;
let community_follower_form = CommunityFollowerForm {
community_id: data.community_id,
user_id: user_id
user_id: user_id,
};
if data.follow {
match CommunityFollower::follow(&conn, &community_follower_form) {
Ok(user) => user,
Err(_e) => {
return Err(APIError::err(&self.op, "community_follower_already_exists"))?
}
Err(_e) => return Err(APIError::err(&self.op, "community_follower_already_exists"))?,
};
} else {
match CommunityFollower::ignore(&conn, &community_follower_form) {
Ok(user) => user,
Err(_e) => {
return Err(APIError::err(&self.op, "community_follower_already_exists"))?
}
Err(_e) => return Err(APIError::err(&self.op, "community_follower_already_exists"))?,
};
}
let community_view = CommunityView::read(&conn, data.community_id, Some(user_id))?;
Ok(
CommunityResponse {
Ok(CommunityResponse {
op: self.op.to_string(),
community: community_view
}
)
community: community_view,
})
}
}
impl Perform<GetFollowedCommunitiesResponse> for Oper<GetFollowedCommunities> {
fn perform(&self) -> Result<GetFollowedCommunitiesResponse, Error> {
let data: &GetFollowedCommunities = &self.data;
@ -446,31 +403,25 @@ impl Perform<GetFollowedCommunitiesResponse> for Oper<GetFollowedCommunities> {
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
return Err(APIError::err(&self.op, "not_logged_in"))?
}
Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
};
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,
Err(_e) => {
return Err(APIError::err(&self.op, "system_err_login"))?
}
Err(_e) => return Err(APIError::err(&self.op, "system_err_login"))?,
};
// Return the jwt
Ok(
GetFollowedCommunitiesResponse {
Ok(GetFollowedCommunitiesResponse {
op: self.op.to_string(),
communities: communities
}
)
communities: communities,
})
}
}
impl Perform<BanFromCommunityResponse> for Oper<BanFromCommunity> {
fn perform(&self) -> Result<BanFromCommunityResponse, Error> {
let data: &BanFromCommunity = &self.data;
@ -478,9 +429,7 @@ impl Perform<BanFromCommunityResponse> for Oper<BanFromCommunity> {
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
return Err(APIError::err(&self.op, "not_logged_in"))?
}
Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
};
let user_id = claims.id;
@ -493,23 +442,19 @@ impl Perform<BanFromCommunityResponse> for Oper<BanFromCommunity> {
if data.ban {
match CommunityUserBan::ban(&conn, &community_user_ban_form) {
Ok(user) => user,
Err(_e) => {
return Err(APIError::err(&self.op, "community_user_already_banned"))?
}
Err(_e) => return Err(APIError::err(&self.op, "community_user_already_banned"))?,
};
} else {
match CommunityUserBan::unban(&conn, &community_user_ban_form) {
Ok(user) => user,
Err(_e) => {
return Err(APIError::err(&self.op, "community_user_already_banned"))?
}
Err(_e) => return Err(APIError::err(&self.op, "community_user_already_banned"))?,
};
}
// Mod tables
let expires = match data.expires {
Some(time) => Some(naive_from_unix(time)),
None => None
None => None,
};
let form = ModBanFromCommunityForm {
@ -524,13 +469,11 @@ impl Perform<BanFromCommunityResponse> for Oper<BanFromCommunity> {
let user_view = UserView::read(&conn, data.user_id)?;
Ok(
BanFromCommunityResponse {
Ok(BanFromCommunityResponse {
op: self.op.to_string(),
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) {
Ok(claims) => claims.claims,
Err(_e) => {
return Err(APIError::err(&self.op, "not_logged_in"))?
}
Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
};
let user_id = claims.id;
let community_moderator_form = CommunityModeratorForm {
community_id: data.community_id,
user_id: data.user_id
user_id: data.user_id,
};
if data.added {
match CommunityModerator::join(&conn, &community_moderator_form) {
Ok(user) => user,
Err(_e) => {
return Err(APIError::err(&self.op, "community_moderator_already_exists"))?
return Err(APIError::err(
&self.op,
"community_moderator_already_exists",
))?
}
};
} else {
match CommunityModerator::leave(&conn, &community_moderator_form) {
Ok(user) => user,
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)?;
Ok(
AddModToCommunityResponse {
Ok(AddModToCommunityResponse {
op: self.op.to_string(),
moderators: moderators,
}
)
})
}
}
@ -596,9 +541,7 @@ impl Perform<GetCommunityResponse> for Oper<TransferCommunity> {
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
return Err(APIError::err(&self.op, "not_logged_in"))?
}
Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
};
let user_id = claims.id;
@ -611,10 +554,15 @@ impl Perform<GetCommunityResponse> for Oper<TransferCommunity> {
let creator_user = admins.remove(creator_index);
admins.insert(0, creator_user);
// 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) {
return Err(APIError::err(&self.op, "not_an_admin"))?
if user_id != read_community.creator_id
&& !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 {
@ -626,35 +574,39 @@ impl Perform<GetCommunityResponse> for Oper<TransferCommunity> {
removed: None,
deleted: None,
nsfw: read_community.nsfw,
updated: Some(naive_now())
updated: Some(naive_now()),
};
let _updated_community = match Community::update(&conn, data.community_id, &community_form) {
Ok(community) => community,
Err(_e) => {
return Err(APIError::err(&self.op, "couldnt_update_community"))?
}
Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_community"))?,
};
// You also have to re-do the community_moderator table, reordering it.
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);
community_mods.insert(0, creator_user);
CommunityModerator::delete_for_community(&conn, data.community_id)?;
for cmod in &community_mods {
let community_moderator_form = CommunityModeratorForm {
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,
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)) {
Ok(community) => community,
Err(_e) => {
return Err(APIError::err(&self.op, "couldnt_find_community"))?
}
Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_community"))?,
};
let moderators = match CommunityModeratorView::for_community(&conn, data.community_id) {
Ok(moderators) => moderators,
Err(_e) => {
return Err(APIError::err(&self.op, "couldnt_find_community"))?
}
Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_community"))?,
};
// Return the jwt
Ok(
GetCommunityResponse {
Ok(GetCommunityResponse {
op: self.op.to_string(),
community: community_view,
moderators: moderators,
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::comment::*;
use crate::db::comment_view::*;
use crate::db::community::*;
use crate::db::community_view::*;
use crate::db::user_view::*;
use crate::db::moderator_views::*;
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 post;
pub mod comment;
pub mod site;
pub mod user;
#[derive(EnumString,ToString,Debug)]
#[derive(EnumString, ToString, Debug)]
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)]
@ -43,18 +76,17 @@ impl APIError {
pub struct Oper<T> {
op: UserOperation,
data: T
data: T,
}
impl <T> Oper<T> {
impl<T> Oper<T> {
pub fn new(op: UserOperation, data: T) -> Oper<T> {
Oper {
op: op,
data: data
}
Oper { op: op, data: data }
}
}
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>,
nsfw: bool,
community_id: i32,
auth: String
auth: String,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct PostResponse {
op: String,
pub post: PostView
pub post: PostView,
}
#[derive(Serialize, Deserialize)]
pub struct GetPost {
pub id: i32,
auth: Option<String>
auth: Option<String>,
}
#[derive(Serialize, Deserialize)]
@ -41,7 +40,7 @@ pub struct GetPosts {
page: Option<i64>,
limit: Option<i64>,
community_id: Option<i32>,
auth: Option<String>
auth: Option<String>,
}
#[derive(Serialize, Deserialize)]
@ -54,16 +53,15 @@ pub struct GetPostsResponse {
pub struct CreatePostLike {
post_id: i32,
score: i16,
auth: String
auth: String,
}
#[derive(Serialize, Deserialize)]
pub struct CreatePostLikeResponse {
op: String,
post: PostView
post: PostView,
}
#[derive(Serialize, Deserialize)]
pub struct EditPost {
pub edit_id: i32,
@ -77,14 +75,14 @@ pub struct EditPost {
nsfw: bool,
locked: Option<bool>,
reason: Option<String>,
auth: String
auth: String,
}
#[derive(Serialize, Deserialize)]
pub struct SavePost {
post_id: i32,
save: bool,
auth: String
auth: String,
}
impl Perform<PostResponse> for Oper<CreatePost> {
@ -92,29 +90,25 @@ impl Perform<PostResponse> for Oper<CreatePost> {
let data: &CreatePost = &self.data;
let conn = establish_connection();
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
return Err(APIError::err(&self.op, "not_logged_in"))?
}
Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
};
if has_slurs(&data.name) ||
(data.body.is_some() && has_slurs(&data.body.to_owned().unwrap())) {
return Err(APIError::err(&self.op, "no_slurs"))?
if has_slurs(&data.name) || (data.body.is_some() && has_slurs(&data.body.to_owned().unwrap())) {
return Err(APIError::err(&self.op, "no_slurs"))?;
}
let user_id = claims.id;
// Check for a community ban
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
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 {
@ -127,45 +121,37 @@ impl Perform<PostResponse> for Oper<CreatePost> {
deleted: None,
nsfw: data.nsfw,
locked: None,
updated: None
updated: None,
};
let inserted_post = match Post::create(&conn, &post_form) {
Ok(post) => post,
Err(_e) => {
return Err(APIError::err(&self.op, "couldnt_create_post"))?
}
Err(_e) => return Err(APIError::err(&self.op, "couldnt_create_post"))?,
};
// They like their own post by default
let like_form = PostLikeForm {
post_id: inserted_post.id,
user_id: user_id,
score: 1
score: 1,
};
// Only add the like if the score isnt 0
let _inserted_like = match PostLike::like(&conn, &like_form) {
Ok(like) => like,
Err(_e) => {
return Err(APIError::err(&self.op, "couldnt_like_post"))?
}
Err(_e) => return Err(APIError::err(&self.op, "couldnt_like_post"))?,
};
// Refetch the view
let post_view = match PostView::read(&conn, inserted_post.id, Some(user_id)) {
Ok(post) => post,
Err(_e) => {
return Err(APIError::err(&self.op, "couldnt_find_post"))?
}
Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_post"))?,
};
Ok(
PostResponse {
Ok(PostResponse {
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 user_id: Option<i32> = match &data.auth {
Some(auth) => {
match Claims::decode(&auth) {
Some(auth) => match Claims::decode(&auth) {
Ok(claims) => {
let user_id = claims.claims.id;
Some(user_id)
}
Err(_e) => None
}
}
None => None
Err(_e) => None,
},
None => None,
};
let post_view = match PostView::read(&conn, data.id, user_id) {
Ok(post) => post,
Err(_e) => {
return Err(APIError::err(&self.op, "couldnt_find_post"))?
}
Err(_e) => 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)?;
@ -207,45 +199,38 @@ impl Perform<GetPostResponse> for Oper<GetPost> {
admins.insert(0, creator_user);
// Return the jwt
Ok(
GetPostResponse {
Ok(GetPostResponse {
op: self.op.to_string(),
post: post_view,
comments: comments,
community: community,
moderators: moderators,
admins: admins,
}
)
})
}
}
impl Perform<GetPostsResponse> for Oper<GetPosts> {
fn perform(&self) -> Result<GetPostsResponse, Error> {
let data: &GetPosts = &self.data;
let conn = establish_connection();
let user_claims: Option<Claims> = match &data.auth {
Some(auth) => {
match Claims::decode(&auth) {
Ok(claims) => {
Some(claims.claims)
}
Err(_e) => None
}
}
None => None
Some(auth) => match Claims::decode(&auth) {
Ok(claims) => Some(claims.claims),
Err(_e) => None,
},
None => None,
};
let user_id = match &user_claims {
Some(claims) => Some(claims.id),
None => None
None => None,
};
let show_nsfw = match &user_claims {
Some(claims) => claims.show_nsfw,
None => false
None => false,
};
let type_ = PostListingType::from_str(&data.type_)?;
@ -264,19 +249,16 @@ impl Perform<GetPostsResponse> for Oper<GetPosts> {
false,
false,
data.page,
data.limit) {
data.limit,
) {
Ok(posts) => posts,
Err(_e) => {
return Err(APIError::err(&self.op, "couldnt_get_posts"))?
}
Err(_e) => return Err(APIError::err(&self.op, "couldnt_get_posts"))?,
};
Ok(
GetPostsResponse {
Ok(GetPostsResponse {
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) {
Ok(claims) => claims.claims,
Err(_e) => {
return Err(APIError::err(&self.op, "not_logged_in"))?
}
Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
};
let user_id = claims.id;
@ -297,18 +277,18 @@ impl Perform<CreatePostLikeResponse> for Oper<CreatePostLike> {
// Check for a community ban
let post = Post::read(&conn, data.post_id)?;
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
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 {
post_id: data.post_id,
user_id: user_id,
score: data.score
score: data.score,
};
// Remove any likes first
@ -319,44 +299,35 @@ impl Perform<CreatePostLikeResponse> for Oper<CreatePostLike> {
if do_add {
let _inserted_like = match PostLike::like(&conn, &like_form) {
Ok(like) => like,
Err(_e) => {
return Err(APIError::err(&self.op, "couldnt_like_post"))?
}
Err(_e) => return Err(APIError::err(&self.op, "couldnt_like_post"))?,
};
}
let post_view = match PostView::read(&conn, data.post_id, Some(user_id)) {
Ok(post) => post,
Err(_e) => {
return Err(APIError::err(&self.op, "couldnt_find_post"))?
}
Err(_e) => return Err(APIError::err(&self.op, "couldnt_find_post"))?,
};
// just output the score
Ok(
CreatePostLikeResponse {
Ok(CreatePostLikeResponse {
op: self.op.to_string(),
post: post_view
}
)
post: post_view,
})
}
}
impl Perform<PostResponse> for Oper<EditPost> {
fn perform(&self) -> Result<PostResponse, Error> {
let data: &EditPost = &self.data;
if has_slurs(&data.name) ||
(data.body.is_some() && has_slurs(&data.body.to_owned().unwrap())) {
return Err(APIError::err(&self.op, "no_slurs"))?
if has_slurs(&data.name) || (data.body.is_some() && has_slurs(&data.body.to_owned().unwrap())) {
return Err(APIError::err(&self.op, "no_slurs"))?;
}
let conn = establish_connection();
let claims = match Claims::decode(&data.auth) {
Ok(claims) => claims.claims,
Err(_e) => {
return Err(APIError::err(&self.op, "not_logged_in"))?
}
Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
};
let user_id = claims.id;
@ -364,31 +335,24 @@ impl Perform<PostResponse> for Oper<EditPost> {
// Verify its the creator or a mod or admin
let mut editors: Vec<i32> = vec![data.creator_id];
editors.append(
&mut CommunityModeratorView::for_community(&conn, data.community_id)
?
&mut CommunityModeratorView::for_community(&conn, data.community_id)?
.into_iter()
.map(|m| m.user_id)
.collect()
);
editors.append(
&mut UserView::admins(&conn)
?
.into_iter()
.map(|a| a.id)
.collect()
.collect(),
);
editors.append(&mut UserView::admins(&conn)?.into_iter().map(|a| a.id).collect());
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
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
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 {
@ -401,14 +365,12 @@ impl Perform<PostResponse> for Oper<EditPost> {
deleted: data.deleted.to_owned(),
nsfw: data.nsfw,
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) {
Ok(post) => post,
Err(_e) => {
return Err(APIError::err(&self.op, "couldnt_update_post"))?
}
Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_post"))?,
};
// Mod tables
@ -433,12 +395,10 @@ impl Perform<PostResponse> for Oper<EditPost> {
let post_view = PostView::read(&conn, data.edit_id, Some(user_id))?;
Ok(
PostResponse {
Ok(PostResponse {
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) {
Ok(claims) => claims.claims,
Err(_e) => {
return Err(APIError::err(&self.op, "not_logged_in"))?
}
Err(_e) => return Err(APIError::err(&self.op, "not_logged_in"))?,
};
let user_id = claims.id;
@ -464,26 +422,20 @@ impl Perform<PostResponse> for Oper<SavePost> {
if data.save {
match PostSaved::save(&conn, &post_saved_form) {
Ok(post) => post,
Err(_e) => {
return Err(APIError::err(&self.op, "couldnt_save_post"))?
}
Err(_e) => return Err(APIError::err(&self.op, "couldnt_save_post"))?,
};
} else {
match PostSaved::unsave(&conn, &post_saved_form) {
Ok(post) => post,
Err(_e) => {
return Err(APIError::err(&self.op, "couldnt_save_post"))?
}
Err(_e) => return Err(APIError::err(&self.op, "couldnt_save_post"))?,
};
}
let post_view = PostView::read(&conn, data.post_id, Some(user_id))?;
Ok(
PostResponse {
Ok(PostResponse {
op: self.op.to_string(),
post: post_view
}
)
post: post_view,
})
}
}

View file

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

View file

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

View file

@ -1,27 +1,51 @@
extern crate activitypub;
use self::activitypub::{context, actor::Person};
use self::activitypub::{actor::Person, context};
use crate::db::user::User_;
impl User_ {
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 mut person = Person::default();
person.object_props.set_context_object(context()).ok();
person.object_props.set_id_string(base_url.to_string()).ok();
person.object_props.set_name_string(self.name.to_owned()).ok();
person.object_props.set_published_utctime(to_datetime_utc(self.published)).ok();
person
.object_props
.set_name_string(self.name.to_owned())
.ok();
person
.object_props
.set_published_utctime(to_datetime_utc(self.published))
.ok();
if let Some(i) = self.updated {
person.object_props.set_updated_utctime(to_datetime_utc(i)).ok();
person
.object_props
.set_updated_utctime(to_datetime_utc(i))
.ok();
}
// person.object_props.summary = self.summary;
person.ap_actor_props.set_inbox_string(format!("{}/inbox", &base_url)).ok();
person.ap_actor_props.set_outbox_string(format!("{}/outbox", &base_url)).ok();
person.ap_actor_props.set_following_string(format!("{}/following", &base_url)).ok();
person.ap_actor_props.set_liked_string(format!("{}/liked", &base_url)).ok();
person
.ap_actor_props
.set_inbox_string(format!("{}/inbox", &base_url))
.ok();
person
.ap_actor_props
.set_outbox_string(format!("{}/outbox", &base_url))
.ok();
person
.ap_actor_props
.set_following_string(format!("{}/following", &base_url))
.ok();
person
.ap_actor_props
.set_liked_string(format!("{}/liked", &base_url))
.ok();
if let Some(i) = &self.preferred_username {
person.ap_actor_props.set_preferred_username_string(i.to_string()).ok();
person
.ap_actor_props
.set_preferred_username_string(i.to_string())
.ok();
}
person
@ -51,10 +75,11 @@ mod tests {
};
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();
println!("{}", json);
}
}

View file

@ -1,29 +1,27 @@
use crate::schema::{category};
use crate::schema::category::dsl::*;
use super::*;
use crate::schema::category;
use crate::schema::category::dsl::*;
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
#[table_name="category"]
#[table_name = "category"]
pub struct Category {
pub id: i32,
pub name: String
pub name: String,
}
#[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize)]
#[table_name="category"]
#[table_name = "category"]
pub struct CategoryForm {
pub name: String,
}
impl Crud<CategoryForm> for Category {
fn read(conn: &PgConnection, category_id: i32) -> Result<Self, Error> {
category.find(category_id)
.first::<Self>(conn)
category.find(category_id).first::<Self>(conn)
}
fn delete(conn: &PgConnection, category_id: i32) -> Result<usize, Error> {
diesel::delete(category.find(category_id))
.execute(conn)
diesel::delete(category.find(category_id)).execute(conn)
}
fn create(conn: &PgConnection, new_category: &CategoryForm) -> Result<Self, Error> {
@ -32,7 +30,11 @@ impl Crud<CategoryForm> for Category {
.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))
.set(new_category)
.get_result::<Self>(conn)
@ -55,7 +57,7 @@ mod tests {
let categories = Category::list_all(&conn).unwrap();
let expected_first_category = Category {
id: 1,
name: "Discussion".into()
name: "Discussion".into(),
};
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::*;
use crate::schema::{comment, comment_like, comment_saved};
// WITH RECURSIVE MyTree AS (
// SELECT * FROM comment WHERE parent_id IS NULL
@ -11,7 +11,7 @@ use super::post::Post;
#[derive(Queryable, Associations, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
#[belongs_to(Post)]
#[table_name="comment"]
#[table_name = "comment"]
pub struct Comment {
pub id: i32,
pub creator_id: i32,
@ -26,7 +26,7 @@ pub struct Comment {
}
#[derive(Insertable, AsChangeset, Clone)]
#[table_name="comment"]
#[table_name = "comment"]
pub struct CommentForm {
pub creator_id: i32,
pub post_id: i32,
@ -41,14 +41,12 @@ pub struct CommentForm {
impl Crud<CommentForm> for Comment {
fn read(conn: &PgConnection, comment_id: i32) -> Result<Self, Error> {
use crate::schema::comment::dsl::*;
comment.find(comment_id)
.first::<Self>(conn)
comment.find(comment_id).first::<Self>(conn)
}
fn delete(conn: &PgConnection, comment_id: i32) -> Result<usize, Error> {
use crate::schema::comment::dsl::*;
diesel::delete(comment.find(comment_id))
.execute(conn)
diesel::delete(comment.find(comment_id)).execute(conn)
}
fn create(conn: &PgConnection, comment_form: &CommentForm) -> Result<Self, Error> {
@ -58,7 +56,11 @@ impl Crud<CommentForm> for Comment {
.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::*;
diesel::update(comment.find(comment_id))
.set(comment_form)
@ -79,15 +81,15 @@ pub struct CommentLike {
}
#[derive(Insertable, AsChangeset, Clone)]
#[table_name="comment_like"]
#[table_name = "comment_like"]
pub struct CommentLikeForm {
pub user_id: i32,
pub comment_id: i32,
pub post_id: i32,
pub score: i16
pub score: i16,
}
impl Likeable <CommentLikeForm> for CommentLike {
impl Likeable<CommentLikeForm> for CommentLike {
fn read(conn: &PgConnection, comment_id_from: i32) -> Result<Vec<Self>, Error> {
use crate::schema::comment_like::dsl::*;
comment_like
@ -106,7 +108,8 @@ impl Likeable <CommentLikeForm> for CommentLike {
diesel::delete(
comment_like
.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)
}
}
@ -131,13 +134,13 @@ pub struct CommentSaved {
}
#[derive(Insertable, AsChangeset, Clone)]
#[table_name="comment_saved"]
#[table_name = "comment_saved"]
pub struct CommentSavedForm {
pub comment_id: i32,
pub user_id: i32,
}
impl Saveable <CommentSavedForm> for CommentSaved {
impl Saveable<CommentSavedForm> for CommentSaved {
fn save(conn: &PgConnection, comment_saved_form: &CommentSavedForm) -> Result<Self, Error> {
use crate::schema::comment_saved::dsl::*;
insert_into(comment_saved)
@ -146,19 +149,21 @@ impl Saveable <CommentSavedForm> for CommentSaved {
}
fn unsave(conn: &PgConnection, comment_saved_form: &CommentSavedForm) -> Result<usize, Error> {
use crate::schema::comment_saved::dsl::*;
diesel::delete(comment_saved
diesel::delete(
comment_saved
.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)
}
}
#[cfg(test)]
mod tests {
use super::*;
use super::super::post::*;
use super::super::community::*;
use super::super::post::*;
use super::super::user::*;
use super::*;
#[test]
fn test_crud() {
let conn = establish_connection();
@ -214,7 +219,7 @@ mod tests {
deleted: None,
read: None,
parent_id: None,
updated: None
updated: None,
};
let inserted_comment = Comment::create(&conn, &comment_form).unwrap();
@ -229,7 +234,7 @@ mod tests {
read: false,
parent_id: None,
published: inserted_comment.published,
updated: None
updated: None,
};
let child_comment_form = CommentForm {
@ -240,7 +245,7 @@ mod tests {
removed: None,
deleted: None,
read: None,
updated: None
updated: None,
};
let inserted_child_comment = Comment::create(&conn, &child_comment_form).unwrap();
@ -250,7 +255,7 @@ mod tests {
comment_id: inserted_comment.id,
post_id: inserted_post.id,
user_id: inserted_user.id,
score: 1
score: 1,
};
let inserted_comment_like = CommentLike::like(&conn, &comment_like_form).unwrap();
@ -261,7 +266,7 @@ mod tests {
post_id: inserted_post.id,
user_id: inserted_user.id,
published: inserted_comment_like.published,
score: 1
score: 1,
};
// Comment Saved
@ -294,10 +299,12 @@ mod tests {
assert_eq!(expected_comment, updated_comment);
assert_eq!(expected_comment_like, inserted_comment_like);
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, saved_removed);
assert_eq!(1, num_deleted);
}
}

View file

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

View file

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

View file

@ -73,8 +73,10 @@ table! {
}
}
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)]
#[table_name="community_view"]
#[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "community_view"]
pub struct CommunityView {
pub id: i32,
pub name: String,
@ -98,7 +100,11 @@ pub struct 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::*;
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
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())
.filter(user_id.is_null()),
.filter(user_id.is_null())
}
SortType::New => query = query.order_by(published.desc()).filter(user_id.is_null()),
SortType::TopAll => {
match from_user_id {
Some(from_user_id) => query = query.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())
SortType::TopAll => match from_user_id {
Some(from_user_id) => {
query = query
.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 {
@ -161,77 +176,97 @@ impl CommunityView {
}
}
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)]
#[table_name="community_moderator_view"]
#[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "community_moderator_view"]
pub struct CommunityModeratorView {
pub id: i32,
pub community_id: i32,
pub user_id: i32,
pub published: chrono::NaiveDateTime,
pub user_name : String,
pub user_name: String,
pub community_name: String,
}
impl CommunityModeratorView {
pub fn for_community(conn: &PgConnection, from_community_id: i32) -> Result<Vec<Self>, Error> {
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> {
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)]
#[table_name="community_follower_view"]
#[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "community_follower_view"]
pub struct CommunityFollowerView {
pub id: i32,
pub community_id: i32,
pub user_id: i32,
pub published: chrono::NaiveDateTime,
pub user_name : String,
pub user_name: String,
pub community_name: String,
}
impl CommunityFollowerView {
pub fn for_community(conn: &PgConnection, from_community_id: i32) -> Result<Vec<Self>, Error> {
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> {
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(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)]
#[table_name="community_user_ban_view"]
#[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "community_user_ban_view"]
pub struct CommunityUserBanView {
pub id: i32,
pub community_id: i32,
pub user_id: i32,
pub published: chrono::NaiveDateTime,
pub user_name : String,
pub user_name: String,
pub community_name: String,
}
impl CommunityUserBanView {
pub fn for_community(conn: &PgConnection, from_community_id: i32) -> Result<Vec<Self>, Error> {
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> {
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::*;
community_user_ban_view
.filter(user_id.eq(from_user_id))
@ -240,9 +275,10 @@ impl CommunityUserBanView {
}
}
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)]
#[table_name="site_view"]
#[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "site_view"]
pub struct SiteView {
pub id: i32,
pub name: String,

View file

@ -1,73 +1,117 @@
use diesel::*;
use crate::Settings;
use diesel::dsl::*;
use diesel::result::Error;
use crate::{Settings};
use diesel::*;
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 comment;
pub mod comment_view;
pub mod community;
pub mod community_view;
pub mod user_view;
pub mod moderator;
pub mod moderator_views;
pub mod post;
pub mod post_view;
pub mod user;
pub mod user_view;
pub trait Crud<T> {
fn create(conn: &PgConnection, form: &T) -> Result<Self, 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;
fn create(conn: &PgConnection, form: &T) -> Result<Self, 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> {
fn follow(conn: &PgConnection, form: &T) -> Result<Self, Error> where Self: Sized;
fn ignore(conn: &PgConnection, form: &T) -> Result<usize, Error> where Self: Sized;
fn follow(conn: &PgConnection, form: &T) -> Result<Self, Error>
where
Self: Sized;
fn ignore(conn: &PgConnection, form: &T) -> Result<usize, Error>
where
Self: Sized;
}
pub trait Joinable<T> {
fn join(conn: &PgConnection, form: &T) -> Result<Self, Error> where Self: Sized;
fn leave(conn: &PgConnection, form: &T) -> Result<usize, Error> where Self: Sized;
fn join(conn: &PgConnection, form: &T) -> Result<Self, Error>
where
Self: Sized;
fn leave(conn: &PgConnection, form: &T) -> Result<usize, Error>
where
Self: Sized;
}
pub trait Likeable<T> {
fn read(conn: &PgConnection, id: i32) -> Result<Vec<Self>, Error> where 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;
fn read(conn: &PgConnection, id: i32) -> Result<Vec<Self>, Error>
where
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> {
fn ban(conn: &PgConnection, form: &T) -> Result<Self, Error> where Self: Sized;
fn unban(conn: &PgConnection, form: &T) -> Result<usize, Error> where Self: Sized;
fn ban(conn: &PgConnection, form: &T) -> Result<Self, Error>
where
Self: Sized;
fn unban(conn: &PgConnection, form: &T) -> Result<usize, Error>
where
Self: Sized;
}
pub trait Saveable<T> {
fn save(conn: &PgConnection, form: &T) -> Result<Self, Error> where Self: Sized;
fn unsave(conn: &PgConnection, form: &T) -> Result<usize, Error> where Self: Sized;
fn save(conn: &PgConnection, form: &T) -> Result<Self, Error>
where
Self: Sized;
fn unsave(conn: &PgConnection, form: &T) -> Result<usize, Error>
where
Self: Sized;
}
pub trait Readable<T> {
fn mark_as_read(conn: &PgConnection, form: &T) -> Result<Self, Error> where Self: Sized;
fn mark_as_unread(conn: &PgConnection, form: &T) -> Result<usize, Error> where Self: Sized;
fn mark_as_read(conn: &PgConnection, form: &T) -> Result<Self, Error>
where
Self: Sized;
fn mark_as_unread(conn: &PgConnection, form: &T) -> Result<usize, Error>
where
Self: Sized;
}
pub fn establish_connection() -> PgConnection {
let db_url = Settings::get().db_url;
PgConnection::establish(&db_url)
.expect(&format!("Error connecting to {}", db_url))
PgConnection::establish(&db_url).expect(&format!("Error connecting to {}", db_url))
}
#[derive(EnumString,ToString,Debug, Serialize, Deserialize)]
#[derive(EnumString, ToString, Debug, Serialize, Deserialize)]
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 {
All, Comments, Posts, Communities, Users, Url
All,
Comments,
Posts,
Communities,
Users,
Url,
}
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)]
mod tests {
use super::fuzzy_search;
#[test] fn test_fuzzy_search() {
#[test]
fn test_fuzzy_search() {
let test = "This is a fuzzy search";
assert_eq!(fuzzy_search(test), "%This%is%a%fuzzy%search%".to_string());
}
}

View file

@ -1,8 +1,11 @@
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 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)]
#[table_name="mod_remove_post"]
#[table_name = "mod_remove_post"]
pub struct ModRemovePost {
pub id: i32,
pub mod_user_id: i32,
@ -13,7 +16,7 @@ pub struct ModRemovePost {
}
#[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize)]
#[table_name="mod_remove_post"]
#[table_name = "mod_remove_post"]
pub struct ModRemovePostForm {
pub mod_user_id: i32,
pub post_id: i32,
@ -24,14 +27,12 @@ pub struct ModRemovePostForm {
impl Crud<ModRemovePostForm> for ModRemovePost {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_remove_post::dsl::*;
mod_remove_post.find(from_id)
.first::<Self>(conn)
mod_remove_post.find(from_id).first::<Self>(conn)
}
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
use crate::schema::mod_remove_post::dsl::*;
diesel::delete(mod_remove_post.find(from_id))
.execute(conn)
diesel::delete(mod_remove_post.find(from_id)).execute(conn)
}
fn create(conn: &PgConnection, form: &ModRemovePostForm) -> Result<Self, Error> {
@ -49,10 +50,8 @@ impl Crud<ModRemovePostForm> for ModRemovePost {
}
}
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
#[table_name="mod_lock_post"]
#[table_name = "mod_lock_post"]
pub struct ModLockPost {
pub id: i32,
pub mod_user_id: i32,
@ -62,7 +61,7 @@ pub struct ModLockPost {
}
#[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize)]
#[table_name="mod_lock_post"]
#[table_name = "mod_lock_post"]
pub struct ModLockPostForm {
pub mod_user_id: i32,
pub post_id: i32,
@ -72,14 +71,12 @@ pub struct ModLockPostForm {
impl Crud<ModLockPostForm> for ModLockPost {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_lock_post::dsl::*;
mod_lock_post.find(from_id)
.first::<Self>(conn)
mod_lock_post.find(from_id).first::<Self>(conn)
}
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
use crate::schema::mod_lock_post::dsl::*;
diesel::delete(mod_lock_post.find(from_id))
.execute(conn)
diesel::delete(mod_lock_post.find(from_id)).execute(conn)
}
fn create(conn: &PgConnection, form: &ModLockPostForm) -> Result<Self, Error> {
@ -98,7 +95,7 @@ impl Crud<ModLockPostForm> for ModLockPost {
}
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
#[table_name="mod_remove_comment"]
#[table_name = "mod_remove_comment"]
pub struct ModRemoveComment {
pub id: i32,
pub mod_user_id: i32,
@ -109,7 +106,7 @@ pub struct ModRemoveComment {
}
#[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize)]
#[table_name="mod_remove_comment"]
#[table_name = "mod_remove_comment"]
pub struct ModRemoveCommentForm {
pub mod_user_id: i32,
pub comment_id: i32,
@ -120,14 +117,12 @@ pub struct ModRemoveCommentForm {
impl Crud<ModRemoveCommentForm> for ModRemoveComment {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_remove_comment::dsl::*;
mod_remove_comment.find(from_id)
.first::<Self>(conn)
mod_remove_comment.find(from_id).first::<Self>(conn)
}
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
use crate::schema::mod_remove_comment::dsl::*;
diesel::delete(mod_remove_comment.find(from_id))
.execute(conn)
diesel::delete(mod_remove_comment.find(from_id)).execute(conn)
}
fn create(conn: &PgConnection, form: &ModRemoveCommentForm) -> Result<Self, Error> {
@ -146,7 +141,7 @@ impl Crud<ModRemoveCommentForm> for ModRemoveComment {
}
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
#[table_name="mod_remove_community"]
#[table_name = "mod_remove_community"]
pub struct ModRemoveCommunity {
pub id: i32,
pub mod_user_id: i32,
@ -158,7 +153,7 @@ pub struct ModRemoveCommunity {
}
#[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize)]
#[table_name="mod_remove_community"]
#[table_name = "mod_remove_community"]
pub struct ModRemoveCommunityForm {
pub mod_user_id: i32,
pub community_id: i32,
@ -170,14 +165,12 @@ pub struct ModRemoveCommunityForm {
impl Crud<ModRemoveCommunityForm> for ModRemoveCommunity {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_remove_community::dsl::*;
mod_remove_community.find(from_id)
.first::<Self>(conn)
mod_remove_community.find(from_id).first::<Self>(conn)
}
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
use crate::schema::mod_remove_community::dsl::*;
diesel::delete(mod_remove_community.find(from_id))
.execute(conn)
diesel::delete(mod_remove_community.find(from_id)).execute(conn)
}
fn create(conn: &PgConnection, form: &ModRemoveCommunityForm) -> Result<Self, Error> {
@ -187,7 +180,11 @@ impl Crud<ModRemoveCommunityForm> for ModRemoveCommunity {
.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::*;
diesel::update(mod_remove_community.find(from_id))
.set(form)
@ -196,7 +193,7 @@ impl Crud<ModRemoveCommunityForm> for ModRemoveCommunity {
}
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
#[table_name="mod_ban_from_community"]
#[table_name = "mod_ban_from_community"]
pub struct ModBanFromCommunity {
pub id: i32,
pub mod_user_id: i32,
@ -209,7 +206,7 @@ pub struct ModBanFromCommunity {
}
#[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize)]
#[table_name="mod_ban_from_community"]
#[table_name = "mod_ban_from_community"]
pub struct ModBanFromCommunityForm {
pub mod_user_id: i32,
pub other_user_id: i32,
@ -222,14 +219,12 @@ pub struct ModBanFromCommunityForm {
impl Crud<ModBanFromCommunityForm> for ModBanFromCommunity {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_ban_from_community::dsl::*;
mod_ban_from_community.find(from_id)
.first::<Self>(conn)
mod_ban_from_community.find(from_id).first::<Self>(conn)
}
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
use crate::schema::mod_ban_from_community::dsl::*;
diesel::delete(mod_ban_from_community.find(from_id))
.execute(conn)
diesel::delete(mod_ban_from_community.find(from_id)).execute(conn)
}
fn create(conn: &PgConnection, form: &ModBanFromCommunityForm) -> Result<Self, Error> {
@ -239,7 +234,11 @@ impl Crud<ModBanFromCommunityForm> for ModBanFromCommunity {
.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::*;
diesel::update(mod_ban_from_community.find(from_id))
.set(form)
@ -247,9 +246,8 @@ impl Crud<ModBanFromCommunityForm> for ModBanFromCommunity {
}
}
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
#[table_name="mod_ban"]
#[table_name = "mod_ban"]
pub struct ModBan {
pub id: i32,
pub mod_user_id: i32,
@ -261,7 +259,7 @@ pub struct ModBan {
}
#[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize)]
#[table_name="mod_ban"]
#[table_name = "mod_ban"]
pub struct ModBanForm {
pub mod_user_id: i32,
pub other_user_id: i32,
@ -273,21 +271,17 @@ pub struct ModBanForm {
impl Crud<ModBanForm> for ModBan {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_ban::dsl::*;
mod_ban.find(from_id)
.first::<Self>(conn)
mod_ban.find(from_id).first::<Self>(conn)
}
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
use crate::schema::mod_ban::dsl::*;
diesel::delete(mod_ban.find(from_id))
.execute(conn)
diesel::delete(mod_ban.find(from_id)).execute(conn)
}
fn create(conn: &PgConnection, form: &ModBanForm) -> Result<Self, Error> {
use crate::schema::mod_ban::dsl::*;
insert_into(mod_ban)
.values(form)
.get_result::<Self>(conn)
insert_into(mod_ban).values(form).get_result::<Self>(conn)
}
fn update(conn: &PgConnection, from_id: i32, form: &ModBanForm) -> Result<Self, Error> {
@ -299,7 +293,7 @@ impl Crud<ModBanForm> for ModBan {
}
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
#[table_name="mod_add_community"]
#[table_name = "mod_add_community"]
pub struct ModAddCommunity {
pub id: i32,
pub mod_user_id: i32,
@ -310,7 +304,7 @@ pub struct ModAddCommunity {
}
#[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize)]
#[table_name="mod_add_community"]
#[table_name = "mod_add_community"]
pub struct ModAddCommunityForm {
pub mod_user_id: i32,
pub other_user_id: i32,
@ -321,14 +315,12 @@ pub struct ModAddCommunityForm {
impl Crud<ModAddCommunityForm> for ModAddCommunity {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_add_community::dsl::*;
mod_add_community.find(from_id)
.first::<Self>(conn)
mod_add_community.find(from_id).first::<Self>(conn)
}
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
use crate::schema::mod_add_community::dsl::*;
diesel::delete(mod_add_community.find(from_id))
.execute(conn)
diesel::delete(mod_add_community.find(from_id)).execute(conn)
}
fn create(conn: &PgConnection, form: &ModAddCommunityForm) -> Result<Self, Error> {
@ -347,7 +339,7 @@ impl Crud<ModAddCommunityForm> for ModAddCommunity {
}
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
#[table_name="mod_add"]
#[table_name = "mod_add"]
pub struct ModAdd {
pub id: i32,
pub mod_user_id: i32,
@ -357,7 +349,7 @@ pub struct ModAdd {
}
#[derive(Insertable, AsChangeset, Clone, Serialize, Deserialize)]
#[table_name="mod_add"]
#[table_name = "mod_add"]
pub struct ModAddForm {
pub mod_user_id: i32,
pub other_user_id: i32,
@ -367,21 +359,17 @@ pub struct ModAddForm {
impl Crud<ModAddForm> for ModAdd {
fn read(conn: &PgConnection, from_id: i32) -> Result<Self, Error> {
use crate::schema::mod_add::dsl::*;
mod_add.find(from_id)
.first::<Self>(conn)
mod_add.find(from_id).first::<Self>(conn)
}
fn delete(conn: &PgConnection, from_id: i32) -> Result<usize, Error> {
use crate::schema::mod_add::dsl::*;
diesel::delete(mod_add.find(from_id))
.execute(conn)
diesel::delete(mod_add.find(from_id)).execute(conn)
}
fn create(conn: &PgConnection, form: &ModAddForm) -> Result<Self, Error> {
use crate::schema::mod_add::dsl::*;
insert_into(mod_add)
.values(form)
.get_result::<Self>(conn)
insert_into(mod_add).values(form).get_result::<Self>(conn)
}
fn update(conn: &PgConnection, from_id: i32, form: &ModAddForm) -> Result<Self, Error> {
@ -394,11 +382,11 @@ impl Crud<ModAddForm> for ModAdd {
#[cfg(test)]
mod tests {
use super::*;
use super::super::user::*;
use super::super::post::*;
use super::super::community::*;
use super::super::comment::*;
use super::super::community::*;
use super::super::post::*;
use super::super::user::*;
use super::*;
// use Crud;
#[test]
fn test_crud() {
@ -469,7 +457,7 @@ mod tests {
deleted: None,
read: None,
parent_id: None,
updated: None
updated: None,
};
let inserted_comment = Comment::create(&conn, &comment_form).unwrap();
@ -484,7 +472,8 @@ mod tests {
removed: None,
};
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 {
id: inserted_mod_remove_post.id,
post_id: inserted_post.id,
@ -519,8 +508,10 @@ mod tests {
reason: None,
removed: None,
};
let inserted_mod_remove_comment = ModRemoveComment::create(&conn, &mod_remove_comment_form).unwrap();
let read_moderator_remove_comment = ModRemoveComment::read(&conn, inserted_mod_remove_comment.id).unwrap();
let inserted_mod_remove_comment =
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 {
id: inserted_mod_remove_comment.id,
comment_id: inserted_comment.id,
@ -539,8 +530,10 @@ mod tests {
removed: None,
expires: None,
};
let inserted_mod_remove_community = ModRemoveCommunity::create(&conn, &mod_remove_community_form).unwrap();
let read_moderator_remove_community = ModRemoveCommunity::read(&conn, inserted_mod_remove_community.id).unwrap();
let inserted_mod_remove_community =
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 {
id: inserted_mod_remove_community.id,
community_id: inserted_community.id,
@ -561,8 +554,10 @@ mod tests {
banned: None,
expires: None,
};
let inserted_mod_ban_from_community = 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 inserted_mod_ban_from_community =
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 {
id: inserted_mod_ban_from_community.id,
community_id: inserted_community.id,
@ -603,8 +598,10 @@ mod tests {
community_id: inserted_community.id,
removed: None,
};
let inserted_mod_add_community = ModAddCommunity::create(&conn, &mod_add_community_form).unwrap();
let read_moderator_add_community = ModAddCommunity::read(&conn, inserted_mod_add_community.id).unwrap();
let inserted_mod_add_community =
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 {
id: inserted_mod_add_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_lock_post, read_moderator_lock_post);
assert_eq!(expected_moderator_remove_comment, 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_remove_comment,
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_add_community, read_moderator_add_community);
assert_eq!(
expected_moderator_add_community,
read_moderator_add_community
);
assert_eq!(expected_moderator_add, read_moderator_add);
}
}

View file

@ -15,8 +15,10 @@ table! {
}
}
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)]
#[table_name="mod_remove_post_view"]
#[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "mod_remove_post_view"]
pub struct ModRemovePostView {
pub id: i32,
pub mod_user_id: i32,
@ -31,7 +33,8 @@ pub struct ModRemovePostView {
}
impl ModRemovePostView {
pub fn list(conn: &PgConnection,
pub fn list(
conn: &PgConnection,
from_community_id: Option<i32>,
from_mod_user_id: Option<i32>,
page: Option<i64>,
@ -50,7 +53,11 @@ impl ModRemovePostView {
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,9 +75,10 @@ table! {
}
}
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)]
#[table_name="mod_lock_post_view"]
#[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "mod_lock_post_view"]
pub struct ModLockPostView {
pub id: i32,
pub mod_user_id: i32,
@ -84,7 +92,8 @@ pub struct ModLockPostView {
}
impl ModLockPostView {
pub fn list(conn: &PgConnection,
pub fn list(
conn: &PgConnection,
from_community_id: Option<i32>,
from_mod_user_id: Option<i32>,
page: Option<i64>,
@ -103,7 +112,11 @@ impl ModLockPostView {
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,8 +139,10 @@ table! {
}
}
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)]
#[table_name="mod_remove_comment_view"]
#[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "mod_remove_comment_view"]
pub struct ModRemoveCommentView {
pub id: i32,
pub mod_user_id: i32,
@ -146,7 +161,8 @@ pub struct ModRemoveCommentView {
}
impl ModRemoveCommentView {
pub fn list(conn: &PgConnection,
pub fn list(
conn: &PgConnection,
from_community_id: Option<i32>,
from_mod_user_id: Option<i32>,
page: Option<i64>,
@ -165,7 +181,11 @@ impl ModRemoveCommentView {
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,8 +203,10 @@ table! {
}
}
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)]
#[table_name="mod_remove_community_view"]
#[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "mod_remove_community_view"]
pub struct ModRemoveCommunityView {
pub id: i32,
pub mod_user_id: i32,
@ -198,7 +220,8 @@ pub struct ModRemoveCommunityView {
}
impl ModRemoveCommunityView {
pub fn list(conn: &PgConnection,
pub fn list(
conn: &PgConnection,
from_mod_user_id: Option<i32>,
page: Option<i64>,
limit: Option<i64>,
@ -212,11 +235,14 @@ impl ModRemoveCommunityView {
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! {
mod_ban_from_community_view (id) {
id -> Int4,
@ -233,8 +259,10 @@ table! {
}
}
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)]
#[table_name="mod_ban_from_community_view"]
#[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "mod_ban_from_community_view"]
pub struct ModBanFromCommunityView {
pub id: i32,
pub mod_user_id: i32,
@ -250,7 +278,8 @@ pub struct ModBanFromCommunityView {
}
impl ModBanFromCommunityView {
pub fn list(conn: &PgConnection,
pub fn list(
conn: &PgConnection,
from_community_id: Option<i32>,
from_mod_user_id: Option<i32>,
page: Option<i64>,
@ -269,7 +298,11 @@ impl ModBanFromCommunityView {
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,8 +320,10 @@ table! {
}
}
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)]
#[table_name="mod_ban_view"]
#[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "mod_ban_view"]
pub struct ModBanView {
pub id: i32,
pub mod_user_id: i32,
@ -302,7 +337,8 @@ pub struct ModBanView {
}
impl ModBanView {
pub fn list(conn: &PgConnection,
pub fn list(
conn: &PgConnection,
from_mod_user_id: Option<i32>,
page: Option<i64>,
limit: Option<i64>,
@ -316,7 +352,11 @@ impl ModBanView {
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,8 +374,10 @@ table! {
}
}
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)]
#[table_name="mod_add_community_view"]
#[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "mod_add_community_view"]
pub struct ModAddCommunityView {
pub id: i32,
pub mod_user_id: i32,
@ -349,7 +391,8 @@ pub struct ModAddCommunityView {
}
impl ModAddCommunityView {
pub fn list(conn: &PgConnection,
pub fn list(
conn: &PgConnection,
from_community_id: Option<i32>,
from_mod_user_id: Option<i32>,
page: Option<i64>,
@ -368,7 +411,11 @@ impl ModAddCommunityView {
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,8 +431,10 @@ table! {
}
}
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)]
#[table_name="mod_add_view"]
#[derive(
Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize, QueryableByName, Clone,
)]
#[table_name = "mod_add_view"]
pub struct ModAddView {
pub id: i32,
pub mod_user_id: i32,
@ -397,7 +446,8 @@ pub struct ModAddView {
}
impl ModAddView {
pub fn list(conn: &PgConnection,
pub fn list(
conn: &PgConnection,
from_mod_user_id: Option<i32>,
page: Option<i64>,
limit: Option<i64>,
@ -411,6 +461,10 @@ impl ModAddView {
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,8 +1,8 @@
use crate::schema::{post, post_like, post_saved, post_read};
use super::*;
use crate::schema::{post, post_like, post_read, post_saved};
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
#[table_name="post"]
#[table_name = "post"]
pub struct Post {
pub id: i32,
pub name: String,
@ -19,7 +19,7 @@ pub struct Post {
}
#[derive(Insertable, AsChangeset, Clone)]
#[table_name="post"]
#[table_name = "post"]
pub struct PostForm {
pub name: String,
pub url: Option<String>,
@ -36,21 +36,17 @@ pub struct PostForm {
impl Crud<PostForm> for Post {
fn read(conn: &PgConnection, post_id: i32) -> Result<Self, Error> {
use crate::schema::post::dsl::*;
post.find(post_id)
.first::<Self>(conn)
post.find(post_id).first::<Self>(conn)
}
fn delete(conn: &PgConnection, post_id: i32) -> Result<usize, Error> {
use crate::schema::post::dsl::*;
diesel::delete(post.find(post_id))
.execute(conn)
diesel::delete(post.find(post_id)).execute(conn)
}
fn create(conn: &PgConnection, new_post: &PostForm) -> Result<Self, Error> {
use crate::schema::post::dsl::*;
insert_into(post)
.values(new_post)
.get_result::<Self>(conn)
insert_into(post).values(new_post).get_result::<Self>(conn)
}
fn update(conn: &PgConnection, post_id: i32, new_post: &PostForm) -> Result<Self, Error> {
@ -73,14 +69,14 @@ pub struct PostLike {
}
#[derive(Insertable, AsChangeset, Clone)]
#[table_name="post_like"]
#[table_name = "post_like"]
pub struct PostLikeForm {
pub post_id: i32,
pub user_id: i32,
pub score: i16
pub score: i16,
}
impl Likeable <PostLikeForm> for PostLike {
impl Likeable<PostLikeForm> for PostLike {
fn read(conn: &PgConnection, post_id_from: i32) -> Result<Vec<Self>, Error> {
use crate::schema::post_like::dsl::*;
post_like
@ -95,9 +91,11 @@ impl Likeable <PostLikeForm> for PostLike {
}
fn remove(conn: &PgConnection, post_like_form: &PostLikeForm) -> Result<usize, Error> {
use crate::schema::post_like::dsl::*;
diesel::delete(post_like
diesel::delete(
post_like
.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)
}
}
@ -113,13 +111,13 @@ pub struct PostSaved {
}
#[derive(Insertable, AsChangeset, Clone)]
#[table_name="post_saved"]
#[table_name = "post_saved"]
pub struct PostSavedForm {
pub post_id: i32,
pub user_id: i32,
}
impl Saveable <PostSavedForm> for PostSaved {
impl Saveable<PostSavedForm> for PostSaved {
fn save(conn: &PgConnection, post_saved_form: &PostSavedForm) -> Result<Self, Error> {
use crate::schema::post_saved::dsl::*;
insert_into(post_saved)
@ -128,9 +126,11 @@ impl Saveable <PostSavedForm> for PostSaved {
}
fn unsave(conn: &PgConnection, post_saved_form: &PostSavedForm) -> Result<usize, Error> {
use crate::schema::post_saved::dsl::*;
diesel::delete(post_saved
diesel::delete(
post_saved
.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)
}
}
@ -146,13 +146,13 @@ pub struct PostRead {
}
#[derive(Insertable, AsChangeset, Clone)]
#[table_name="post_read"]
#[table_name = "post_read"]
pub struct PostReadForm {
pub post_id: i32,
pub user_id: i32,
}
impl Readable <PostReadForm> for PostRead {
impl Readable<PostReadForm> for PostRead {
fn mark_as_read(conn: &PgConnection, post_read_form: &PostReadForm) -> Result<Self, Error> {
use crate::schema::post_read::dsl::*;
insert_into(post_read)
@ -161,18 +161,20 @@ impl Readable <PostReadForm> for PostRead {
}
fn mark_as_unread(conn: &PgConnection, post_read_form: &PostReadForm) -> Result<usize, Error> {
use crate::schema::post_read::dsl::*;
diesel::delete(post_read
diesel::delete(
post_read
.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)
}
}
#[cfg(test)]
mod tests {
use super::*;
use super::super::community::*;
use super::super::user::*;
use super::*;
#[test]
fn test_crud() {
let conn = establish_connection();
@ -215,7 +217,7 @@ mod tests {
deleted: None,
locked: None,
nsfw: false,
updated: None
updated: None,
};
let inserted_post = Post::create(&conn, &new_post).unwrap();
@ -232,14 +234,14 @@ mod tests {
locked: false,
nsfw: false,
deleted: false,
updated: None
updated: None,
};
// Post Like
let post_like_form = PostLikeForm {
post_id: inserted_post.id,
user_id: inserted_user.id,
score: 1
score: 1,
};
let inserted_post_like = PostLike::like(&conn, &post_like_form).unwrap();
@ -249,7 +251,7 @@ mod tests {
post_id: inserted_post.id,
user_id: inserted_user.id,
published: inserted_post_like.published,
score: 1
score: 1,
};
// Post Save
@ -301,6 +303,5 @@ mod tests {
assert_eq!(1, saved_removed);
assert_eq!(1, read_removed);
assert_eq!(1, num_deleted);
}
}

View file

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

View file

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

View file

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

View file

@ -1,30 +1,34 @@
#![recursion_limit = "512"]
#[macro_use] pub extern crate strum_macros;
#[macro_use] pub extern crate lazy_static;
#[macro_use] pub extern crate failure;
#[macro_use] pub extern crate diesel;
pub extern crate dotenv;
pub extern crate chrono;
pub extern crate serde;
pub extern crate serde_json;
#[macro_use]
pub extern crate strum_macros;
#[macro_use]
pub extern crate lazy_static;
#[macro_use]
pub extern crate failure;
#[macro_use]
pub extern crate diesel;
pub extern crate actix;
pub extern crate actix_web;
pub extern crate rand;
pub extern crate strum;
pub extern crate jsonwebtoken;
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 serde;
pub extern crate serde_json;
pub extern crate strum;
pub mod schema;
pub mod api;
pub mod apub;
pub mod db;
pub mod schema;
pub mod websocket;
use dotenv::dotenv;
use std::env;
use regex::Regex;
use chrono::{DateTime, NaiveDateTime, Utc};
use dotenv::dotenv;
use regex::Regex;
use std::env;
pub struct Settings {
db_url: String,
@ -36,8 +40,7 @@ impl Settings {
fn get() -> Self {
dotenv().ok();
Settings {
db_url: env::var("DATABASE_URL")
.expect("DATABASE_URL must be set"),
db_url: env::var("DATABASE_URL").expect("DATABASE_URL must be set"),
hostname: env::var("HOSTNAME").unwrap_or("rrr".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)]
mod tests {
use crate::{Settings, is_email_regex, remove_slurs, has_slurs};
use crate::{has_slurs, is_email_regex, remove_slurs, Settings};
#[test]
fn test_api() {
assert_eq!(Settings::get().api_endpoint(), "rrr/api/v1");
}
#[test] fn test_email() {
#[test]
fn test_email() {
assert!(is_email_regex("gush@gmail.com"));
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 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(slur_free));
}

View file

@ -23,7 +23,7 @@ fn chat_route(
req: HttpRequest,
stream: web::Payload,
chat_server: web::Data<Addr<ChatServer>>,
) -> Result<HttpResponse, Error> {
) -> Result<HttpResponse, Error> {
ws::start(
WSSession {
cs_addr: chat_server.get_ref().to_owned(),
@ -67,7 +67,8 @@ impl Actor for WSSession {
// before processing any other events.
// across all routes within application
let addr = ctx.address();
self.cs_addr
self
.cs_addr
.send(Connect {
addr: addr.recipient(),
ip: self.ip.to_owned(),
@ -121,7 +122,8 @@ impl StreamHandler<ws::Message, ws::ProtocolError> for WSSession {
let m = text.trim().to_owned();
println!("WEBSOCKET MESSAGE: {:?} from id: {}", &m, self.id);
self.cs_addr
self
.cs_addr
.send(StandardMessage {
id: self.id,
msg: m,

View file

@ -3,28 +3,27 @@
//! room through `ChatServer`.
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 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::user::*;
use crate::api::comment::*;
use crate::api::community::*;
use crate::api::post::*;
use crate::api::comment::*;
use crate::api::site::*;
use crate::api::user::*;
use crate::api::*;
const RATE_LIMIT_MESSAGE: i32 = 30;
const RATE_LIMIT_MESSAGES_PER_SECOND: i32 = 60;
const RATE_LIMIT_POST: i32 = 1;
const RATE_LIMIT_POSTS_PER_SECOND: i32 = 60*10;
const RATE_LIMIT_POSTS_PER_SECOND: i32 = 60 * 10;
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
#[derive(Message)]
@ -73,7 +72,7 @@ impl actix::Message for StandardMessage {
#[derive(Debug)]
pub struct RateLimitBucket {
last_checked: SystemTime,
allowance: f64
allowance: f64,
}
pub struct SessionInfo {
@ -132,9 +131,14 @@ impl ChatServer {
&self.rooms.get_mut(&room_id).unwrap().insert(id);
}
fn send_community_message(&self, community_id: &i32, message: &str, skip_id: usize) -> Result<(), Error> {
use crate::db::*;
fn send_community_message(
&self,
community_id: &i32,
message: &str,
skip_id: usize,
) -> Result<(), Error> {
use crate::db::post_view::*;
use crate::db::*;
let conn = establish_connection();
let posts = PostView::list(
&conn,
@ -149,7 +153,8 @@ impl ChatServer {
false,
false,
None,
Some(9999))?;
Some(9999),
)?;
for post in posts {
self.send_room_message(&post.id, message, skip_id);
}
@ -186,7 +191,10 @@ impl ChatServer {
}
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 {
op: "Rate Limit".to_string(),
message: format!("Too many requests. {} per {} seconds", rate, per),
@ -204,7 +212,6 @@ impl ChatServer {
}
}
/// Make actor from `ChatServer`
impl Actor for ChatServer {
/// 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;
fn handle(&mut self, msg: Connect, _ctx: &mut Context<Self>) -> Self::Result {
// notify all users in same room
// 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>();
println!("{} joined", &msg.ip);
self.sessions.insert(id, SessionInfo {
self.sessions.insert(
id,
SessionInfo {
addr: msg.addr,
ip: msg.ip.to_owned(),
});
},
);
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(),
allowance: -2f64,
});
},
);
}
id
@ -248,7 +260,6 @@ impl Handler<Disconnect> for ChatServer {
type Result = ();
fn handle(&mut self, msg: Disconnect, _: &mut Context<Self>) {
// let mut rooms: Vec<i32> = Vec::new();
// remove address
@ -267,12 +278,10 @@ impl Handler<Disconnect> for ChatServer {
impl Handler<StandardMessage> for ChatServer {
type Result = MessageResult<StandardMessage>;
fn handle(&mut self, msg: StandardMessage, _: &mut Context<Self>) -> Self::Result {
let msg_out = match parse_json_message(self, msg) {
Ok(m) => m,
Err(e) => e.to_string()
Err(e) => e.to_string(),
};
MessageResult(msg_out)
@ -280,7 +289,6 @@ impl Handler<StandardMessage> for ChatServer {
}
fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<String, Error> {
let json: Value = serde_json::from_str(&msg.msg)?;
let data = &json["data"].to_string();
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 res = Oper::new(user_operation, login).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::Register => {
chat.check_rate_limit_register(msg.id)?;
let register: Register = serde_json::from_str(data)?;
let res = Oper::new(user_operation, register).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::GetUserDetails => {
let get_user_details: GetUserDetails = serde_json::from_str(data)?;
let res = Oper::new(user_operation, get_user_details).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::SaveUserSettings => {
let save_user_settings: SaveUserSettings = serde_json::from_str(data)?;
let res = Oper::new(user_operation, save_user_settings).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::AddAdmin => {
let add_admin: AddAdmin = serde_json::from_str(data)?;
let res = Oper::new(user_operation, add_admin).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::BanUser => {
let ban_user: BanUser = serde_json::from_str(data)?;
let res = Oper::new(user_operation, ban_user).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::GetReplies => {
let get_replies: GetReplies = serde_json::from_str(data)?;
let res = Oper::new(user_operation, get_replies).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::MarkAllAsRead => {
let mark_all_as_read: MarkAllAsRead = serde_json::from_str(data)?;
let res = Oper::new(user_operation, mark_all_as_read).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::GetCommunity => {
let get_community: GetCommunity = serde_json::from_str(data)?;
let res = Oper::new(user_operation, get_community).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::ListCommunities => {
let list_communities: ListCommunities = serde_json::from_str(data)?;
let res = Oper::new(user_operation, list_communities).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::CreateCommunity => {
chat.check_rate_limit_register(msg.id)?;
let create_community: CreateCommunity = serde_json::from_str(data)?;
let res = Oper::new(user_operation, create_community).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::EditCommunity => {
let edit_community: EditCommunity = serde_json::from_str(data)?;
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)?;
chat.send_community_message(&community_sent.community.id, &community_sent_str, msg.id)?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::FollowCommunity => {
let follow_community: FollowCommunity = serde_json::from_str(data)?;
let res = Oper::new(user_operation, follow_community).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::GetFollowedCommunities => {
let followed_communities: GetFollowedCommunities = serde_json::from_str(data)?;
let res = Oper::new(user_operation, followed_communities).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::BanFromCommunity => {
let ban_from_community: BanFromCommunity = serde_json::from_str(data)?;
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)?;
chat.send_community_message(&community_id, &res_str, msg.id)?;
Ok(res_str)
},
}
UserOperation::AddModToCommunity => {
let mod_add_to_community: AddModToCommunity = serde_json::from_str(data)?;
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)?;
chat.send_community_message(&community_id, &res_str, msg.id)?;
Ok(res_str)
},
}
UserOperation::ListCategories => {
let list_categories: ListCategories = ListCategories;
let res = Oper::new(user_operation, list_categories).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::CreatePost => {
chat.check_rate_limit_post(msg.id)?;
let create_post: CreatePost = serde_json::from_str(data)?;
let res = Oper::new(user_operation, create_post).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::GetPost => {
let get_post: GetPost = serde_json::from_str(data)?;
chat.join_room(get_post.id, msg.id);
let res = Oper::new(user_operation, get_post).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::GetPosts => {
let get_posts: GetPosts = serde_json::from_str(data)?;
let res = Oper::new(user_operation, get_posts).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::CreatePostLike => {
chat.check_rate_limit_message(msg.id)?;
let create_post_like: CreatePostLike = serde_json::from_str(data)?;
let res = Oper::new(user_operation, create_post_like).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::EditPost => {
let edit_post: EditPost = serde_json::from_str(data)?;
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)?;
chat.send_room_message(&post_sent.post.id, &post_sent_str, msg.id);
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::SavePost => {
let save_post: SavePost = serde_json::from_str(data)?;
let res = Oper::new(user_operation, save_post).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::CreateComment => {
chat.check_rate_limit_message(msg.id)?;
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)?;
chat.send_room_message(&post_id, &comment_sent_str, msg.id);
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::EditComment => {
let edit_comment: EditComment = serde_json::from_str(data)?;
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)?;
chat.send_room_message(&post_id, &comment_sent_str, msg.id);
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::SaveComment => {
let save_comment: SaveComment = serde_json::from_str(data)?;
let res = Oper::new(user_operation, save_comment).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::CreateCommentLike => {
chat.check_rate_limit_message(msg.id)?;
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)?;
chat.send_room_message(&post_id, &comment_sent_str, msg.id);
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::GetModlog => {
let get_modlog: GetModlog = serde_json::from_str(data)?;
let res = Oper::new(user_operation, get_modlog).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::CreateSite => {
let create_site: CreateSite = serde_json::from_str(data)?;
let res = Oper::new(user_operation, create_site).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::EditSite => {
let edit_site: EditSite = serde_json::from_str(data)?;
let res = Oper::new(user_operation, edit_site).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::GetSite => {
let get_site: GetSite = serde_json::from_str(data)?;
let res = Oper::new(user_operation, get_site).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::Search => {
let search: Search = serde_json::from_str(data)?;
let res = Oper::new(user_operation, search).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::TransferCommunity => {
let transfer_community: TransferCommunity = serde_json::from_str(data)?;
let res = Oper::new(user_operation, transfer_community).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
UserOperation::TransferSite => {
let transfer_site: TransferSite = serde_json::from_str(data)?;
let res = Oper::new(user_operation, transfer_site).perform()?;
Ok(serde_json::to_string(&res)?)
},
}
}
}