summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorDessalines <tyhou13@gmx.com>2019-04-04 23:26:38 -0700
committerDessalines <tyhou13@gmx.com>2019-04-04 23:26:38 -0700
commit2c66d86e2686c09e56d7b65ab679ce929d499478 (patch)
tree8d4f2fb0e95ba245a58b8730bb5fd89967e2e69c /server
parent6a3bea1f50137993c74f8c38e417892929022234 (diff)
Adding subscribe to communities.
- Adding subscribe. Fixes #12. Fixes #27.
Diffstat (limited to 'server')
-rw-r--r--server/migrations/2019-04-03-155205_create_community_view/up.sql34
-rw-r--r--server/src/actions/community_view.rs37
-rw-r--r--server/src/actions/post_view.rs2
-rw-r--r--server/src/websocket_server/server.rs119
4 files changed, 167 insertions, 25 deletions
diff --git a/server/migrations/2019-04-03-155205_create_community_view/up.sql b/server/migrations/2019-04-03-155205_create_community_view/up.sql
index f2f4a766..7c608742 100644
--- a/server/migrations/2019-04-03-155205_create_community_view/up.sql
+++ b/server/migrations/2019-04-03-155205_create_community_view/up.sql
@@ -1,11 +1,31 @@
create view community_view as
-select *,
-(select name from user_ u where c.creator_id = u.id) as creator_name,
-(select name from category ct where c.category_id = ct.id) as category_name,
-(select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers,
-(select count(*) from post p where p.community_id = c.id) as number_of_posts,
-(select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments
-from community c;
+with all_community as
+(
+ select *,
+ (select name from user_ u where c.creator_id = u.id) as creator_name,
+ (select name from category ct where c.category_id = ct.id) as category_name,
+ (select count(*) from community_follower cf where cf.community_id = c.id) as number_of_subscribers,
+ (select count(*) from post p where p.community_id = c.id) as number_of_posts,
+ (select count(*) from comment co, post p where c.id = p.community_id and p.id = co.post_id) as number_of_comments
+ from community c
+)
+
+select
+ac.*,
+u.id as user_id,
+cf.id::boolean as subscribed
+from user_ u
+cross join all_community ac
+left join community_follower cf on u.id = cf.user_id and ac.id = cf.community_id
+
+union all
+
+select
+ac.*,
+null as user_id,
+null as subscribed
+from all_community ac
+;
create view community_moderator_view as
select *,
diff --git a/server/src/actions/community_view.rs b/server/src/actions/community_view.rs
index eafda161..7eb07a16 100644
--- a/server/src/actions/community_view.rs
+++ b/server/src/actions/community_view.rs
@@ -18,6 +18,8 @@ table! {
number_of_subscribers -> BigInt,
number_of_posts -> BigInt,
number_of_comments -> BigInt,
+ user_id -> Nullable<Int4>,
+ subscribed -> Nullable<Bool>,
}
}
@@ -58,18 +60,43 @@ pub struct CommunityView {
pub category_name: String,
pub number_of_subscribers: i64,
pub number_of_posts: i64,
- pub number_of_comments: i64
+ pub number_of_comments: i64,
+ pub user_id: Option<i32>,
+ pub subscribed: Option<bool>,
}
impl CommunityView {
- pub fn read(conn: &PgConnection, from_community_id: i32) -> Result<Self, Error> {
+ pub fn read(conn: &PgConnection, from_community_id: i32, from_user_id: Option<i32>) -> Result<Self, Error> {
use actions::community_view::community_view::dsl::*;
- community_view.find(from_community_id).first::<Self>(conn)
+
+ let mut query = community_view.into_boxed();
+
+ query = query.filter(id.eq(from_community_id));
+
+ // The view lets you pass a null user_id, if you're not logged in
+ if let Some(from_user_id) = from_user_id {
+ query = query.filter(user_id.eq(from_user_id));
+ } else {
+ query = query.filter(user_id.is_null());
+ };
+
+ query.first::<Self>(conn)
}
- pub fn list_all(conn: &PgConnection) -> Result<Vec<Self>, Error> {
+ pub fn list_all(conn: &PgConnection, from_user_id: Option<i32>) -> Result<Vec<Self>, Error> {
use actions::community_view::community_view::dsl::*;
- community_view.load::<Self>(conn)
+ let mut query = community_view.into_boxed();
+
+ // The view lets you pass a null user_id, if you're not logged in
+ if let Some(from_user_id) = from_user_id {
+ query = query.filter(user_id.eq(from_user_id))
+ .order_by((subscribed.desc(), number_of_subscribers.desc()));
+ } else {
+ query = query.filter(user_id.is_null())
+ .order_by(number_of_subscribers.desc());
+ };
+
+ query.load::<Self>(conn)
}
}
diff --git a/server/src/actions/post_view.rs b/server/src/actions/post_view.rs
index f53a9f0c..c48c651e 100644
--- a/server/src/actions/post_view.rs
+++ b/server/src/actions/post_view.rs
@@ -113,7 +113,7 @@ impl PostView {
query = query.filter(user_id.eq(from_user_id));
} else {
query = query.filter(user_id.is_null());
- }
+ };
query.first::<Self>(conn)
}
diff --git a/server/src/websocket_server/server.rs b/server/src/websocket_server/server.rs
index a0d12935..fe7cd0e6 100644
--- a/server/src/websocket_server/server.rs
+++ b/server/src/websocket_server/server.rs
@@ -22,7 +22,7 @@ use actions::community_view::*;
#[derive(EnumString,ToString,Debug)]
pub enum UserOperation {
- Login, Register, CreateCommunity, CreatePost, ListCommunities, ListCategories, GetPost, GetCommunity, CreateComment, EditComment, CreateCommentLike, GetPosts, CreatePostLike, EditPost, EditCommunity
+ Login, Register, CreateCommunity, CreatePost, ListCommunities, ListCategories, GetPost, GetCommunity, CreateComment, EditComment, CreateCommentLike, GetPosts, CreatePostLike, EditPost, EditCommunity, FollowCommunity
}
#[derive(Serialize, Deserialize)]
@@ -109,7 +109,9 @@ pub struct CommunityResponse {
}
#[derive(Serialize, Deserialize)]
-pub struct ListCommunities;
+pub struct ListCommunities {
+ auth: Option<String>
+}
#[derive(Serialize, Deserialize)]
pub struct ListCommunitiesResponse {
@@ -174,7 +176,8 @@ pub struct GetPostsResponse {
#[derive(Serialize, Deserialize)]
pub struct GetCommunity {
- id: i32
+ id: i32,
+ auth: Option<String>
}
#[derive(Serialize, Deserialize)]
@@ -251,6 +254,13 @@ pub struct EditCommunity {
auth: String
}
+#[derive(Serialize, Deserialize)]
+pub struct FollowCommunity {
+ community_id: i32,
+ follow: bool,
+ auth: String
+}
+
/// `ChatServer` manages chat rooms and responsible for coordinating chat
/// session. implementation is super primitive
pub struct ChatServer {
@@ -389,7 +399,7 @@ impl Handler<StandardMessage> for ChatServer {
create_community.perform(self, msg.id)
},
UserOperation::ListCommunities => {
- let list_communities: ListCommunities = ListCommunities;
+ let list_communities: ListCommunities = serde_json::from_str(&data.to_string()).unwrap();
list_communities.perform(self, msg.id)
},
UserOperation::ListCategories => {
@@ -436,6 +446,10 @@ impl Handler<StandardMessage> for ChatServer {
let edit_community: EditCommunity = serde_json::from_str(&data.to_string()).unwrap();
edit_community.perform(self, msg.id)
},
+ UserOperation::FollowCommunity => {
+ let follow_community: FollowCommunity = serde_json::from_str(&data.to_string()).unwrap();
+ follow_community.perform(self, msg.id)
+ },
_ => {
let e = ErrorMessage {
op: "Unknown".to_string(),
@@ -599,7 +613,7 @@ impl Perform for CreateCommunity {
}
};
- let community_view = CommunityView::read(&conn, inserted_community.id).unwrap();
+ let community_view = CommunityView::read(&conn, inserted_community.id, Some(user_id)).unwrap();
serde_json::to_string(
&CommunityResponse {
@@ -620,7 +634,20 @@ impl Perform for ListCommunities {
let conn = establish_connection();
- let communities: Vec<CommunityView> = CommunityView::list_all(&conn).unwrap();
+ let user_id: Option<i32> = match &self.auth {
+ Some(auth) => {
+ match Claims::decode(&auth) {
+ Ok(claims) => {
+ let user_id = claims.claims.id;
+ Some(user_id)
+ }
+ Err(_e) => None
+ }
+ }
+ None => None
+ };
+
+ let communities: Vec<CommunityView> = CommunityView::list_all(&conn, user_id).unwrap();
// Return the jwt
serde_json::to_string(
@@ -767,7 +794,7 @@ impl Perform for GetPost {
let comments = CommentView::list(&conn, self.id, user_id).unwrap();
- let community = CommunityView::read(&conn, post_view.community_id).unwrap();
+ let community = CommunityView::read(&conn, post_view.community_id, user_id).unwrap();
let moderators = CommunityModeratorView::for_community(&conn, post_view.community_id).unwrap();
@@ -794,7 +821,20 @@ impl Perform for GetCommunity {
let conn = establish_connection();
- let community_view = match CommunityView::read(&conn, self.id) {
+ let user_id: Option<i32> = match &self.auth {
+ Some(auth) => {
+ match Claims::decode(&auth) {
+ Ok(claims) => {
+ let user_id = claims.claims.id;
+ Some(user_id)
+ }
+ Err(_e) => None
+ }
+ }
+ None => None
+ };
+
+ let community_view = match CommunityView::read(&conn, self.id, user_id) {
Ok(community) => community,
Err(_e) => {
return self.error("Couldn't find Community");
@@ -917,7 +957,7 @@ impl Perform for EditComment {
// Verify its the creator
let orig_comment = Comment::read(&conn, self.edit_id).unwrap();
if user_id != orig_comment.creator_id {
- return self.error("Incorrect creator.");
+ return self.error("Incorrect creator.");
}
let comment_form = CommentForm {
@@ -1158,7 +1198,7 @@ impl Perform for EditPost {
// Verify its the creator
let orig_post = Post::read(&conn, self.edit_id).unwrap();
if user_id != orig_post.creator_id {
- return self.error("Incorrect creator.");
+ return self.error("Incorrect creator.");
}
let post_form = PostForm {
@@ -1227,7 +1267,7 @@ impl Perform for EditCommunity {
let moderator_view = CommunityModeratorView::for_community(&conn, self.edit_id).unwrap();
let mod_ids: Vec<i32> = moderator_view.into_iter().map(|m| m.user_id).collect();
if !mod_ids.contains(&user_id) {
- return self.error("Incorrect creator.");
+ return self.error("Incorrect creator.");
};
let community_form = CommunityForm {
@@ -1246,7 +1286,7 @@ impl Perform for EditCommunity {
}
};
- let community_view = CommunityView::read(&conn, self.edit_id).unwrap();
+ let community_view = CommunityView::read(&conn, self.edit_id, Some(user_id)).unwrap();
// Do the subscriber stuff here
// let mut community_sent = post_view.clone();
@@ -1273,6 +1313,61 @@ impl Perform for EditCommunity {
community_out
}
}
+
+
+impl Perform for FollowCommunity {
+ fn op_type(&self) -> UserOperation {
+ UserOperation::FollowCommunity
+ }
+
+ fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> String {
+
+ let conn = establish_connection();
+
+ let claims = match Claims::decode(&self.auth) {
+ Ok(claims) => claims.claims,
+ Err(_e) => {
+ return self.error("Not logged in.");
+ }
+ };
+
+ let user_id = claims.id;
+
+ let community_follower_form = CommunityFollowerForm {
+ community_id: self.community_id,
+ user_id: user_id
+ };
+
+ if self.follow {
+
+ match CommunityFollower::follow(&conn, &community_follower_form) {
+ Ok(user) => user,
+ Err(_e) => {
+ return self.error("Community follower already exists.");
+ }
+ };
+ } else {
+ match CommunityFollower::ignore(&conn, &community_follower_form) {
+ Ok(user) => user,
+ Err(_e) => {
+ return self.error("Community follower already exists.");
+ }
+ };
+ }
+
+ let community_view = CommunityView::read(&conn, self.community_id, Some(user_id)).unwrap();
+
+ serde_json::to_string(
+ &CommunityResponse {
+ op: self.op_type().to_string(),
+ community: community_view
+ }
+ )
+ .unwrap()
+ }
+}
+
+
// impl Handler<Login> for ChatServer {
// type Result = MessageResult<Login>;