From 663a601e1102794416ebc00af3c5479a0153518b Mon Sep 17 00:00:00 2001 From: Dessalines Date: Sun, 13 Oct 2019 17:36:35 -0700 Subject: [PATCH] Adding admin abilities on user pages. - Fixes #280 --- server/src/api/user.rs | 7 ++++ ui/src/components/comment-node.tsx | 2 +- ui/src/components/post-listing.tsx | 60 +++++++++++++++++------------- ui/src/components/user.tsx | 38 ++++++++++++++++--- ui/src/interfaces.ts | 1 + 5 files changed, 76 insertions(+), 32 deletions(-) diff --git a/server/src/api/user.rs b/server/src/api/user.rs index 222b64083..aded85572 100644 --- a/server/src/api/user.rs +++ b/server/src/api/user.rs @@ -50,6 +50,7 @@ pub struct GetUserDetailsResponse { moderates: Vec, comments: Vec, posts: Vec, + admins: Vec, } #[derive(Serialize, Deserialize)] @@ -367,6 +368,11 @@ impl Perform for Oper { let follows = CommunityFollowerView::for_user(&conn, user_details_id)?; let moderates = CommunityModeratorView::for_user(&conn, user_details_id)?; + let site_creator_id = Site::read(&conn, 1)?.creator_id; + let mut admins = UserView::admins(&conn)?; + let creator_index = admins.iter().position(|r| r.id == site_creator_id).unwrap(); + let creator_user = admins.remove(creator_index); + admins.insert(0, creator_user); // Return the jwt Ok(GetUserDetailsResponse { @@ -376,6 +382,7 @@ impl Perform for Oper { moderates: moderates, comments: comments, posts: posts, + admins: admins, }) } } diff --git a/ui/src/components/comment-node.tsx b/ui/src/components/comment-node.tsx index b45f13fcc..2cb556023 100644 --- a/ui/src/components/comment-node.tsx +++ b/ui/src/components/comment-node.tsx @@ -137,7 +137,7 @@ export class CommentNode extends Component { } {/* Admins and mods can remove comments */} - {this.canMod && + {(this.canMod || this.canAdmin) &&
  • {!node.comment.removed ? # : diff --git a/ui/src/components/post-listing.tsx b/ui/src/components/post-listing.tsx index 2b7afc6b0..d0322d984 100644 --- a/ui/src/components/post-listing.tsx +++ b/ui/src/components/post-listing.tsx @@ -24,7 +24,6 @@ interface PostListingState { interface PostListingProps { post: Post; - editable?: boolean; showCommunity?: boolean; showBody?: boolean; viewOnly?: boolean; @@ -174,14 +173,18 @@ export class PostListing extends Component {
    • - {UserService.Instance.user && this.props.editable && + {UserService.Instance.user && <> -
    • - {post.saved ? i18n.t('unsave') : i18n.t('save')} -
    • -
    • - # -
    • + {this.props.showBody && + <> +
    • + {post.saved ? i18n.t('unsave') : i18n.t('save')} +
    • +
    • + # +
    • + + } {this.myPost && <>
    • @@ -205,14 +208,16 @@ export class PostListing extends Component { } {/* Mods can ban from community, and appoint as mods to community */} - {this.canMod && + {(this.canMod || this.canAdmin) && +
    • + {!post.removed ? + # : + # + } +
    • + } + {this.canMod && <> -
    • - {!post.removed ? - # : - # - } -
    • {!this.isMod &&
    • {!post.banned_from_community ? @@ -326,23 +331,26 @@ export class PostListing extends Component { return this.props.admins && isMod(this.props.admins.map(a => a.id), this.props.post.creator_id); } - get adminsThenMods(): Array { - return this.props.admins.map(a => a.id) - .concat(this.props.moderators.map(m => m.user_id)); - } - get canMod(): boolean { + if (this.props.admins && this.props.moderators) { + let adminsThenMods = this.props.admins.map(a => a.id) + .concat(this.props.moderators.map(m => m.user_id)); - if (this.props.editable) { - return canMod(UserService.Instance.user, this.adminsThenMods, this.props.post.creator_id); - } else return false; + return canMod(UserService.Instance.user, adminsThenMods, this.props.post.creator_id); + } else { + return false; + } } get canModOnSelf(): boolean { + if (this.props.admins && this.props.moderators) { + let adminsThenMods = this.props.admins.map(a => a.id) + .concat(this.props.moderators.map(m => m.user_id)); - if (this.props.editable) { - return canMod(UserService.Instance.user, this.adminsThenMods, this.props.post.creator_id, true); - } else return false; + return canMod(UserService.Instance.user, adminsThenMods, this.props.post.creator_id, true); + } else { + return false; + } } get canAdmin(): boolean { diff --git a/ui/src/components/user.tsx b/ui/src/components/user.tsx index c5ba974f0..016721ad1 100644 --- a/ui/src/components/user.tsx +++ b/ui/src/components/user.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, Post, Comment, CommunityUser, GetUserDetailsForm, SortType, UserDetailsResponse, UserView, CommentResponse, UserSettingsForm, LoginResponse } from '../interfaces'; +import { UserOperation, Post, Comment, CommunityUser, GetUserDetailsForm, SortType, UserDetailsResponse, UserView, CommentResponse, UserSettingsForm, LoginResponse, BanUserResponse, AddAdminResponse } from '../interfaces'; import { WebSocketService, UserService } from '../services'; import { msgOp, fetchLimit, routeSortTypeToEnum, capitalizeFirstLetter } from '../utils'; import { PostListing } from './post-listing'; @@ -24,6 +24,7 @@ interface UserState { comments: Array; posts: Array; saved?: Array; + admins: Array; view: View; sort: SortType; page: number; @@ -53,6 +54,7 @@ export class User extends Component { moderates: [], comments: [], posts: [], + admins: [], loading: true, view: this.getViewFromProps(this.props), sort: this.getSortTypeFromProps(this.props), @@ -199,8 +201,16 @@ export class User extends Component { {combined.map(i =>
      {i.type_ == "posts" - ? - : + ? + : + }
      ) @@ -213,7 +223,9 @@ export class User extends Component { return (
      {this.state.comments.map(comment => - + )}
      ); @@ -223,7 +235,11 @@ export class User extends Component { return (
      {this.state.posts.map(post => - + )}
      ); @@ -415,6 +431,7 @@ export class User extends Component { this.state.follows = res.follows; this.state.moderates = res.moderates; this.state.posts = res.posts; + this.state.admins = res.admins; this.state.loading = false; if (this.isCurrentUser) { this.state.userSettingsForm.show_nsfw = UserService.Instance.user.show_nsfw; @@ -454,6 +471,17 @@ export class User extends Component { if (res.comment.my_vote !== null) found.my_vote = res.comment.my_vote; this.setState(this.state); + } else if (op == UserOperation.BanUser) { + let res: BanUserResponse = msg; + this.state.comments.filter(c => c.creator_id == res.user.id) + .forEach(c => c.banned = res.banned); + this.state.posts.filter(c => c.creator_id == res.user.id) + .forEach(c => c.banned = res.banned); + this.setState(this.state); + } else if (op == UserOperation.AddAdmin) { + let res: AddAdminResponse = msg; + this.state.admins = res.admins; + this.setState(this.state); } else if (op == UserOperation.SaveUserSettings) { this.state = this.emptyState; this.state.userSettingsLoading = false; diff --git a/ui/src/interfaces.ts b/ui/src/interfaces.ts index 3221415b3..b9ccf3032 100644 --- a/ui/src/interfaces.ts +++ b/ui/src/interfaces.ts @@ -172,6 +172,7 @@ export interface UserDetailsResponse { moderates: Array; comments: Array; posts: Array; + admins: Array; } export interface GetRepliesForm {