Added new role for moderator to Groups

• Added:
- new role for moderator to Groups
This commit is contained in:
mgabdev 2020-09-02 18:06:38 -05:00
parent cc224d7659
commit ac9b9e8448
8 changed files with 61 additions and 19 deletions

View File

@ -24,6 +24,7 @@ class GroupCollectionItem extends ImmutablePureComponent {
const isMember = relationships.get('member') const isMember = relationships.get('member')
const isAdmin = relationships.get('admin') const isAdmin = relationships.get('admin')
const isModerator = relationships.get('moderator')
const coverSrc = group.get('cover_image_url') || '' const coverSrc = group.get('cover_image_url') || ''
const coverMissing = coverSrc.indexOf(PLACEHOLDER_MISSING_HEADER_SRC) > -1 || !coverSrc const coverMissing = coverSrc.indexOf(PLACEHOLDER_MISSING_HEADER_SRC) > -1 || !coverSrc
@ -34,6 +35,7 @@ class GroupCollectionItem extends ImmutablePureComponent {
{group.get('title')} {group.get('title')}
{isMember && intl.formatMessage(messages.member)} {isMember && intl.formatMessage(messages.member)}
{isAdmin && intl.formatMessage(messages.admin)} {isAdmin && intl.formatMessage(messages.admin)}
{isModerator && intl.formatMessage(messages.moderator)}
</React.Fragment> </React.Fragment>
) )
} }
@ -69,12 +71,12 @@ class GroupCollectionItem extends ImmutablePureComponent {
} }
{ {
(!coverSrc || coverMissing) && (isMember || isAdmin) && (!coverSrc || coverMissing) && (isMember || isAdmin || isModerator) &&
<div className={[_s.d, _s.h40PX, _s.bgSubtle, _s.borderColorSecondary, _s.borderBottom1PX].join(' ')} /> <div className={[_s.d, _s.h40PX, _s.bgSubtle, _s.borderColorSecondary, _s.borderBottom1PX].join(' ')} />
} }
{ {
(isMember || isAdmin) && (isMember || isAdmin || isModerator) &&
<div className={[_s.d, _s.flexRow, _s.posAbs, _s.top0, _s.right0, _s.pt10, _s.mr10].join(' ')}> <div className={[_s.d, _s.flexRow, _s.posAbs, _s.top0, _s.right0, _s.pt10, _s.mr10].join(' ')}>
{ {
isMember && isMember &&
@ -98,6 +100,17 @@ class GroupCollectionItem extends ImmutablePureComponent {
{intl.formatMessage(messages.admin)} {intl.formatMessage(messages.admin)}
</Text> </Text>
} }
{
isModerator &&
<Text
isBadge
className={[_s.bgBlack, _s.ml5].join(' ')}
size='extraSmall'
color='white'
>
{intl.formatMessage(messages.moderator)}
</Text>
}
</div> </div>
} }
@ -127,6 +140,7 @@ const messages = defineMessages({
viewGroup: { id: 'view_group', defaultMessage: 'View Group' }, viewGroup: { id: 'view_group', defaultMessage: 'View Group' },
member: { id: 'member', defaultMessage: 'Member' }, member: { id: 'member', defaultMessage: 'Member' },
admin: { id: 'admin', defaultMessage: 'Admin' }, admin: { id: 'admin', defaultMessage: 'Admin' },
moderator: { id: 'moderator', defaultMessage: 'Moderator' },
}) })
const mapStateToProps = (state, { id }) => ({ const mapStateToProps = (state, { id }) => ({

View File

@ -15,8 +15,8 @@ class GroupMemberOptionsPopover extends React.PureComponent {
this.props.onCreateRemovedAccount(this.props.groupId, this.props.accountId) this.props.onCreateRemovedAccount(this.props.groupId, this.props.accountId)
} }
handleOnMakeAdmin = () => { handleOnUpdateRole = (role) => {
this.props.onUpdateRole(this.props.groupId, this.props.accountId, 'admin') this.props.onUpdateRole(this.props.groupId, this.props.accountId, role)
} }
handleOnClosePopover = () => { handleOnClosePopover = () => {
@ -24,7 +24,7 @@ class GroupMemberOptionsPopover extends React.PureComponent {
} }
render() { render() {
const { isXS } = this.props const { isModerator, isXS } = this.props
const listItems = [ const listItems = [
{ {
@ -33,13 +33,23 @@ class GroupMemberOptionsPopover extends React.PureComponent {
title: 'Remove from group', title: 'Remove from group',
onClick: this.handleOnRemoveFromGroup, onClick: this.handleOnRemoveFromGroup,
}, },
{ ]
if (!isModerator) {
listItems.push({
hideArrow: true,
icon: 'group',
title: 'Make group moderator',
onClick: () => this.handleOnUpdateRole('moderator'),
})
listItems.push({
hideArrow: true, hideArrow: true,
icon: 'group', icon: 'group',
title: 'Make group admin', title: 'Make group admin',
onClick: this.handleOnMakeAdmin, onClick: () => this.handleOnUpdateRole('admin'),
}, })
] }
return ( return (
<PopoverLayout <PopoverLayout
@ -77,6 +87,7 @@ GroupMemberOptionsPopover.defaultProps = {
onClosePopover: PropTypes.func.isRequired, onClosePopover: PropTypes.func.isRequired,
onCreateRemovedAccount: PropTypes.func.isRequired, onCreateRemovedAccount: PropTypes.func.isRequired,
onUpdateRole: PropTypes.func.isRequired, onUpdateRole: PropTypes.func.isRequired,
isModerator: PropTypes.bool,
} }
export default connect(null, mapDispatchToProps)(GroupMemberOptionsPopover) export default connect(null, mapDispatchToProps)(GroupMemberOptionsPopover)

View File

@ -149,7 +149,7 @@ class StatusOptionsPopover extends ImmutablePureComponent {
const mutingConversation = status.get('muted') const mutingConversation = status.get('muted')
const publicStatus = ['public', 'unlisted'].includes(status.get('visibility')) const publicStatus = ['public', 'unlisted'].includes(status.get('visibility'))
const isReply = !!status.get('in_reply_to_id') const isReply = !!status.get('in_reply_to_id')
const withGroupAdmin = !!groupRelationships ? groupRelationships.get('admin') : false const withGroupAdmin = !!groupRelationships ? (groupRelationships.get('admin') || groupRelationships.get('moderator')) : false
const mailToHref = !status ? undefined : `mailto:?subject=Gab&body=${status.get('url')}` const mailToHref = !status ? undefined : `mailto:?subject=Gab&body=${status.get('url')}`
let menu = [] let menu = []

View File

@ -34,7 +34,10 @@ class GroupMembers extends ImmutablePureComponent {
} }
handleOpenGroupMemberOptions = (e, accountId) => { handleOpenGroupMemberOptions = (e, accountId) => {
this.props.onOpenGroupMemberOptions(e.currentTarget, accountId, this.props.groupId) const { relationships, groupId } = this.props
const isMod = relationships ? relationships.get('moderator') : true
this.props.onOpenGroupMemberOptions(e.currentTarget, accountId, groupId, isMod)
} }
handleLoadMore = debounce(() => { handleLoadMore = debounce(() => {
@ -51,9 +54,9 @@ class GroupMembers extends ImmutablePureComponent {
if (!group || !relationships) return <ColumnIndicator type='loading' /> if (!group || !relationships) return <ColumnIndicator type='loading' />
const isAdmin = relationships ? relationships.get('admin') : false const isAdminOrMod = relationships ? (relationships.get('admin') || relationships.get('moderator')) : false
if (!isAdmin) return <ColumnIndicator type='missing' /> if (!isAdminOrMod) return <ColumnIndicator type='missing' />
return ( return (
<Block> <Block>
@ -86,13 +89,14 @@ class GroupMembers extends ImmutablePureComponent {
> >
{ {
accountIds && accountIds.map((id) => ( accountIds && accountIds.map((id) => (
// : todo : add badges for isAdmin, isModerator
<Account <Account
compact compact
key={id} key={id}
id={id} id={id}
actionIcon={(!isAdmin || id === me) ? undefined : 'ellipsis'} actionIcon={(!isAdminOrMod || id === me) ? undefined : 'ellipsis'}
onActionClick={(data, event) => { onActionClick={(data, event) => {
return !isAdmin ? false : this.handleOpenGroupMemberOptions(event, id) return !isAdminOrMod ? false : this.handleOpenGroupMemberOptions(event, id)
}} }}
/> />
)) ))
@ -125,11 +129,12 @@ const mapDispatchToProps = (dispatch) => ({
onExpandMembers(groupId) { onExpandMembers(groupId) {
dispatch(expandMembers(groupId)) dispatch(expandMembers(groupId))
}, },
onOpenGroupMemberOptions(targetRef, accountId, groupId) { onOpenGroupMemberOptions(targetRef, accountId, groupId, isModerator) {
dispatch(openPopover('GROUP_MEMBER_OPTIONS', { dispatch(openPopover('GROUP_MEMBER_OPTIONS', {
targetRef, targetRef,
accountId, accountId,
groupId, groupId,
isModerator,
position: 'top', position: 'top',
})) }))
}, },

View File

@ -13,6 +13,10 @@ module GroupInteractions
follow_mapping(GroupAccount.where(group_id: target_group_ids, account_id: account_id, role: :admin), :group_id) follow_mapping(GroupAccount.where(group_id: target_group_ids, account_id: account_id, role: :admin), :group_id)
end end
def moderator_map(target_group_ids, account_id)
follow_mapping(GroupAccount.where(group_id: target_group_ids, account_id: account_id, role: :moderator), :group_id)
end
private private
def follow_mapping(query, field) def follow_mapping(query, field)

View File

@ -13,7 +13,10 @@
class GroupAccount < ApplicationRecord class GroupAccount < ApplicationRecord
self.ignored_columns = ["unread_count"] self.ignored_columns = ["unread_count"]
enum role: { admin: "admin" } enum role: {
admin: "admin",
moderator: "moderator"
}
belongs_to :group belongs_to :group
belongs_to :account belongs_to :account

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class GroupRelationshipsPresenter class GroupRelationshipsPresenter
attr_reader :member, :admin attr_reader :member, :admin, :moderator
def initialize(group_ids, current_account_id, **options) def initialize(group_ids, current_account_id, **options)
@group_ids = group_ids.map { |a| a.is_a?(Group) ? a.id : a } @group_ids = group_ids.map { |a| a.is_a?(Group) ? a.id : a }
@ -9,6 +9,7 @@ class GroupRelationshipsPresenter
@member = Group.member_map(@group_ids, @current_account_id) @member = Group.member_map(@group_ids, @current_account_id)
@admin = Group.admin_map(@group_ids, @current_account_id) @admin = Group.admin_map(@group_ids, @current_account_id)
@moderator = Group.moderator_map(@group_ids, @current_account_id)
end end
end end

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class REST::GroupRelationshipSerializer < ActiveModel::Serializer class REST::GroupRelationshipSerializer < ActiveModel::Serializer
attributes :id, :member, :admin attributes :id, :member, :admin, :moderator
def id def id
object.id.to_s object.id.to_s
@ -15,4 +15,8 @@ class REST::GroupRelationshipSerializer < ActiveModel::Serializer
instance_options[:relationships].admin[object.id] ? true : false instance_options[:relationships].admin[object.id] ? true : false
end end
def moderator
instance_options[:relationships].moderator[object.id] ? true : false
end
end end