More moderation fixed

This commit is contained in:
Dessalines 2019-04-20 00:24:59 -07:00
parent 9afadfb9c4
commit e14e6e53cd
11 changed files with 93 additions and 52 deletions

View file

@ -184,7 +184,7 @@ mod tests {
description: None, description: None,
category_id: 1, category_id: 1,
creator_id: inserted_user.id, creator_id: inserted_user.id,
removed: false, removed: None,
updated: None updated: None
}; };
@ -196,8 +196,8 @@ mod tests {
url: None, url: None,
body: None, body: None,
community_id: inserted_community.id, community_id: inserted_community.id,
removed: false, removed: None,
locked: false, locked: None,
updated: None updated: None
}; };

View file

@ -168,7 +168,7 @@ mod tests {
description: None, description: None,
category_id: 1, category_id: 1,
creator_id: inserted_user.id, creator_id: inserted_user.id,
removed: false, removed: None,
updated: None updated: None
}; };
@ -180,8 +180,8 @@ mod tests {
url: None, url: None,
body: None, body: None,
community_id: inserted_community.id, community_id: inserted_community.id,
removed: false, removed: None,
locked: false, locked: None,
updated: None updated: None
}; };

View file

@ -27,7 +27,7 @@ pub struct CommunityForm {
pub description: Option<String>, pub description: Option<String>,
pub category_id: i32, pub category_id: i32,
pub creator_id: i32, pub creator_id: i32,
pub removed: bool, pub removed: Option<bool>,
pub updated: Option<chrono::NaiveDateTime> pub updated: Option<chrono::NaiveDateTime>
} }
@ -236,7 +236,7 @@ mod tests {
title: "nada".to_owned(), title: "nada".to_owned(),
description: None, description: None,
category_id: 1, category_id: 1,
removed: false, removed: None,
updated: None, updated: None,
}; };

View file

@ -441,7 +441,7 @@ mod tests {
description: None, description: None,
category_id: 1, category_id: 1,
creator_id: inserted_user.id, creator_id: inserted_user.id,
removed: false, removed: None,
updated: None updated: None
}; };
@ -453,8 +453,8 @@ mod tests {
body: None, body: None,
creator_id: inserted_user.id, creator_id: inserted_user.id,
community_id: inserted_community.id, community_id: inserted_community.id,
removed: false, removed: None,
locked: false, locked: None,
updated: None updated: None
}; };

View file

@ -28,8 +28,8 @@ pub struct PostForm {
pub body: Option<String>, pub body: Option<String>,
pub creator_id: i32, pub creator_id: i32,
pub community_id: i32, pub community_id: i32,
pub removed: bool, pub removed: Option<bool>,
pub locked: bool, pub locked: Option<bool>,
pub updated: Option<chrono::NaiveDateTime> pub updated: Option<chrono::NaiveDateTime>
} }
@ -198,7 +198,7 @@ mod tests {
description: None, description: None,
category_id: 1, category_id: 1,
creator_id: inserted_user.id, creator_id: inserted_user.id,
removed: false, removed: None,
updated: None updated: None
}; };
@ -210,8 +210,8 @@ mod tests {
body: None, body: None,
creator_id: inserted_user.id, creator_id: inserted_user.id,
community_id: inserted_community.id, community_id: inserted_community.id,
removed: false, removed: None,
locked: false, locked: None,
updated: None updated: None
}; };

View file

@ -200,7 +200,7 @@ mod tests {
description: None, description: None,
creator_id: inserted_user.id, creator_id: inserted_user.id,
category_id: 1, category_id: 1,
removed: false, removed: None,
updated: None updated: None
}; };
@ -212,8 +212,8 @@ mod tests {
body: None, body: None,
creator_id: inserted_user.id, creator_id: inserted_user.id,
community_id: inserted_community.id, community_id: inserted_community.id,
removed: false, removed: None,
locked: false, locked: None,
updated: None updated: None
}; };

View file

