diff options
-rw-r--r-- | server/migrations/2019-03-30-212058_create_post_view/up.sql | 1 | ||||
-rw-r--r-- | server/src/actions/post_view.rs | 10 | ||||
-rw-r--r-- | server/src/websocket_server/server.rs | 31 | ||||
-rw-r--r-- | ui/src/components/comment-node.tsx | 14 | ||||
-rw-r--r-- | ui/src/components/community.tsx | 14 | ||||
-rw-r--r-- | ui/src/components/post-listing.tsx | 20 | ||||
-rw-r--r-- | ui/src/components/post.tsx | 6 | ||||
-rw-r--r-- | ui/src/components/sidebar.tsx | 39 | ||||
-rw-r--r-- | ui/src/interfaces.ts | 2 |
9 files changed, 88 insertions, 49 deletions
diff --git a/server/migrations/2019-03-30-212058_create_post_view/up.sql b/server/migrations/2019-03-30-212058_create_post_view/up.sql index 17dc8604..4a4fd146 100644 --- a/server/migrations/2019-03-30-212058_create_post_view/up.sql +++ b/server/migrations/2019-03-30-212058_create_post_view/up.sql @@ -16,6 +16,7 @@ with all_post as p.*, (select name from user_ where p.creator_id = user_.id) as creator_name, (select name from community where p.community_id = community.id) as community_name, + (select removed from community c where p.community_id = c.id) as community_removed, (select count(*) from comment where comment.post_id = p.id) as number_of_comments, coalesce(sum(pl.score), 0) as score, count (case when pl.score = 1 then 1 else null end) as upvotes, diff --git a/server/src/actions/post_view.rs b/server/src/actions/post_view.rs index ba42fe27..ccad9317 100644 --- a/server/src/actions/post_view.rs +++ b/server/src/actions/post_view.rs @@ -25,6 +25,7 @@ table! { updated -> Nullable<Timestamp>, creator_name -> Varchar, community_name -> Varchar, + community_removed -> Bool, number_of_comments -> BigInt, score -> BigInt, upvotes -> BigInt, @@ -54,6 +55,7 @@ pub struct PostView { pub updated: Option<chrono::NaiveDateTime>, pub creator_name: String, pub community_name: String, + pub community_removed: bool, pub number_of_comments: i64, pub score: i64, pub upvotes: i64, @@ -133,13 +135,11 @@ impl PostView { .order_by(score.desc()) }; - - // TODO make sure community removed isn't fetched either - query = query .limit(limit) .offset(offset) - .filter(removed.eq(false)); + .filter(removed.eq(false)) + .filter(community_removed.eq(false)); query.load::<Self>(conn) } @@ -255,6 +255,7 @@ mod tests { removed: false, locked: false, community_name: community_name.to_owned(), + community_removed: false, number_of_comments: 0, score: 1, upvotes: 1, @@ -280,6 +281,7 @@ mod tests { creator_name: user_name.to_owned(), community_id: inserted_community.id, community_name: community_name.to_owned(), + community_removed: false, number_of_comments: 0, score: 1, upvotes: 1, diff --git a/server/src/websocket_server/server.rs b/server/src/websocket_server/server.rs index ba6e176b..068fd027 100644 --- a/server/src/websocket_server/server.rs +++ b/server/src/websocket_server/server.rs @@ -196,7 +196,8 @@ pub struct GetCommunity { pub struct GetCommunityResponse { op: String, community: CommunityView, - moderators: Vec<CommunityModeratorView> + moderators: Vec<CommunityModeratorView>, + admins: Vec<UserView>, } #[derive(Serialize, Deserialize)] @@ -1165,13 +1166,16 @@ impl Perform for GetCommunity { } }; + let admins = UserView::admins(&conn)?; + // Return the jwt Ok( serde_json::to_string( &GetCommunityResponse { op: self.op_type().to_string(), community: community_view, - moderators: moderators + moderators: moderators, + admins: admins, } )? ) @@ -1817,11 +1821,24 @@ impl Perform for EditCommunity { } // Verify its a mod - let moderator_view = CommunityModeratorView::for_community(&conn, self.edit_id)?; - let mod_ids: Vec<i32> = moderator_view.into_iter().map(|m| m.user_id).collect(); - if !mod_ids.contains(&user_id) { - return Err(self.error("Incorrect creator."))? - }; + let mut editors: Vec<i32> = Vec::new(); + editors.append( + &mut CommunityModeratorView::for_community(&conn, self.edit_id) + ? + .into_iter() + .map(|m| m.user_id) + .collect() + ); + editors.append( + &mut UserView::admins(&conn) + ? + .into_iter() + .map(|a| a.id) + .collect() + ); + if !editors.contains(&user_id) { + return Err(self.error("Not allowed to edit community"))? + } let community_form = CommunityForm { name: self.name.to_owned(), diff --git a/ui/src/components/comment-node.tsx b/ui/src/components/comment-node.tsx index cf7b1bce..415dad77 100644 --- a/ui/src/components/comment-node.tsx +++ b/ui/src/components/comment-node.tsx @@ -210,13 +210,6 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { return UserService.Instance.user && this.props.node.comment.creator_id == UserService.Instance.user.id; } - get canMod(): boolean { - let adminsThenMods = this.props.admins.map(a => a.id) - .concat(this.props.moderators.map(m => m.user_id)); - - return canMod(UserService.Instance.user, adminsThenMods, this.props.node.comment.creator_id); - } - get isMod(): boolean { return this.props.moderators && isMod(this.props.moderators.map(m => m.user_id), this.props.node.comment.creator_id); } @@ -225,6 +218,13 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> { return this.props.admins && isMod(this.props.admins.map(a => a.id), this.props.node.comment.creator_id); } + get canMod(): boolean { + let adminsThenMods = this.props.admins.map(a => a.id) + .concat(this.props.moderators.map(m => m.user_id)); + + return canMod(UserService.Instance.user, adminsThenMods, this.props.node.comment.creator_id); + } + get canAdmin(): boolean { return this.props.admins && canMod(UserService.Instance.user, this.props.admins.map(a => a.id), this.props.node.comment.creator_id); } diff --git a/ui/src/components/community.tsx b/ui/src/components/community.tsx index 6271bde5..c89d2f06 100644 --- a/ui/src/components/community.tsx +++ b/ui/src/components/community.tsx @@ -1,7 +1,7 @@ import { Component } from 'inferno'; import { Subscription } from "rxjs"; import { retryWhen, delay, take } from 'rxjs/operators'; -import { UserOperation, Community as CommunityI, GetCommunityResponse, CommunityResponse, CommunityUser} from '../interfaces'; +import { UserOperation, Community as CommunityI, GetCommunityResponse, CommunityResponse, CommunityUser, UserView } from '../interfaces'; import { WebSocketService } from '../services'; import { PostListings } from './post-listings'; import { Sidebar } from './sidebar'; @@ -11,6 +11,7 @@ interface State { community: CommunityI; communityId: number; moderators: Array<CommunityUser>; + admins: Array<UserView>; loading: boolean; } @@ -29,9 +30,11 @@ export class Community extends Component<any, State> { number_of_subscribers: null, number_of_posts: null, number_of_comments: null, - published: null + published: null, + removed: null, }, moderators: [], + admins: [], communityId: Number(this.props.match.params.id), loading: true } @@ -71,7 +74,11 @@ export class Community extends Component<any, State> { <PostListings communityId={this.state.communityId} /> </div> <div class="col-12 col-md-3"> - <Sidebar community={this.state.community} moderators={this.state.moderators} /> + <Sidebar + community={this.state.community} + moderators={this.state.moderators} + admins={this.state.admins} + /> </div> </div> } @@ -90,6 +97,7 @@ export class Community extends Component<any, State> { let res: GetCommunityResponse = msg; this.state.community = res.community; this.state.moderators = res.moderators; + this.state.admins = res.admins; this.state.loading = false; this.setState(this.state); } else if (op == UserOperation.EditCommunity) { diff --git a/ui/src/components/post-listing.tsx b/ui/src/components/post-listing.tsx index 8803d629..93e88071 100644 --- a/ui/src/components/post-listing.tsx +++ b/ui/src/components/post-listing.tsx @@ -174,6 +174,14 @@ export class PostListing extends Component<PostListingProps, PostListingState> { return UserService.Instance.user && this.props.post.creator_id == UserService.Instance.user.id; } + get isMod(): boolean { + return this.props.moderators && isMod(this.props.moderators.map(m => m.user_id), this.props.post.creator_id); + } + + get isAdmin(): boolean { + return this.props.admins && isMod(this.props.admins.map(a => a.id), this.props.post.creator_id); + } + get canMod(): boolean { if (this.props.editable) { @@ -185,18 +193,6 @@ export class PostListing extends Component<PostListingProps, PostListingState> { } else return false; } - get isMod(): boolean { - return this.props.moderators && isMod(this.props.moderators.map(m => m.user_id), this.props.post.creator_id); - } - - get isAdmin(): boolean { - return this.props.admins && isMod(this.props.admins.map(a => a.id), this.props.post.creator_id); - } - - get canAdmin(): boolean { - return this.props.admins && canMod(UserService.Instance.user, this.props.admins.map(a => a.id), this.props.post.creator_id); - } - handlePostLike(i: PostListing) { let form: CreatePostLikeForm = { diff --git a/ui/src/components/post.tsx b/ui/src/components/post.tsx index 3f243220..3ece6747 100644 --- a/ui/src/components/post.tsx +++ b/ui/src/components/post.tsx @@ -148,7 +148,11 @@ export class Post extends Component<any, PostState> { sidebar() { return ( <div class="sticky-top"> - <Sidebar community={this.state.community} moderators={this.state.moderators} /> + <Sidebar + community={this.state.community} + moderators={this.state.moderators} + admins={this.state.admins} + /> </div> ); } diff --git a/ui/src/components/sidebar.tsx b/ui/src/components/sidebar.tsx index 2f231f9a..95880448 100644 --- a/ui/src/components/sidebar.tsx +++ b/ui/src/components/sidebar.tsx @@ -1,6 +1,6 @@ import { Component, linkEvent } from 'inferno'; import { Link } from 'inferno-router'; -import { Community, CommunityUser, FollowCommunityForm, CommunityForm as CommunityFormI } from '../interfaces'; +import { Community, CommunityUser, FollowCommunityForm, CommunityForm as CommunityFormI, UserView } from '../interfaces'; import { WebSocketService, UserService } from '../services'; import { mdToHtml, getUnixTime } from '../utils'; import { CommunityForm } from './community-form'; @@ -8,6 +8,7 @@ import { CommunityForm } from './community-form'; interface SidebarProps { community: Community; moderators: Array<CommunityUser>; + admins: Array<UserView>; } interface SidebarState { @@ -54,24 +55,29 @@ export class Sidebar extends Component<SidebarProps, SidebarState> { } </h5> <Link className="text-muted" to={`/community/${community.id}`}>/f/{community.name}</Link> - {community.am_mod && - <ul class="list-inline mb-1 text-muted small font-weight-bold"> - <li className="list-inline-item"> - <span class="pointer" onClick={linkEvent(this, this.handleEditClick)}>edit</span> - </li> - {this.amCreator && + <ul class="list-inline mb-1 text-muted small font-weight-bold"> + {this.canMod && + <> <li className="list-inline-item"> - {/* <span class="pointer" onClick={linkEvent(this, this.handleDeleteClick)}>delete</span> */} + <span class="pointer" onClick={linkEvent(this, this.handleEditClick)}>edit</span> </li> - } + {this.amCreator && + <li className="list-inline-item"> + {/* <span class="pointer" onClick={linkEvent(this, this.handleDeleteClick)}>delete</span> */} + </li> + } + </> + } + {this.canAdmin && <li className="list-inline-item"> {!this.props.community.removed ? <span class="pointer" onClick={linkEvent(this, this.handleModRemoveShow)}>remove</span> : <span class="pointer" onClick={linkEvent(this, this.handleModRemoveSubmit)}>restore</span> } </li> - </ul> - } + + } + </ul> {this.state.showRemoveDialog && <form onSubmit={linkEvent(this, this.handleModRemoveSubmit)}> <div class="form-group row"> @@ -156,10 +162,13 @@ export class Sidebar extends Component<SidebarProps, SidebarState> { return this.props.community.creator_id == UserService.Instance.user.id; } - // private get amMod(): boolean { - // return UserService.Instance.loggedIn && - // this.props.moderators.map(m => m.user_id).includes(UserService.Instance.user.id); - // } + get canMod(): boolean { + return UserService.Instance.user && this.props.moderators.map(m => m.user_id).includes(UserService.Instance.user.id); + } + + get canAdmin(): boolean { + return UserService.Instance.user && this.props.admins.map(a => a.id).includes(UserService.Instance.user.id); + } handleDeleteClick() { } diff --git a/ui/src/interfaces.ts b/ui/src/interfaces.ts index 24bb6157..23b86074 100644 --- a/ui/src/interfaces.ts +++ b/ui/src/interfaces.ts @@ -72,6 +72,7 @@ export interface Post { updated?: string; creator_name: string; community_name: string; + community_removed: boolean; number_of_comments: number; score: number; upvotes: number; @@ -350,6 +351,7 @@ export interface GetCommunityResponse { op: string; community: Community; moderators: Array<CommunityUser>; + admins: Array<UserView>; } |