Getting community moderators
- Getting back mods with a fetch. Fixes #28
This commit is contained in:
parent
d07a1b4563
commit
f3cbe9e6ce
8 changed files with 105 additions and 13 deletions
|
@ -9,10 +9,12 @@ from community c;
|
||||||
|
|
||||||
create view community_moderator_view as
|
create view community_moderator_view as
|
||||||
select *,
|
select *,
|
||||||
(select name from user_ u where cm.user_id = u.id) as user_name
|
(select name from user_ u where cm.user_id = u.id) as user_name,
|
||||||
|
(select name from community c where cm.community_id = c.id) as community_name
|
||||||
from community_moderator cm;
|
from community_moderator cm;
|
||||||
|
|
||||||
create view community_follower_view as
|
create view community_follower_view as
|
||||||
select *,
|
select *,
|
||||||
(select name from user_ u where cf.user_id = u.id) as user_name
|
(select name from user_ u where cf.user_id = u.id) as user_name,
|
||||||
|
(select name from community c where cf.community_id = c.id) as community_name
|
||||||
from community_follower cf;
|
from community_follower cf;
|
||||||
|
|
|
@ -21,6 +21,28 @@ table! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table! {
|
||||||
|
community_moderator_view (id) {
|
||||||
|
id -> Int4,
|
||||||
|
community_id -> Int4,
|
||||||
|
user_id -> Int4,
|
||||||
|
published -> Timestamp,
|
||||||
|
user_name -> Varchar,
|
||||||
|
community_name -> Varchar,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table! {
|
||||||
|
community_follower_view (id) {
|
||||||
|
id -> Int4,
|
||||||
|
community_id -> Int4,
|
||||||
|
user_id -> Int4,
|
||||||
|
published -> Timestamp,
|
||||||
|
user_name -> Varchar,
|
||||||
|
community_name -> Varchar,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)]
|
#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize,QueryableByName,Clone)]
|
||||||
#[table_name="community_view"]
|
#[table_name="community_view"]
|
||||||
pub struct CommunityView {
|
pub struct CommunityView {
|
||||||
|
@ -51,3 +73,27 @@ impl CommunityView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[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 community_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CommunityModeratorView {
|
||||||
|
pub fn for_community(conn: &PgConnection, from_community_id: i32) -> Result<Vec<Self>, Error> {
|
||||||
|
use actions::community_view::community_moderator_view::dsl::*;
|
||||||
|
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 actions::community_view::community_moderator_view::dsl::*;
|
||||||
|
community_moderator_view.filter(user_id.eq(from_user_id)).load::<Self>(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -153,7 +153,8 @@ pub struct GetPostResponse {
|
||||||
op: String,
|
op: String,
|
||||||
post: PostView,
|
post: PostView,
|
||||||
comments: Vec<CommentView>,
|
comments: Vec<CommentView>,
|
||||||
community: CommunityView
|
community: CommunityView,
|
||||||
|
moderators: Vec<CommunityModeratorView>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
@ -179,7 +180,8 @@ pub struct GetCommunity {
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct GetCommunityResponse {
|
pub struct GetCommunityResponse {
|
||||||
op: String,
|
op: String,
|
||||||
community: CommunityView
|
community: CommunityView,
|
||||||
|
moderators: Vec<CommunityModeratorView>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
|
@ -762,13 +764,16 @@ impl Perform for GetPost {
|
||||||
|
|
||||||
let community = CommunityView::read(&conn, post_view.community_id).unwrap();
|
let community = CommunityView::read(&conn, post_view.community_id).unwrap();
|
||||||
|
|
||||||
|
let moderators = CommunityModeratorView::for_community(&conn, post_view.community_id).unwrap();
|
||||||
|
|
||||||
// Return the jwt
|
// Return the jwt
|
||||||
serde_json::to_string(
|
serde_json::to_string(
|
||||||
&GetPostResponse {
|
&GetPostResponse {
|
||||||
op: self.op_type().to_string(),
|
op: self.op_type().to_string(),
|
||||||
post: post_view,
|
post: post_view,
|
||||||
comments: comments,
|
comments: comments,
|
||||||
community: community
|
community: community,
|
||||||
|
moderators: moderators
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -791,11 +796,20 @@ impl Perform for GetCommunity {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let moderators = match CommunityModeratorView::for_community(&conn, self.id) {
|
||||||
|
Ok(moderators) => moderators,
|
||||||
|
Err(_e) => {
|
||||||
|
return self.error("Couldn't find Community");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Return the jwt
|
// Return the jwt
|
||||||
serde_json::to_string(
|
serde_json::to_string(
|
||||||
&GetCommunityResponse {
|
&GetCommunityResponse {
|
||||||
op: self.op_type().to_string(),
|
op: self.op_type().to_string(),
|
||||||
community: community_view
|
community: community_view,
|
||||||
|
moderators: moderators
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
|
@ -32,6 +32,7 @@ export class Communities extends Component<any, CommunitiesState> {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
<h4>Communities</h4>
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-sm table-hover" data-sortable>
|
<table class="table table-sm table-hover" data-sortable>
|
||||||
<thead>
|
<thead>
|
||||||
|
|
|
@ -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 as CommunityI, CommunityResponse, Post, GetPostsForm, ListingSortType, ListingType, GetPostsResponse, CreatePostLikeForm, CreatePostLikeResponse} from '../interfaces';
|
import { UserOperation, Community as CommunityI, CommunityResponse, Post, GetPostsForm, ListingSortType, ListingType, GetPostsResponse, CreatePostLikeForm, CreatePostLikeResponse, CommunityUser} from '../interfaces';
|
||||||
import { WebSocketService, UserService } from '../services';
|
import { WebSocketService, UserService } from '../services';
|
||||||
import { MomentTime } from './moment-time';
|
import { MomentTime } from './moment-time';
|
||||||
import { PostListing } from './post-listing';
|
import { PostListing } from './post-listing';
|
||||||
|
@ -11,6 +11,7 @@ import { msgOp, mdToHtml } from '../utils';
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
community: CommunityI;
|
community: CommunityI;
|
||||||
|
moderators: Array<CommunityUser>;
|
||||||
posts: Array<Post>;
|
posts: Array<Post>;
|
||||||
sortType: ListingSortType;
|
sortType: ListingSortType;
|
||||||
}
|
}
|
||||||
|
@ -29,8 +30,10 @@ export class Community extends Component<any, State> {
|
||||||
creator_name: null,
|
creator_name: null,
|
||||||
number_of_subscribers: null,
|
number_of_subscribers: null,
|
||||||
number_of_posts: null,
|
number_of_posts: null,
|
||||||
|
number_of_comments: null,
|
||||||
published: null
|
published: null
|
||||||
},
|
},
|
||||||
|
moderators: [],
|
||||||
posts: [],
|
posts: [],
|
||||||
sortType: ListingSortType.Hot,
|
sortType: ListingSortType.Hot,
|
||||||
}
|
}
|
||||||
|
@ -78,7 +81,7 @@ export class Community extends Component<any, State> {
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-sm-2 col-lg-3">
|
<div class="col-12 col-sm-2 col-lg-3">
|
||||||
<Sidebar community={this.state.community} />
|
<Sidebar community={this.state.community} moderators={this.state.moderators} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -126,6 +129,7 @@ export class Community extends Component<any, State> {
|
||||||
} else if (op == UserOperation.GetCommunity) {
|
} else if (op == UserOperation.GetCommunity) {
|
||||||
let res: CommunityResponse = msg;
|
let res: CommunityResponse = msg;
|
||||||
this.state.community = res.community;
|
this.state.community = res.community;
|
||||||
|
this.state.moderators = res.moderators;
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
} else if (op == UserOperation.GetPosts) {
|
} else if (op == UserOperation.GetPosts) {
|
||||||
let res: GetPostsResponse = msg;
|
let res: GetPostsResponse = msg;
|
||||||
|
|
|
@ -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, Post as PostI, GetPostResponse, PostResponse, Comment, CommentForm as CommentFormI, CommentResponse, CommentLikeForm, CommentSortType, CreatePostLikeResponse } from '../interfaces';
|
import { UserOperation, Community, Post as PostI, GetPostResponse, PostResponse, Comment, CommentForm as CommentFormI, CommentResponse, CommentLikeForm, CommentSortType, CreatePostLikeResponse, CommunityUser } from '../interfaces';
|
||||||
import { WebSocketService, UserService } from '../services';
|
import { WebSocketService, UserService } from '../services';
|
||||||
import { msgOp, hotRank,mdToHtml } from '../utils';
|
import { msgOp, hotRank,mdToHtml } from '../utils';
|
||||||
import { MomentTime } from './moment-time';
|
import { MomentTime } from './moment-time';
|
||||||
|
@ -20,6 +20,7 @@ interface PostState {
|
||||||
comments: Array<Comment>;
|
comments: Array<Comment>;
|
||||||
commentSort: CommentSortType;
|
commentSort: CommentSortType;
|
||||||
community: Community;
|
community: Community;
|
||||||
|
moderators: Array<CommunityUser>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Post extends Component<any, PostState> {
|
export class Post extends Component<any, PostState> {
|
||||||
|
@ -30,6 +31,7 @@ export class Post extends Component<any, PostState> {
|
||||||
comments: [],
|
comments: [],
|
||||||
commentSort: CommentSortType.Hot,
|
commentSort: CommentSortType.Hot,
|
||||||
community: null,
|
community: null,
|
||||||
|
moderators: []
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
|
@ -118,7 +120,7 @@ export class Post extends Component<any, PostState> {
|
||||||
sidebar() {
|
sidebar() {
|
||||||
return (
|
return (
|
||||||
<div class="sticky-top">
|
<div class="sticky-top">
|
||||||
<Sidebar community={this.state.community} />
|
<Sidebar community={this.state.community} moderators={this.state.moderators} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -188,6 +190,7 @@ export class Post extends Component<any, PostState> {
|
||||||
this.state.post = res.post;
|
this.state.post = res.post;
|
||||||
this.state.comments = res.comments;
|
this.state.comments = res.comments;
|
||||||
this.state.community = res.community;
|
this.state.community = res.community;
|
||||||
|
this.state.moderators = res.moderators;
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
} else if (op == UserOperation.CreateComment) {
|
} else if (op == UserOperation.CreateComment) {
|
||||||
let res: CommentResponse = msg;
|
let res: CommentResponse = msg;
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import { Component, linkEvent } from 'inferno';
|
import { Component, linkEvent } from 'inferno';
|
||||||
import { Community } from '../interfaces';
|
import { Link } from 'inferno-router';
|
||||||
|
import { Community, CommunityUser } from '../interfaces';
|
||||||
import { mdToHtml } from '../utils';
|
import { mdToHtml } from '../utils';
|
||||||
|
|
||||||
interface SidebarProps {
|
interface SidebarProps {
|
||||||
community: Community;
|
community: Community;
|
||||||
|
moderators: Array<CommunityUser>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SidebarState {
|
interface SidebarState {
|
||||||
|
@ -22,14 +24,23 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
|
||||||
<div>
|
<div>
|
||||||
<h4>{community.title}</h4>
|
<h4>{community.title}</h4>
|
||||||
<ul class="list-inline">
|
<ul class="list-inline">
|
||||||
<li className="list-inline-item badge badge-light">{community.category_name}</li>
|
<li className="list-inline-item"><Link className="badge badge-light" to="/communities">{community.category_name}</Link></li>
|
||||||
<li className="list-inline-item badge badge-light">{community.number_of_subscribers} Subscribers</li>
|
<li className="list-inline-item badge badge-light">{community.number_of_subscribers} Subscribers</li>
|
||||||
<li className="list-inline-item badge badge-light">{community.number_of_posts} Posts</li>
|
<li className="list-inline-item badge badge-light">{community.number_of_posts} Posts</li>
|
||||||
<li className="list-inline-item badge badge-light">{community.number_of_comments} Comments</li>
|
<li className="list-inline-item badge badge-light">{community.number_of_comments} Comments</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div><button type="button" class="btn btn-secondary mb-2">Subscribe</button></div>
|
<div><button type="button" class="btn btn-secondary mb-2">Subscribe</button></div>
|
||||||
|
{community.description &&
|
||||||
|
<div>
|
||||||
|
<hr />
|
||||||
|
<div className="md-div" dangerouslySetInnerHTML={mdToHtml(community.description)} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
<hr />
|
<hr />
|
||||||
{community.description && <div className="md-div" dangerouslySetInnerHTML={mdToHtml(community.description)} />}
|
<h5>Moderators</h5>
|
||||||
|
{this.props.moderators.map(mod =>
|
||||||
|
<Link to={`/user/${mod.user_id}`}>{mod.user_name}</Link>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,15 @@ export interface User {
|
||||||
username: string;
|
username: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CommunityUser {
|
||||||
|
id: number;
|
||||||
|
user_id: number;
|
||||||
|
user_name: string;
|
||||||
|
community_id: number;
|
||||||
|
community_name: string;
|
||||||
|
published: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Community {
|
export interface Community {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -35,6 +44,7 @@ export interface CommunityForm {
|
||||||
export interface CommunityResponse {
|
export interface CommunityResponse {
|
||||||
op: string;
|
op: string;
|
||||||
community: Community;
|
community: Community;
|
||||||
|
moderators: Array<CommunityUser>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ListCommunitiesResponse {
|
export interface ListCommunitiesResponse {
|
||||||
|
@ -82,6 +92,7 @@ export interface GetPostResponse {
|
||||||
post: Post;
|
post: Post;
|
||||||
comments: Array<Comment>;
|
comments: Array<Comment>;
|
||||||
community: Community;
|
community: Community;
|
||||||
|
moderators: Array<CommunityUser>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PostResponse {
|
export interface PostResponse {
|
||||||
|
|
Reference in a new issue