@ -261,8 +261,8 @@ pub struct EditPost {
name: String, name: String,
url: Option<String>, url: Option<String>,
body: Option<String>, body: Option<String>,
removed: bool, removed: Option<bool>,
locked: bool, locked: Option<bool>,
reason: Option<String>, reason: Option<String>,
auth: String auth: String
} }
@ -281,7 +281,7 @@ pub struct EditCommunity {
title: String, title: String,
description: Option<String>, description: Option<String>,
category_id: i32, category_id: i32,
removed: bool, removed: Option<bool>,
reason: Option<String>, reason: Option<String>,
expires: Option<i64>, expires: Option<i64>,
auth: String auth: String
@ -836,14 +836,13 @@ impl Perform for CreateCommunity {
} }
// When you create a community, make sure the user becomes a moderator and a follower // When you create a community, make sure the user becomes a moderator and a follower
let community_form = CommunityForm { let community_form = CommunityForm {
name: self.name.to_owned(), name: self.name.to_owned(),
title: self.title.to_owned(), title: self.title.to_owned(),
description: self.description.to_owned(), description: self.description.to_owned(),
category_id: self.category_id, category_id: self.category_id,
creator_id: user_id, creator_id: user_id,
removed: false, removed: None,
updated: None, updated: None,
}; };
@ -988,8 +987,8 @@ impl Perform for CreatePost {
body: self.body.to_owned(), body: self.body.to_owned(),
community_id: self.community_id, community_id: self.community_id,
creator_id: user_id, creator_id: user_id,
removed: false, removed: None,
locked: false, locked: None,
updated: None updated: None
}; };
@ -1612,15 +1611,24 @@ impl Perform for EditPost {
let user_id = claims.id; let user_id = claims.id;
// Verify its the creator or a mod // Verify its the creator or a mod or admin
let mut editors: Vec<i32> = CommunityModeratorView::for_community(&conn, self.community_id) let mut editors: Vec<i32> = vec![self.creator_id];
editors.append(
&mut CommunityModeratorView::for_community(&conn, self.community_id)
.unwrap() .unwrap()
.into_iter() .into_iter()
.map(|m| m.user_id) .map(|m| m.user_id)
.collect(); .collect()
editors.push(self.creator_id); );
editors.append(
&mut UserView::admins(&conn)
.unwrap()
.into_iter()
.map(|a| a.id)
.collect()
);
if !editors.contains(&user_id) { if !editors.contains(&user_id) {
return self.error("Not allowed to edit comment."); return self.error("Not allowed to edit post.");
} }
// Check for a community ban // Check for a community ban
@ -1652,21 +1660,21 @@ impl Perform for EditPost {
}; };
// Mod tables // Mod tables
if self.removed { if let Some(removed) = self.removed.to_owned() {
let form = ModRemovePostForm { let form = ModRemovePostForm {
mod_user_id: user_id, mod_user_id: user_id,
post_id: self.edit_id, post_id: self.edit_id,
removed: Some(self.removed), removed: Some(removed),
reason: self.reason.to_owned(), reason: self.reason.to_owned(),
}; };
ModRemovePost::create(&conn, &form).unwrap(); ModRemovePost::create(&conn, &form).unwrap();
} }
if self.locked { if let Some(locked) = self.locked.to_owned() {
let form = ModLockPostForm { let form = ModLockPostForm {
mod_user_id: user_id, mod_user_id: user_id,
post_id: self.edit_id, post_id: self.edit_id,
locked: Some(self.locked), locked: Some(locked),
}; };
ModLockPost::create(&conn, &form).unwrap(); ModLockPost::create(&conn, &form).unwrap();
} }
@ -1803,7 +1811,7 @@ impl Perform for EditCommunity {
}; };
// Mod tables // Mod tables
if self.removed { if let Some(removed) = self.removed.to_owned() {
let expires = match self.expires { let expires = match self.expires {
Some(time) => Some(naive_from_unix(time)), Some(time) => Some(naive_from_unix(time)),
None => None None => None
@ -1811,7 +1819,7 @@ impl Perform for EditCommunity {
let form = ModRemoveCommunityForm { let form = ModRemoveCommunityForm {
mod_user_id: user_id, mod_user_id: user_id,
community_id: self.edit_id, community_id: self.edit_id,
removed: Some(self.removed), removed: Some(removed),
reason: self.reason.to_owned(), reason: self.reason.to_owned(),
expires: expires expires: expires
}; };

View file

@ -212,15 +212,15 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
} }
get isMod(): boolean { get isMod(): boolean {
return isMod(this.props.moderators.map(m => m.user_id), this.props.node.comment.creator_id); return this.props.moderators && isMod(this.props.moderators.map(m => m.user_id), this.props.node.comment.creator_id);
} }
get isAdmin(): boolean { get isAdmin(): boolean {
return isMod(this.props.admins.map(a => a.id), this.props.node.comment.creator_id); return this.props.admins && isMod(this.props.admins.map(a => a.id), this.props.node.comment.creator_id);
} }
get canAdmin(): boolean { get canAdmin(): boolean {
return canMod(UserService.Instance.user, this.props.admins.map(a => a.id), this.props.node.comment.creator_id); return this.props.admins && canMod(UserService.Instance.user, this.props.admins.map(a => a.id), this.props.node.comment.creator_id);
} }
handleReplyClick(i: CommentNode) { handleReplyClick(i: CommentNode) {
@ -240,7 +240,6 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
creator_id: i.props.node.comment.creator_id, creator_id: i.props.node.comment.creator_id,
post_id: i.props.node.comment.post_id, post_id: i.props.node.comment.post_id,
parent_id: i.props.node.comment.parent_id, parent_id: i.props.node.comment.parent_id,
removed: i.props.node.comment.removed,
auth: null auth: null
}; };
WebSocketService.Instance.editComment(deleteForm); WebSocketService.Instance.editComment(deleteForm);

View file

@ -1,10 +1,10 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from 'inferno';
import { Link } from 'inferno-router'; import { Link } from 'inferno-router';
import { WebSocketService, UserService } from '../services'; import { WebSocketService, UserService } from '../services';
import { Post, CreatePostLikeForm, PostForm as PostFormI, SavePostForm } from '../interfaces'; import { Post, CreatePostLikeForm, PostForm as PostFormI, SavePostForm, CommunityUser, UserView } from '../interfaces';
import { MomentTime } from './moment-time'; import { MomentTime } from './moment-time';
import { PostForm } from './post-form'; import { PostForm } from './post-form';
import { mdToHtml } from '../utils'; import { mdToHtml, canMod, isMod } from '../utils';
interface PostListingState { interface PostListingState {
showEdit: boolean; showEdit: boolean;
@ -19,6 +19,8 @@ interface PostListingProps {
showCommunity?: boolean; showCommunity?: boolean;
showBody?: boolean; showBody?: boolean;
viewOnly?: boolean; viewOnly?: boolean;
moderators?: Array<CommunityUser>;
admins?: Array<UserView>;
} }
export class PostListing extends Component<PostListingProps, PostListingState> { export class PostListing extends Component<PostListingProps, PostListingState> {
@ -98,6 +100,12 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
<li className="list-inline-item"> <li className="list-inline-item">
<span>by </span> <span>by </span>
<Link className="text-info" to={`/user/${post.creator_id}`}>{post.creator_name}</Link> <Link className="text-info" to={`/user/${post.creator_id}`}>{post.creator_name}</Link>
{this.isMod &&
<span className="mx-1 badge badge-secondary">mod</span>
}
{this.isAdmin &&
<span className="mx-1 badge badge-secondary">admin</span>
}
{this.props.showCommunity && {this.props.showCommunity &&
<span> <span>
<span> to </span> <span> to </span>
@ -135,7 +143,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
</li> </li>
</> </>
} }
{this.props.post.am_mod && {this.canMod &&
<span> <span>
<li className="list-inline-item"> <li className="list-inline-item">
{!this.props.post.removed ? {!this.props.post.removed ?
@ -166,6 +174,29 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
return UserService.Instance.user && this.props.post.creator_id == UserService.Instance.user.id; return UserService.Instance.user && this.props.post.creator_id == UserService.Instance.user.id;
} }
get canMod(): boolean {
if (this.props.editable) {
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.post.creator_id);
} 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) { handlePostLike(i: PostListing) {
let form: CreatePostLikeForm = { let form: CreatePostLikeForm = {
@ -207,8 +238,6 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
url: '', url: '',
edit_id: i.props.post.id, edit_id: i.props.post.id,
creator_id: i.props.post.creator_id, creator_id: i.props.post.creator_id,
removed: !i.props.post.removed,
locked: !i.props.post.locked,
auth: null auth: null
}; };
WebSocketService.Instance.editPost(deleteForm); WebSocketService.Instance.editPost(deleteForm);
@ -242,7 +271,6 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
edit_id: i.props.post.id, edit_id: i.props.post.id,
creator_id: i.props.post.creator_id, creator_id: i.props.post.creator_id,
removed: !i.props.post.removed, removed: !i.props.post.removed,
locked: !i.props.post.locked,
reason: i.state.removeReason, reason: i.state.removeReason,
auth: null, auth: null,
}; };
@ -258,7 +286,6 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
community_id: i.props.post.community_id, community_id: i.props.post.community_id,
edit_id: i.props.post.id, edit_id: i.props.post.id,
creator_id: i.props.post.creator_id, creator_id: i.props.post.creator_id,
removed: !i.props.post.removed,
locked: !i.props.post.locked, locked: !i.props.post.locked,
auth: null, auth: null,
}; };

View file

@ -82,7 +82,14 @@ export class Post extends Component<any, PostState> {
<h5><svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg></h5> : <h5><svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg></h5> :
<div class="row"> <div class="row">
<div class="col-12 col-md-8 col-lg-7 mb-3"> <div class="col-12 col-md-8 col-lg-7 mb-3">
<PostListing post={this.state.post} showBody showCommunity editable /> <PostListing
post={this.state.post}
showBody
showCommunity
editable
moderators={this.state.moderators}
admins={this.state.admins}
/>
<div className="mb-2" /> <div className="mb-2" />
<CommentForm postId={this.state.post.id} disabled={this.state.post.locked} /> <CommentForm postId={this.state.post.id} disabled={this.state.post.locked} />
{this.sortRadios()} {this.sortRadios()}

View file

@ -370,8 +370,8 @@ export interface PostForm {
updated?: number; updated?: number;
edit_id?: number; edit_id?: number;
creator_id: number; creator_id: number;
removed: boolean; removed?: boolean;
locked: boolean; locked?: boolean;
reason?: string; reason?: string;
auth: string; auth: string;
} }
@ -402,7 +402,7 @@ export interface CommentForm {
parent_id?: number; parent_id?: number;
edit_id?: number; edit_id?: number;
creator_id: number; creator_id: number;
removed: boolean; removed?: boolean;
reason?: string; reason?: string;
auth: string; auth: string;
} }