From 3ff85b1fdb0d80f860fe44a24930bffb73c258a0 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Tue, 9 Apr 2019 23:19:12 -0700 Subject: [PATCH] Adding trending communities. - Fixes #29 - Communities fetching now has sort and limit. --- server/src/actions/community_view.rs | 25 ++++++++---- server/src/websocket_server/server.rs | 6 ++- ui/src/components/communities.tsx | 9 ++++- ui/src/components/login.tsx | 2 +- ui/src/components/main.tsx | 56 ++++++++++++++++++++------- ui/src/components/post-form.tsx | 8 +++- ui/src/interfaces.ts | 6 +++ ui/src/services/WebSocketService.ts | 8 ++-- 8 files changed, 89 insertions(+), 31 deletions(-) diff --git a/server/src/actions/community_view.rs b/server/src/actions/community_view.rs index 185484bf0..cb89b2264 100644 --- a/server/src/actions/community_view.rs +++ b/server/src/actions/community_view.rs @@ -2,6 +2,7 @@ extern crate diesel; use diesel::*; use diesel::result::Error; use serde::{Deserialize, Serialize}; +use {SortType}; table! { community_view (id) { @@ -83,17 +84,27 @@ impl CommunityView { query.first::(conn) } - pub fn list_all(conn: &PgConnection, from_user_id: Option) -> Result, Error> { + pub fn list(conn: &PgConnection, from_user_id: Option, sort: SortType, limit: Option) -> Result, Error> { use actions::community_view::community_view::dsl::*; 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()); + + match sort { + 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.desc(), number_of_subscribers.desc())), + None => query = query.order_by(number_of_subscribers.desc()).filter(user_id.is_null()) + } + } + _ => () + }; + + if let Some(limit) = limit { + query = query.limit(limit); }; query.load::(conn) diff --git a/server/src/websocket_server/server.rs b/server/src/websocket_server/server.rs index 42124d2d6..137761ab3 100644 --- a/server/src/websocket_server/server.rs +++ b/server/src/websocket_server/server.rs @@ -111,6 +111,8 @@ pub struct CommunityResponse { #[derive(Serialize, Deserialize)] pub struct ListCommunities { + sort: String, + limit: Option, auth: Option } @@ -675,7 +677,9 @@ impl Perform for ListCommunities { None => None }; - let communities: Vec = CommunityView::list_all(&conn, user_id).unwrap(); + let sort = SortType::from_str(&self.sort).expect("listing sort"); + + let communities: Vec = CommunityView::list(&conn, user_id, sort, self.limit).unwrap(); // Return the jwt serde_json::to_string( diff --git a/ui/src/components/communities.tsx b/ui/src/components/communities.tsx index 268aa1151..4d2512ccc 100644 --- a/ui/src/components/communities.tsx +++ b/ui/src/components/communities.tsx @@ -2,7 +2,7 @@ import { Component, linkEvent } from 'inferno'; import { Link } from 'inferno-router'; import { Subscription } from "rxjs"; import { retryWhen, delay, take } from 'rxjs/operators'; -import { UserOperation, Community, ListCommunitiesResponse, CommunityResponse, FollowCommunityForm } from '../interfaces'; +import { UserOperation, Community, ListCommunitiesResponse, CommunityResponse, FollowCommunityForm, ListCommunitiesForm, SortType } from '../interfaces'; import { WebSocketService } from '../services'; import { msgOp } from '../utils'; @@ -30,7 +30,12 @@ export class Communities extends Component { (err) => console.error(err), () => console.log('complete') ); - WebSocketService.Instance.listCommunities(); + + let listCommunitiesForm: ListCommunitiesForm = { + sort: SortType[SortType.TopAll] + } + + WebSocketService.Instance.listCommunities(listCommunitiesForm); } diff --git a/ui/src/components/login.tsx b/ui/src/components/login.tsx index 933b08be6..2d2339f55 100644 --- a/ui/src/components/login.tsx +++ b/ui/src/components/login.tsx @@ -103,7 +103,7 @@ export class Login extends Component {
- +
diff --git a/ui/src/components/main.tsx b/ui/src/components/main.tsx index 8faf858ae..55066d009 100644 --- a/ui/src/components/main.tsx +++ b/ui/src/components/main.tsx @@ -2,13 +2,14 @@ import { Component } from 'inferno'; import { Link } from 'inferno-router'; import { Subscription } from "rxjs"; import { retryWhen, delay, take } from 'rxjs/operators'; -import { UserOperation, CommunityUser, GetFollowedCommunitiesResponse } from '../interfaces'; +import { UserOperation, CommunityUser, GetFollowedCommunitiesResponse, ListCommunitiesForm, ListCommunitiesResponse, Community, SortType } from '../interfaces'; import { WebSocketService, UserService } from '../services'; import { PostListings } from './post-listings'; import { msgOp, repoUrl } from '../utils'; interface State { subscribedCommunities: Array; + trendingCommunities: Array; loading: boolean; } @@ -17,6 +18,7 @@ export class Main extends Component { private subscription: Subscription; private emptyState: State = { subscribedCommunities: [], + trendingCommunities: [], loading: true } @@ -36,6 +38,13 @@ export class Main extends Component { if (UserService.Instance.loggedIn) { WebSocketService.Instance.getFollowedCommunities(); } + + let listCommunitiesForm: ListCommunitiesForm = { + sort: SortType[SortType.New], + limit: 8 + } + + WebSocketService.Instance.listCommunities(listCommunitiesForm); } componentWillUnmount() { @@ -50,21 +59,22 @@ export class Main extends Component {
- {UserService.Instance.loggedIn ? + {this.state.loading ? +

: +
+ {this.trendingCommunities()} + {UserService.Instance.loggedIn ?
- {this.state.loading ? -

: -
-

Subscribed forums

-
    - {this.state.subscribedCommunities.map(community => -
  • {community.community_name}
  • - )} -
-
- } +

Subscribed forums

+
    + {this.state.subscribedCommunities.map(community => +
  • {community.community_name}
  • + )} +
: - this.landing() + this.landing() + } +
}
@@ -72,6 +82,19 @@ export class Main extends Component { ) } + trendingCommunities() { + return ( +
+

Trending forums

+
    + {this.state.trendingCommunities.map(community => +
  • {community.name}
  • + )} +
+
+ ) + } + landing() { return (
@@ -99,6 +122,11 @@ export class Main extends Component { this.state.subscribedCommunities = res.communities; this.state.loading = false; this.setState(this.state); + } else if (op == UserOperation.ListCommunities) { + let res: ListCommunitiesResponse = msg; + this.state.trendingCommunities = res.communities; + this.state.loading = false; + this.setState(this.state); } } } diff --git a/ui/src/components/post-form.tsx b/ui/src/components/post-form.tsx index 03ace3802..67a3f42e0 100644 --- a/ui/src/components/post-form.tsx +++ b/ui/src/components/post-form.tsx @@ -1,7 +1,7 @@ import { Component, linkEvent } from 'inferno'; import { Subscription } from "rxjs"; import { retryWhen, delay, take } from 'rxjs/operators'; -import { PostForm as PostFormI, Post, PostResponse, UserOperation, Community, ListCommunitiesResponse } from '../interfaces'; +import { PostForm as PostFormI, Post, PostResponse, UserOperation, Community, ListCommunitiesResponse, ListCommunitiesForm, SortType } from '../interfaces'; import { WebSocketService } from '../services'; import { msgOp } from '../utils'; import * as autosize from 'autosize'; @@ -56,7 +56,11 @@ export class PostForm extends Component { () => console.log('complete') ); - WebSocketService.Instance.listCommunities(); + let listCommunitiesForm: ListCommunitiesForm = { + sort: SortType[SortType.TopAll] + } + + WebSocketService.Instance.listCommunities(listCommunitiesForm); } componentDidMount() { diff --git a/ui/src/interfaces.ts b/ui/src/interfaces.ts index 660886479..b6139134d 100644 --- a/ui/src/interfaces.ts +++ b/ui/src/interfaces.ts @@ -67,6 +67,12 @@ export interface CommunityResponse { community: Community; } +export interface ListCommunitiesForm { + sort: string; + limit?: number; + auth?: string; +} + export interface ListCommunitiesResponse { op: string; communities: Array; diff --git a/ui/src/services/WebSocketService.ts b/ui/src/services/WebSocketService.ts index b5efd6a7f..99d65adfa 100644 --- a/ui/src/services/WebSocketService.ts +++ b/ui/src/services/WebSocketService.ts @@ -1,5 +1,5 @@ import { wsUri } from '../env'; -import { LoginForm, RegisterForm, UserOperation, CommunityForm, PostForm, CommentForm, CommentLikeForm, GetPostsForm, CreatePostLikeForm, FollowCommunityForm, GetUserDetailsForm } from '../interfaces'; +import { LoginForm, RegisterForm, UserOperation, CommunityForm, PostForm, CommentForm, CommentLikeForm, GetPostsForm, CreatePostLikeForm, FollowCommunityForm, GetUserDetailsForm, ListCommunitiesForm } from '../interfaces'; import { webSocket } from 'rxjs/webSocket'; import { Subject } from 'rxjs'; import { retryWhen, delay, take } from 'rxjs/operators'; @@ -47,9 +47,9 @@ export class WebSocketService { this.subject.next(this.wsSendWrapper(UserOperation.FollowCommunity, followCommunityForm)); } - public listCommunities() { - let data = {auth: UserService.Instance.auth }; - this.subject.next(this.wsSendWrapper(UserOperation.ListCommunities, data)); + public listCommunities(form: ListCommunitiesForm) { + this.setAuth(form, false); + this.subject.next(this.wsSendWrapper(UserOperation.ListCommunities, form)); } public getFollowedCommunities() {