mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-16 17:34:00 +00:00
Adding trending communities.
- Fixes #29 - Communities fetching now has sort and limit.
This commit is contained in:
parent
42939df040
commit
3ff85b1fdb
8 changed files with 89 additions and 31 deletions
|
@ -2,6 +2,7 @@ extern crate diesel;
|
||||||
use diesel::*;
|
use diesel::*;
|
||||||
use diesel::result::Error;
|
use diesel::result::Error;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use {SortType};
|
||||||
|
|
||||||
table! {
|
table! {
|
||||||
community_view (id) {
|
community_view (id) {
|
||||||
|
@ -83,17 +84,27 @@ impl CommunityView {
|
||||||
query.first::<Self>(conn)
|
query.first::<Self>(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_all(conn: &PgConnection, from_user_id: Option<i32>) -> Result<Vec<Self>, Error> {
|
pub fn list(conn: &PgConnection, from_user_id: Option<i32>, sort: SortType, limit: Option<i64>) -> Result<Vec<Self>, Error> {
|
||||||
use actions::community_view::community_view::dsl::*;
|
use actions::community_view::community_view::dsl::*;
|
||||||
let mut query = community_view.into_boxed();
|
let mut query = community_view.into_boxed();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// The view lets you pass a null user_id, if you're not logged in
|
// The view lets you pass a null user_id, if you're not logged in
|
||||||
if let Some(from_user_id) = from_user_id {
|
|
||||||
query = query.filter(user_id.eq(from_user_id))
|
match sort {
|
||||||
.order_by((subscribed.desc(), number_of_subscribers.desc()));
|
SortType::New => query = query.order_by(published.desc()).filter(user_id.is_null()),
|
||||||
} else {
|
SortType::TopAll => {
|
||||||
query = query.filter(user_id.is_null())
|
match from_user_id {
|
||||||
.order_by(number_of_subscribers.desc());
|
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::<Self>(conn)
|
query.load::<Self>(conn)
|
||||||
|
|
|
@ -111,6 +111,8 @@ pub struct CommunityResponse {
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct ListCommunities {
|
pub struct ListCommunities {
|
||||||
|
sort: String,
|
||||||
|
limit: Option<i64>,
|
||||||
auth: Option<String>
|
auth: Option<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -675,7 +677,9 @@ impl Perform for ListCommunities {
|
||||||
None => None
|
None => None
|
||||||
};
|
};
|
||||||
|
|
||||||
let communities: Vec<CommunityView> = CommunityView::list_all(&conn, user_id).unwrap();
|
let sort = SortType::from_str(&self.sort).expect("listing sort");
|
||||||
|
|
||||||
|
let communities: Vec<CommunityView> = CommunityView::list(&conn, user_id, sort, self.limit).unwrap();
|
||||||
|
|
||||||
// Return the jwt
|
// Return the jwt
|
||||||
serde_json::to_string(
|
serde_json::to_string(
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { Component, linkEvent } from 'inferno';
|
||||||
import { Link } from 'inferno-router';
|
import { Link } from 'inferno-router';
|
||||||
import { Subscription } from "rxjs";
|
import { Subscription } from "rxjs";
|
||||||
import { retryWhen, delay, take } from 'rxjs/operators';
|
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 { WebSocketService } from '../services';
|
||||||
import { msgOp } from '../utils';
|
import { msgOp } from '../utils';
|
||||||
|
|
||||||
|
@ -30,7 +30,12 @@ export class Communities extends Component<any, CommunitiesState> {
|
||||||
(err) => console.error(err),
|
(err) => console.error(err),
|
||||||
() => console.log('complete')
|
() => console.log('complete')
|
||||||
);
|
);
|
||||||
WebSocketService.Instance.listCommunities();
|
|
||||||
|
let listCommunitiesForm: ListCommunitiesForm = {
|
||||||
|
sort: SortType[SortType.TopAll]
|
||||||
|
}
|
||||||
|
|
||||||
|
WebSocketService.Instance.listCommunities(listCommunitiesForm);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,7 @@ export class Login extends Component<any, State> {
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-sm-2 col-form-label">Email</label>
|
<label class="col-sm-2 col-form-label">Email</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<input type="email" class="form-control" value={this.state.registerForm.email} onInput={linkEvent(this, this.handleRegisterEmailChange)} minLength={3} />
|
<input type="email" class="form-control" placeholder="Optional" value={this.state.registerForm.email} onInput={linkEvent(this, this.handleRegisterEmailChange)} minLength={3} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
|
|
|
@ -2,13 +2,14 @@ import { Component } from 'inferno';
|
||||||
import { Link } from 'inferno-router';
|
import { Link } from 'inferno-router';
|
||||||
import { Subscription } from "rxjs";
|
import { Subscription } from "rxjs";
|
||||||
import { retryWhen, delay, take } from 'rxjs/operators';
|
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 { WebSocketService, UserService } from '../services';
|
||||||
import { PostListings } from './post-listings';
|
import { PostListings } from './post-listings';
|
||||||
import { msgOp, repoUrl } from '../utils';
|
import { msgOp, repoUrl } from '../utils';
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
subscribedCommunities: Array<CommunityUser>;
|
subscribedCommunities: Array<CommunityUser>;
|
||||||
|
trendingCommunities: Array<Community>;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +18,7 @@ export class Main extends Component<any, State> {
|
||||||
private subscription: Subscription;
|
private subscription: Subscription;
|
||||||
private emptyState: State = {
|
private emptyState: State = {
|
||||||
subscribedCommunities: [],
|
subscribedCommunities: [],
|
||||||
|
trendingCommunities: [],
|
||||||
loading: true
|
loading: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +38,13 @@ export class Main extends Component<any, State> {
|
||||||
if (UserService.Instance.loggedIn) {
|
if (UserService.Instance.loggedIn) {
|
||||||
WebSocketService.Instance.getFollowedCommunities();
|
WebSocketService.Instance.getFollowedCommunities();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let listCommunitiesForm: ListCommunitiesForm = {
|
||||||
|
sort: SortType[SortType.New],
|
||||||
|
limit: 8
|
||||||
|
}
|
||||||
|
|
||||||
|
WebSocketService.Instance.listCommunities(listCommunitiesForm);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
@ -50,25 +59,39 @@ export class Main extends Component<any, State> {
|
||||||
<PostListings />
|
<PostListings />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-4">
|
<div class="col-12 col-md-4">
|
||||||
{UserService.Instance.loggedIn ?
|
|
||||||
<div>
|
|
||||||
{this.state.loading ?
|
{this.state.loading ?
|
||||||
<h4><svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg></h4> :
|
<h4><svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg></h4> :
|
||||||
|
<div>
|
||||||
|
{this.trendingCommunities()}
|
||||||
|
{UserService.Instance.loggedIn ?
|
||||||
<div>
|
<div>
|
||||||
<h4>Subscribed forums</h4>
|
<h4>Subscribed forums</h4>
|
||||||
<ul class="list-unstyled">
|
<ul class="list-inline">
|
||||||
{this.state.subscribedCommunities.map(community =>
|
{this.state.subscribedCommunities.map(community =>
|
||||||
<li><Link to={`/community/${community.community_id}`}>{community.community_name}</Link></li>
|
<li class="list-inline-item"><Link to={`/community/${community.community_id}`}>{community.community_name}</Link></li>
|
||||||
)}
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div> :
|
</div> :
|
||||||
this.landing()
|
this.landing()
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
trendingCommunities() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h4>Trending forums</h4>
|
||||||
|
<ul class="list-inline">
|
||||||
|
{this.state.trendingCommunities.map(community =>
|
||||||
|
<li class="list-inline-item"><Link to={`/community/${community.id}`}>{community.name}</Link></li>
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,6 +122,11 @@ export class Main extends Component<any, State> {
|
||||||
this.state.subscribedCommunities = res.communities;
|
this.state.subscribedCommunities = res.communities;
|
||||||
this.state.loading = false;
|
this.state.loading = false;
|
||||||
this.setState(this.state);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Component, linkEvent } from 'inferno';
|
import { Component, linkEvent } from 'inferno';
|
||||||
import { Subscription } from "rxjs";
|
import { Subscription } from "rxjs";
|
||||||
import { retryWhen, delay, take } from 'rxjs/operators';
|
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 { WebSocketService } from '../services';
|
||||||
import { msgOp } from '../utils';
|
import { msgOp } from '../utils';
|
||||||
import * as autosize from 'autosize';
|
import * as autosize from 'autosize';
|
||||||
|
@ -56,7 +56,11 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
||||||
() => console.log('complete')
|
() => console.log('complete')
|
||||||
);
|
);
|
||||||
|
|
||||||
WebSocketService.Instance.listCommunities();
|
let listCommunitiesForm: ListCommunitiesForm = {
|
||||||
|
sort: SortType[SortType.TopAll]
|
||||||
|
}
|
||||||
|
|
||||||
|
WebSocketService.Instance.listCommunities(listCommunitiesForm);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
|
|
@ -67,6 +67,12 @@ export interface CommunityResponse {
|
||||||
community: Community;
|
community: Community;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ListCommunitiesForm {
|
||||||
|
sort: string;
|
||||||
|
limit?: number;
|
||||||
|
auth?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ListCommunitiesResponse {
|
export interface ListCommunitiesResponse {
|
||||||
op: string;
|
op: string;
|
||||||
communities: Array<Community>;
|
communities: Array<Community>;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { wsUri } from '../env';
|
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 { webSocket } from 'rxjs/webSocket';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { retryWhen, delay, take } from 'rxjs/operators';
|
import { retryWhen, delay, take } from 'rxjs/operators';
|
||||||
|
@ -47,9 +47,9 @@ export class WebSocketService {
|
||||||
this.subject.next(this.wsSendWrapper(UserOperation.FollowCommunity, followCommunityForm));
|
this.subject.next(this.wsSendWrapper(UserOperation.FollowCommunity, followCommunityForm));
|
||||||
}
|
}
|
||||||
|
|
||||||
public listCommunities() {
|
public listCommunities(form: ListCommunitiesForm) {
|
||||||
let data = {auth: UserService.Instance.auth };
|
this.setAuth(form, false);
|
||||||
this.subject.next(this.wsSendWrapper(UserOperation.ListCommunities, data));
|
this.subject.next(this.wsSendWrapper(UserOperation.ListCommunities, form));
|
||||||
}
|
}
|
||||||
|
|
||||||
public getFollowedCommunities() {
|
public getFollowedCommunities() {
|
||||||
|
|
Loading…
Reference in a new issue