Commentron Moderation Delegation API
This commit is contained in:
parent
510056a479
commit
b4b45ffbdc
7 changed files with 864 additions and 97 deletions
42
flow-typed/Comment.js
vendored
42
flow-typed/Comment.js
vendored
|
@ -37,10 +37,18 @@ declare type CommentsState = {
|
|||
myReactsByCommentId: any,
|
||||
othersReactsByCommentId: any,
|
||||
pendingCommentReactions: Array<string>,
|
||||
moderationBlockList: ?Array<string>,
|
||||
moderationBlockList: ?Array<string>, // @KP rename to "personalBlockList"?
|
||||
adminBlockList: ?Array<string>,
|
||||
moderatorBlockList: ?Array<string>,
|
||||
moderatorBlockListDelegatorsMap: {[string]: Array<string>}, // {"blockedUri": ["delegatorUri1", ""delegatorUri2", ...]}
|
||||
fetchingModerationBlockList: boolean,
|
||||
moderationDelegatesById: { [string]: Array<{ channelId: string, channelName: string }> },
|
||||
fetchingModerationDelegates: boolean,
|
||||
moderationDelegatorsById: { [string]: { global: boolean, delegators: { name: string, claimId: string } }},
|
||||
fetchingModerationDelegators: boolean,
|
||||
blockingByUri: {},
|
||||
unBlockingByUri: {},
|
||||
togglingForDelegatorMap: {[string]: Array<string>}, // {"blockedUri": ["delegatorUri1", ""delegatorUri2", ...]}
|
||||
commentsDisabledChannelIds: Array<string>,
|
||||
settingsByChannelId: { [string]: PerChannelSettings }, // ChannelID -> settings
|
||||
fetchingSettings: boolean,
|
||||
|
@ -88,6 +96,38 @@ declare type SuperListParams = {};
|
|||
|
||||
declare type ModerationBlockParams = {};
|
||||
|
||||
declare type ModerationAddDelegateParams = {
|
||||
mod_channel_id: string,
|
||||
mod_channel_name: string,
|
||||
creator_channel_id: string,
|
||||
creator_channel_name: string,
|
||||
signature: string,
|
||||
signing_ts: string,
|
||||
};
|
||||
|
||||
declare type ModerationRemoveDelegateParams = {
|
||||
mod_channel_id: string,
|
||||
mod_channel_name: string,
|
||||
creator_channel_id: string,
|
||||
creator_channel_name: string,
|
||||
signature: string,
|
||||
signing_ts: string,
|
||||
};
|
||||
|
||||
declare type ModerationListDelegatesParams = {
|
||||
creator_channel_id: string,
|
||||
creator_channel_name: string,
|
||||
signature: string,
|
||||
signing_ts: string,
|
||||
};
|
||||
|
||||
declare type ModerationAmIParams = {
|
||||
channel_name: string,
|
||||
channel_id: string,
|
||||
signature: string,
|
||||
signing_ts: string
|
||||
};
|
||||
|
||||
declare type SettingsParams = {
|
||||
channel_name: string,
|
||||
channel_id: string,
|
||||
|
|
|
@ -8,6 +8,12 @@ const Comments = {
|
|||
moderation_block: (params: ModerationBlockParams) => fetchCommentsApi('moderation.Block', params),
|
||||
moderation_unblock: (params: ModerationBlockParams) => fetchCommentsApi('moderation.UnBlock', params),
|
||||
moderation_block_list: (params: ModerationBlockParams) => fetchCommentsApi('moderation.BlockedList', params),
|
||||
moderation_add_delegate: (params: ModerationAddDelegateParams) => fetchCommentsApi('moderation.AddDelegate', params),
|
||||
moderation_remove_delegate: (params: ModerationRemoveDelegateParams) =>
|
||||
fetchCommentsApi('moderation.RemoveDelegate', params),
|
||||
moderation_list_delegates: (params: ModerationListDelegatesParams) =>
|
||||
fetchCommentsApi('moderation.ListDelegates', params),
|
||||
moderation_am_i: (params: ModerationAmIParams) => fetchCommentsApi('moderation.AmI', params),
|
||||
comment_list: (params: CommentListParams) => fetchCommentsApi('comment.List', params),
|
||||
comment_abandon: (params: CommentAbandonParams) => fetchCommentsApi('comment.Abandon', params),
|
||||
comment_create: (params: CommentCreateParams) => fetchCommentsApi('comment.Create', params),
|
||||
|
|
|
@ -278,6 +278,12 @@ export const COMMENT_MODERATION_BLOCK_FAILED = 'COMMENT_MODERATION_BLOCK_FAILED'
|
|||
export const COMMENT_MODERATION_UN_BLOCK_STARTED = 'COMMENT_MODERATION_UN_BLOCK_STARTED';
|
||||
export const COMMENT_MODERATION_UN_BLOCK_COMPLETE = 'COMMENT_MODERATION_UN_BLOCK_COMPLETE';
|
||||
export const COMMENT_MODERATION_UN_BLOCK_FAILED = 'COMMENT_MODERATION_UN_BLOCK_FAILED';
|
||||
export const COMMENT_FETCH_MODERATION_DELEGATES_STARTED = 'COMMENT_FETCH_MODERATION_DELEGATES_STARTED';
|
||||
export const COMMENT_FETCH_MODERATION_DELEGATES_FAILED = 'COMMENT_FETCH_MODERATION_DELEGATES_FAILED';
|
||||
export const COMMENT_FETCH_MODERATION_DELEGATES_COMPLETED = 'COMMENT_FETCH_MODERATION_DELEGATES_COMPLETED';
|
||||
export const COMMENT_MODERATION_AM_I_LIST_STARTED = 'COMMENT_MODERATION_AM_I_LIST_STARTED';
|
||||
export const COMMENT_MODERATION_AM_I_LIST_FAILED = 'COMMENT_MODERATION_AM_I_LIST_FAILED';
|
||||
export const COMMENT_MODERATION_AM_I_LIST_COMPLETED = 'COMMENT_MODERATION_AM_I_LIST_COMPLETED';
|
||||
export const COMMENT_FETCH_SETTINGS_STARTED = 'COMMENT_FETCH_SETTINGS_STARTED';
|
||||
export const COMMENT_FETCH_SETTINGS_FAILED = 'COMMENT_FETCH_SETTINGS_FAILED';
|
||||
export const COMMENT_FETCH_SETTINGS_COMPLETED = 'COMMENT_FETCH_SETTINGS_COMPLETED';
|
||||
|
|
|
@ -3,3 +3,9 @@ export const LINKED_COMMENT_QUERY_PARAM = 'lc';
|
|||
export const SORT_COMMENTS_NEW = 'new';
|
||||
export const SORT_COMMENTS_BEST = 'best';
|
||||
export const SORT_COMMENTS_CONTROVERSIAL = 'controversial';
|
||||
|
||||
export const BLOCK_LEVEL = {
|
||||
SELF: 'self',
|
||||
MODERATOR: 'moderator',
|
||||
ADMIN: 'admin',
|
||||
};
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
// @flow
|
||||
import * as ACTIONS from 'constants/action_types';
|
||||
import * as REACTION_TYPES from 'constants/reactions';
|
||||
import { Lbry, parseURI, buildURI, selectClaimsByUri, selectMyChannelClaims } from 'lbry-redux';
|
||||
import { BLOCK_LEVEL } from 'constants/comment';
|
||||
import { Lbry, parseURI, buildURI, selectClaimsById, selectClaimsByUri, selectMyChannelClaims } from 'lbry-redux';
|
||||
import { doToast, doSeeNotifications } from 'redux/actions/notifications';
|
||||
import {
|
||||
makeSelectCommentIdsForUri,
|
||||
|
@ -9,6 +10,7 @@ import {
|
|||
makeSelectOthersReactionsForComment,
|
||||
selectPendingCommentReacts,
|
||||
selectModerationBlockList,
|
||||
selectModerationDelegatorsById,
|
||||
} from 'redux/selectors/comments';
|
||||
import { makeSelectNotificationForCommentId } from 'redux/selectors/notifications';
|
||||
import { selectActiveChannelClaim } from 'redux/selectors/app';
|
||||
|
@ -522,42 +524,87 @@ async function channelSignName(channelClaimId: string, channelName: string) {
|
|||
}
|
||||
|
||||
// Hides a users comments from all creator's claims and prevent them from commenting in the future
|
||||
export function doCommentModToggleBlock(channelUri: string, showLink: boolean, unblock: boolean = false) {
|
||||
function doCommentModToggleBlock(
|
||||
unblock: boolean,
|
||||
commenterUri: string,
|
||||
creatorId: string,
|
||||
blockerIds: Array<string>, // [] = use all my channels
|
||||
blockLevel: string,
|
||||
showLink: boolean = false
|
||||
) {
|
||||
return async (dispatch: Dispatch, getState: GetState) => {
|
||||
const state = getState();
|
||||
const myChannels = selectMyChannelClaims(state);
|
||||
const claim = selectClaimsByUri(state)[channelUri];
|
||||
|
||||
if (!claim) {
|
||||
let blockerChannelClaims = selectMyChannelClaims(state);
|
||||
if (blockerIds.length === 0) {
|
||||
// Specific blockers not provided, so find one based on block-level.
|
||||
switch (blockLevel) {
|
||||
case BLOCK_LEVEL.MODERATOR:
|
||||
{
|
||||
// Find the first channel that is a moderator for 'creatorId'.
|
||||
const delegatorsById = selectModerationDelegatorsById(state);
|
||||
blockerChannelClaims = [
|
||||
blockerChannelClaims.find((x) => {
|
||||
const delegatorDataForId = delegatorsById[x.claim_id];
|
||||
return delegatorDataForId && Object.values(delegatorDataForId.delegators).includes(creatorId);
|
||||
}),
|
||||
];
|
||||
}
|
||||
break;
|
||||
|
||||
case BLOCK_LEVEL.ADMIN:
|
||||
{
|
||||
// Find the first admin channel and use that.
|
||||
const delegatorsById = selectModerationDelegatorsById(state);
|
||||
blockerChannelClaims = [
|
||||
blockerChannelClaims.find((x) => delegatorsById[x.claim_id] && delegatorsById[x.claim_id].global),
|
||||
];
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
blockerChannelClaims = blockerChannelClaims.filter((x) => blockerIds.includes(x.claim_id));
|
||||
}
|
||||
|
||||
const commenterClaim = selectClaimsByUri(state)[commenterUri];
|
||||
if (!commenterClaim) {
|
||||
console.error("Can't find claim to block"); // eslint-disable-line
|
||||
return;
|
||||
}
|
||||
|
||||
const creatorClaim = selectClaimsById(state)[creatorId];
|
||||
if (creatorId && !creatorClaim) {
|
||||
console.error("Can't find creator claim"); // eslint-disable-line
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: unblock ? ACTIONS.COMMENT_MODERATION_UN_BLOCK_STARTED : ACTIONS.COMMENT_MODERATION_BLOCK_STARTED,
|
||||
data: {
|
||||
uri: channelUri,
|
||||
blockedUri: commenterUri,
|
||||
creatorUri: creatorClaim ? creatorClaim.permanent_url : undefined,
|
||||
blockLevel: blockLevel,
|
||||
},
|
||||
});
|
||||
|
||||
const creatorIdForAction = claim ? claim.claim_id : null;
|
||||
const creatorNameForAction = claim ? claim.name : null;
|
||||
const commenterIdForAction = commenterClaim ? commenterClaim.claim_id : null;
|
||||
const commenterNameForAction = commenterClaim ? commenterClaim.name : null;
|
||||
|
||||
let channelSignatures = [];
|
||||
|
||||
const sharedModBlockParams = unblock
|
||||
? {
|
||||
un_blocked_channel_id: creatorIdForAction,
|
||||
un_blocked_channel_name: creatorNameForAction,
|
||||
un_blocked_channel_id: commenterIdForAction,
|
||||
un_blocked_channel_name: commenterNameForAction,
|
||||
}
|
||||
: {
|
||||
blocked_channel_id: creatorIdForAction,
|
||||
blocked_channel_name: creatorNameForAction,
|
||||
blocked_channel_id: commenterIdForAction,
|
||||
blocked_channel_name: commenterNameForAction,
|
||||
};
|
||||
|
||||
const commentAction = unblock ? Comments.moderation_unblock : Comments.moderation_block;
|
||||
|
||||
return Promise.all(myChannels.map((channel) => channelSignName(channel.claim_id, channel.name)))
|
||||
return Promise.all(blockerChannelClaims.map((x) => channelSignName(x.claim_id, x.name)))
|
||||
.then((response) => {
|
||||
channelSignatures = response;
|
||||
// $FlowFixMe
|
||||
|
@ -566,49 +613,174 @@ export function doCommentModToggleBlock(channelUri: string, showLink: boolean, u
|
|||
.filter((x) => x !== undefined && x !== null)
|
||||
.map((signatureData) =>
|
||||
commentAction({
|
||||
// $FlowFixMe
|
||||
mod_channel_id: signatureData.claim_id,
|
||||
// $FlowFixMe
|
||||
mod_channel_name: signatureData.name,
|
||||
// $FlowFixMe
|
||||
signature: signatureData.signature,
|
||||
// $FlowFixMe
|
||||
signing_ts: signatureData.signing_ts,
|
||||
creator_channel_id: creatorClaim ? creatorClaim.claim_id : undefined,
|
||||
creator_channel_name: creatorClaim ? creatorClaim.name : undefined,
|
||||
block_all: unblock ? undefined : blockLevel === BLOCK_LEVEL.ADMIN,
|
||||
global_un_block: unblock ? blockLevel === BLOCK_LEVEL.ADMIN : undefined,
|
||||
...sharedModBlockParams,
|
||||
})
|
||||
)
|
||||
)
|
||||
.then(() => {
|
||||
.then((response) => {
|
||||
const failures = [];
|
||||
|
||||
response.forEach((res, index) => {
|
||||
if (res.status === 'rejected') {
|
||||
// TODO: This should be error codes
|
||||
if (res.reason.message !== 'validation is disallowed for non controlling channels') {
|
||||
// $FlowFixMe
|
||||
failures.push(channelSignatures[index].name + ': ' + res.reason.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (failures.length !== 0) {
|
||||
dispatch(doToast({ message: failures.join(), isError: true }));
|
||||
dispatch({
|
||||
type: unblock ? ACTIONS.COMMENT_MODERATION_UN_BLOCK_FAILED : ACTIONS.COMMENT_MODERATION_BLOCK_FAILED,
|
||||
data: {
|
||||
blockedUri: commenterUri,
|
||||
creatorUri: creatorClaim ? creatorClaim.permanent_url : undefined,
|
||||
blockLevel: blockLevel,
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: unblock ? ACTIONS.COMMENT_MODERATION_UN_BLOCK_COMPLETE : ACTIONS.COMMENT_MODERATION_BLOCK_COMPLETE,
|
||||
data: { channelUri },
|
||||
data: {
|
||||
blockedUri: commenterUri,
|
||||
creatorUri: creatorClaim ? creatorClaim.permanent_url : undefined,
|
||||
blockLevel: blockLevel,
|
||||
},
|
||||
});
|
||||
|
||||
dispatch(doToast({
|
||||
message: __(!unblock ? 'Channel blocked. They will not interact with you again.' : 'Channel unblocked!'),
|
||||
dispatch(
|
||||
doToast({
|
||||
message: unblock
|
||||
? __('Channel unblocked!')
|
||||
: __('Channel "%channel%" blocked.', { channel: commenterNameForAction }),
|
||||
linkText: __(showLink ? 'See All' : ''),
|
||||
linkTarget: '/settings/block_and_mute',
|
||||
}));
|
||||
})
|
||||
);
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch({
|
||||
type: unblock ? ACTIONS.COMMENT_MODERATION_UN_BLOCK_FAILED : ACTIONS.COMMENT_MODERATION_BLOCK_FAILED,
|
||||
data: {
|
||||
blockedUri: commenterUri,
|
||||
creatorUri: creatorClaim ? creatorClaim.permanent_url : undefined,
|
||||
blockLevel: blockLevel,
|
||||
},
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch({
|
||||
type: unblock ? ACTIONS.COMMENT_MODERATION_UN_BLOCK_FAILED : ACTIONS.COMMENT_MODERATION_BLOCK_FAILED,
|
||||
data: {
|
||||
blockedUri: commenterUri,
|
||||
creatorUri: creatorClaim ? creatorClaim.permanent_url : undefined,
|
||||
blockLevel: blockLevel,
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function doCommentModBlock(commentAuthor: string, showLink: boolean = true) {
|
||||
/**
|
||||
* Blocks the commenter for all channels that I own.
|
||||
*
|
||||
* @param commenterUri
|
||||
* @param showLink
|
||||
* @returns {function(Dispatch): *}
|
||||
*/
|
||||
export function doCommentModBlock(commenterUri: string, showLink: boolean = true) {
|
||||
return (dispatch: Dispatch) => {
|
||||
return dispatch(doCommentModToggleBlock(commentAuthor, showLink));
|
||||
return dispatch(doCommentModToggleBlock(false, commenterUri, '', [], BLOCK_LEVEL.SELF, showLink));
|
||||
};
|
||||
}
|
||||
|
||||
export function doCommentModUnBlock(commentAuthor: string, showLink: boolean = true) {
|
||||
/**
|
||||
* Blocks the commenter using the given channel that has Global privileges.
|
||||
*
|
||||
* @param commenterUri
|
||||
* @param blockerId
|
||||
* @returns {function(Dispatch): *}
|
||||
*/
|
||||
export function doCommentModBlockAsAdmin(commenterUri: string, blockerId: string) {
|
||||
return (dispatch: Dispatch) => {
|
||||
return dispatch(doCommentModToggleBlock(commentAuthor, showLink, true));
|
||||
return dispatch(doCommentModToggleBlock(false, commenterUri, '', blockerId ? [blockerId] : [], BLOCK_LEVEL.ADMIN));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks the commenter using the given channel that has been granted
|
||||
* moderation rights by the creator.
|
||||
*
|
||||
* @param commenterUri
|
||||
* @param creatorId
|
||||
* @param blockerId
|
||||
* @returns {function(Dispatch): *}
|
||||
*/
|
||||
export function doCommentModBlockAsModerator(commenterUri: string, creatorId: string, blockerId: string) {
|
||||
return (dispatch: Dispatch) => {
|
||||
return dispatch(
|
||||
doCommentModToggleBlock(false, commenterUri, creatorId, blockerId ? [blockerId] : [], BLOCK_LEVEL.MODERATOR)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Unblocks the commenter for all channels that I own.
|
||||
*
|
||||
* @param commenterUri
|
||||
* @param showLink
|
||||
* @returns {function(Dispatch): *}
|
||||
*/
|
||||
export function doCommentModUnBlock(commenterUri: string, showLink: boolean = true) {
|
||||
return (dispatch: Dispatch) => {
|
||||
return dispatch(doCommentModToggleBlock(true, commenterUri, '', [], BLOCK_LEVEL.SELF, showLink));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Unblocks the commenter using the given channel that has Global privileges.
|
||||
*
|
||||
* @param commenterUri
|
||||
* @param blockerId
|
||||
* @returns {function(Dispatch): *}
|
||||
*/
|
||||
export function doCommentModUnBlockAsAdmin(commenterUri: string, blockerId: string) {
|
||||
return (dispatch: Dispatch) => {
|
||||
return dispatch(doCommentModToggleBlock(true, commenterUri, '', blockerId ? [blockerId] : [], BLOCK_LEVEL.ADMIN));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Unblocks the commenter using the given channel that has been granted
|
||||
* moderation rights by the creator.
|
||||
*
|
||||
* @param commenterUri
|
||||
* @param creatorId
|
||||
* @param blockerId
|
||||
* @returns {function(Dispatch): *}
|
||||
*/
|
||||
export function doCommentModUnBlockAsModerator(commenterUri: string, creatorId: string, blockerId: string) {
|
||||
return (dispatch: Dispatch) => {
|
||||
return dispatch(
|
||||
doCommentModToggleBlock(true, commenterUri, creatorId, blockerId ? [blockerId] : [], BLOCK_LEVEL.MODERATOR)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -640,39 +812,80 @@ export function doFetchModBlockedList() {
|
|||
)
|
||||
)
|
||||
.then((res) => {
|
||||
const blockLists = res.map((r) => r.value);
|
||||
let globalBlockList = [];
|
||||
blockLists
|
||||
let personalBlockList = [];
|
||||
let adminBlockList = [];
|
||||
let moderatorBlockList = [];
|
||||
let moderatorBlockListDelegatorsMap = {};
|
||||
|
||||
const blockListsPerChannel = res.map((r) => r.value);
|
||||
blockListsPerChannel
|
||||
.sort((a, b) => {
|
||||
return 1;
|
||||
})
|
||||
.forEach((channelBlockListData) => {
|
||||
const blockListForChannel = channelBlockListData && channelBlockListData.blocked_channels;
|
||||
if (blockListForChannel) {
|
||||
blockListForChannel.forEach((blockedChannel) => {
|
||||
.forEach((channelBlockLists) => {
|
||||
const storeList = (fetchedList, blockedList, blockedByMap) => {
|
||||
if (fetchedList) {
|
||||
fetchedList.forEach((blockedChannel) => {
|
||||
if (blockedChannel.blocked_channel_name) {
|
||||
const channelUri = buildURI({
|
||||
channelName: blockedChannel.blocked_channel_name,
|
||||
claimId: blockedChannel.blocked_channel_id,
|
||||
});
|
||||
|
||||
if (!globalBlockList.find((blockedChannel) => blockedChannel.channelUri === channelUri)) {
|
||||
globalBlockList.push({ channelUri, blockedAt: blockedChannel.blocked_at });
|
||||
if (!blockedList.find((blockedChannel) => blockedChannel.channelUri === channelUri)) {
|
||||
blockedList.push({ channelUri, blockedAt: blockedChannel.blocked_at });
|
||||
}
|
||||
|
||||
if (blockedByMap !== undefined) {
|
||||
const blockedByChannelUri = buildURI({
|
||||
channelName: blockedChannel.blocked_by_channel_name,
|
||||
claimId: blockedChannel.blocked_by_channel_id,
|
||||
});
|
||||
|
||||
if (blockedByMap[channelUri]) {
|
||||
if (!blockedByMap[channelUri].includes(blockedByChannelUri)) {
|
||||
blockedByMap[channelUri].push(blockedByChannelUri);
|
||||
}
|
||||
} else {
|
||||
blockedByMap[channelUri] = [blockedByChannelUri];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const blocked_channels = channelBlockLists && channelBlockLists.blocked_channels;
|
||||
const globally_blocked_channels = channelBlockLists && channelBlockLists.globally_blocked_channels;
|
||||
const delegated_blocked_channels = channelBlockLists && channelBlockLists.delegated_blocked_channels;
|
||||
|
||||
storeList(blocked_channels, personalBlockList);
|
||||
storeList(globally_blocked_channels, adminBlockList);
|
||||
storeList(delegated_blocked_channels, moderatorBlockList, moderatorBlockListDelegatorsMap);
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: ACTIONS.COMMENT_MODERATION_BLOCK_LIST_COMPLETED,
|
||||
data: {
|
||||
blockList:
|
||||
globalBlockList.length > 0
|
||||
? globalBlockList
|
||||
personalBlockList:
|
||||
personalBlockList.length > 0
|
||||
? personalBlockList
|
||||
.sort((a, b) => new Date(a.blockedAt) - new Date(b.blockedAt))
|
||||
.map((blockedChannel) => blockedChannel.channelUri)
|
||||
: null,
|
||||
adminBlockList:
|
||||
adminBlockList.length > 0
|
||||
? adminBlockList
|
||||
.sort((a, b) => new Date(a.blockedAt) - new Date(b.blockedAt))
|
||||
.map((blockedChannel) => blockedChannel.channelUri)
|
||||
: null,
|
||||
moderatorBlockList:
|
||||
moderatorBlockList.length > 0
|
||||
? moderatorBlockList
|
||||
.sort((a, b) => new Date(a.blockedAt) - new Date(b.blockedAt))
|
||||
.map((blockedChannel) => blockedChannel.channelUri)
|
||||
: null,
|
||||
moderatorBlockListDelegatorsMap: moderatorBlockListDelegatorsMap,
|
||||
},
|
||||
});
|
||||
})
|
||||
|
@ -729,6 +942,190 @@ export const doUpdateBlockListForPublishedChannel = (channelClaim: ChannelClaim)
|
|||
};
|
||||
};
|
||||
|
||||
export function doCommentModAddDelegate(
|
||||
modChannelId: string,
|
||||
modChannelName: string,
|
||||
creatorChannelClaim: ChannelClaim
|
||||
) {
|
||||
return async (dispatch: Dispatch, getState: GetState) => {
|
||||
let signature: ?{
|
||||
signature: string,
|
||||
signing_ts: string,
|
||||
};
|
||||
try {
|
||||
signature = await Lbry.channel_sign({
|
||||
channel_id: creatorChannelClaim.claim_id,
|
||||
hexdata: toHex(creatorChannelClaim.name),
|
||||
});
|
||||
} catch (e) {}
|
||||
|
||||
if (!signature) {
|
||||
return;
|
||||
}
|
||||
|
||||
return Comments.moderation_add_delegate({
|
||||
mod_channel_id: modChannelId,
|
||||
mod_channel_name: modChannelName,
|
||||
creator_channel_id: creatorChannelClaim.claim_id,
|
||||
creator_channel_name: creatorChannelClaim.name,
|
||||
signature: signature.signature,
|
||||
signing_ts: signature.signing_ts,
|
||||
}).catch((err) => {
|
||||
dispatch(
|
||||
doToast({
|
||||
message: err.message,
|
||||
isError: true,
|
||||
})
|
||||
);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function doCommentModRemoveDelegate(
|
||||
modChannelId: string,
|
||||
modChannelName: string,
|
||||
creatorChannelClaim: ChannelClaim
|
||||
) {
|
||||
return async (dispatch: Dispatch, getState: GetState) => {
|
||||
let signature: ?{
|
||||
signature: string,
|
||||
signing_ts: string,
|
||||
};
|
||||
try {
|
||||
signature = await Lbry.channel_sign({
|
||||
channel_id: creatorChannelClaim.claim_id,
|
||||
hexdata: toHex(creatorChannelClaim.name),
|
||||
});
|
||||
} catch (e) {}
|
||||
|
||||
if (!signature) {
|
||||
return;
|
||||
}
|
||||
|
||||
return Comments.moderation_remove_delegate({
|
||||
mod_channel_id: modChannelId,
|
||||
mod_channel_name: modChannelName,
|
||||
creator_channel_id: creatorChannelClaim.claim_id,
|
||||
creator_channel_name: creatorChannelClaim.name,
|
||||
signature: signature.signature,
|
||||
signing_ts: signature.signing_ts,
|
||||
}).catch((err) => {
|
||||
dispatch(
|
||||
doToast({
|
||||
message: err.message,
|
||||
isError: true,
|
||||
})
|
||||
);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function doCommentModListDelegates(channelClaim: ChannelClaim) {
|
||||
return async (dispatch: Dispatch, getState: GetState) => {
|
||||
dispatch({
|
||||
type: ACTIONS.COMMENT_FETCH_MODERATION_DELEGATES_STARTED,
|
||||
});
|
||||
|
||||
let signature: ?{
|
||||
signature: string,
|
||||
signing_ts: string,
|
||||
};
|
||||
try {
|
||||
signature = await Lbry.channel_sign({
|
||||
channel_id: channelClaim.claim_id,
|
||||
hexdata: toHex(channelClaim.name),
|
||||
});
|
||||
} catch (e) {}
|
||||
|
||||
if (!signature) {
|
||||
dispatch({
|
||||
type: ACTIONS.COMMENT_FETCH_MODERATION_DELEGATES_FAILED,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
return Comments.moderation_list_delegates({
|
||||
creator_channel_id: channelClaim.claim_id,
|
||||
creator_channel_name: channelClaim.name,
|
||||
signature: signature.signature,
|
||||
signing_ts: signature.signing_ts,
|
||||
})
|
||||
.then((response) => {
|
||||
dispatch({
|
||||
type: ACTIONS.COMMENT_FETCH_MODERATION_DELEGATES_COMPLETED,
|
||||
data: {
|
||||
id: channelClaim.claim_id,
|
||||
delegates: response.Delegates,
|
||||
},
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
dispatch({
|
||||
type: ACTIONS.COMMENT_FETCH_MODERATION_DELEGATES_FAILED,
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function doFetchCommentModAmIList(channelClaim: ChannelClaim) {
|
||||
return async (dispatch: Dispatch, getState: GetState) => {
|
||||
const state = getState();
|
||||
const myChannels = selectMyChannelClaims(state);
|
||||
|
||||
dispatch({
|
||||
type: ACTIONS.COMMENT_MODERATION_AM_I_LIST_STARTED,
|
||||
});
|
||||
|
||||
let channelSignatures = [];
|
||||
|
||||
return Promise.all(myChannels.map((channel) => channelSignName(channel.claim_id, channel.name)))
|
||||
.then((response) => {
|
||||
channelSignatures = response;
|
||||
// $FlowFixMe
|
||||
return Promise.allSettled(
|
||||
channelSignatures
|
||||
.filter((x) => x !== undefined && x !== null)
|
||||
.map((signatureData) =>
|
||||
Comments.moderation_am_i({
|
||||
channel_name: signatureData.name,
|
||||
channel_id: signatureData.claim_id,
|
||||
signature: signatureData.signature,
|
||||
signing_ts: signatureData.signing_ts,
|
||||
})
|
||||
)
|
||||
)
|
||||
.then((res) => {
|
||||
const delegatorsById = {};
|
||||
|
||||
channelSignatures.forEach((chanSig, index) => {
|
||||
if (chanSig && res[index]) {
|
||||
const value = res[index].value;
|
||||
delegatorsById[chanSig.claim_id] = {
|
||||
global: value ? value.type === 'Global' : false,
|
||||
delegators: value && value.authorized_channels ? value.authorized_channels : {},
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: ACTIONS.COMMENT_MODERATION_AM_I_LIST_COMPLETED,
|
||||
data: delegatorsById,
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
dispatch({
|
||||
type: ACTIONS.COMMENT_MODERATION_AM_I_LIST_FAILED,
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
dispatch({
|
||||
type: ACTIONS.COMMENT_MODERATION_AM_I_LIST_FAILED,
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const doFetchCreatorSettings = (channelClaimIds: Array<string> = []) => {
|
||||
return async (dispatch: Dispatch, getState: GetState) => {
|
||||
const state = getState();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// @flow
|
||||
import * as ACTIONS from 'constants/action_types';
|
||||
import { handleActions } from 'util/redux-utils';
|
||||
import { BLOCK_LEVEL } from 'constants/comment';
|
||||
|
||||
const defaultState: CommentsState = {
|
||||
commentById: {}, // commentId -> Comment
|
||||
|
@ -21,9 +22,17 @@ const defaultState: CommentsState = {
|
|||
myReactsByCommentId: undefined,
|
||||
othersReactsByCommentId: undefined,
|
||||
moderationBlockList: undefined,
|
||||
adminBlockList: undefined,
|
||||
moderatorBlockList: undefined,
|
||||
moderatorBlockListDelegatorsMap: {},
|
||||
fetchingModerationBlockList: false,
|
||||
moderationDelegatesById: {},
|
||||
fetchingModerationDelegates: false,
|
||||
moderationDelegatorsById: {},
|
||||
fetchingModerationDelegators: false,
|
||||
blockingByUri: {},
|
||||
unBlockingByUri: {},
|
||||
togglingForDelegatorMap: {},
|
||||
commentsDisabledChannelIds: [],
|
||||
settingsByChannelId: {}, // ChannelId -> PerChannelSettings
|
||||
fetchingSettings: false,
|
||||
|
@ -391,11 +400,14 @@ export default handleActions(
|
|||
fetchingModerationBlockList: true,
|
||||
}),
|
||||
[ACTIONS.COMMENT_MODERATION_BLOCK_LIST_COMPLETED]: (state: CommentsState, action: any) => {
|
||||
const { blockList } = action.data;
|
||||
const { personalBlockList, adminBlockList, moderatorBlockList, moderatorBlockListDelegatorsMap } = action.data;
|
||||
|
||||
return {
|
||||
...state,
|
||||
moderationBlockList: blockList,
|
||||
moderationBlockList: personalBlockList,
|
||||
adminBlockList: adminBlockList,
|
||||
moderatorBlockList: moderatorBlockList,
|
||||
moderatorBlockListDelegatorsMap: moderatorBlockListDelegatorsMap,
|
||||
fetchingModerationBlockList: false,
|
||||
};
|
||||
},
|
||||
|
@ -404,75 +416,312 @@ export default handleActions(
|
|||
fetchingModerationBlockList: false,
|
||||
}),
|
||||
|
||||
[ACTIONS.COMMENT_MODERATION_BLOCK_STARTED]: (state: CommentsState, action: any) => ({
|
||||
[ACTIONS.COMMENT_MODERATION_BLOCK_STARTED]: (state: CommentsState, action: any) => {
|
||||
const { blockedUri, creatorUri, blockLevel } = action.data;
|
||||
|
||||
switch (blockLevel) {
|
||||
default:
|
||||
case BLOCK_LEVEL.SELF:
|
||||
case BLOCK_LEVEL.ADMIN:
|
||||
return {
|
||||
...state,
|
||||
blockingByUri: {
|
||||
...state.blockingByUri,
|
||||
[action.data.uri]: true,
|
||||
[blockedUri]: true,
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
[ACTIONS.COMMENT_MODERATION_UN_BLOCK_STARTED]: (state: CommentsState, action: any) => ({
|
||||
case BLOCK_LEVEL.MODERATOR:
|
||||
const newMap = Object.assign({}, state.togglingForDelegatorMap);
|
||||
const togglingDelegatorsForBlockedUri = newMap[blockedUri];
|
||||
if (togglingDelegatorsForBlockedUri) {
|
||||
if (!togglingDelegatorsForBlockedUri.includes(creatorUri)) {
|
||||
togglingDelegatorsForBlockedUri.push(creatorUri);
|
||||
}
|
||||
} else {
|
||||
newMap[blockedUri] = [creatorUri];
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
togglingForDelegatorMap: newMap,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
[ACTIONS.COMMENT_MODERATION_UN_BLOCK_STARTED]: (state: CommentsState, action: any) => {
|
||||
const { blockedUri, creatorUri, blockLevel } = action.data;
|
||||
|
||||
switch (blockLevel) {
|
||||
default:
|
||||
case BLOCK_LEVEL.SELF:
|
||||
case BLOCK_LEVEL.ADMIN:
|
||||
return {
|
||||
...state,
|
||||
unBlockingByUri: {
|
||||
...state.unBlockingByUri,
|
||||
[action.data.uri]: true,
|
||||
[blockedUri]: true,
|
||||
},
|
||||
}),
|
||||
[ACTIONS.COMMENT_MODERATION_BLOCK_FAILED]: (state: CommentsState, action: any) => ({
|
||||
};
|
||||
|
||||
case BLOCK_LEVEL.MODERATOR:
|
||||
const newMap = Object.assign({}, state.togglingForDelegatorMap);
|
||||
const togglingDelegatorsForBlockedUri = newMap[blockedUri];
|
||||
if (togglingDelegatorsForBlockedUri) {
|
||||
if (!togglingDelegatorsForBlockedUri.includes(creatorUri)) {
|
||||
togglingDelegatorsForBlockedUri.push(creatorUri);
|
||||
}
|
||||
} else {
|
||||
newMap[blockedUri] = [creatorUri];
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
togglingForDelegatorMap: newMap,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
[ACTIONS.COMMENT_MODERATION_BLOCK_FAILED]: (state: CommentsState, action: any) => {
|
||||
const { blockedUri, creatorUri, blockLevel } = action.data;
|
||||
|
||||
switch (blockLevel) {
|
||||
default:
|
||||
case BLOCK_LEVEL.SELF:
|
||||
case BLOCK_LEVEL.ADMIN:
|
||||
return {
|
||||
...state,
|
||||
blockingByUri: {
|
||||
...state.blockingByUri,
|
||||
[action.data.uri]: false,
|
||||
[blockedUri]: false,
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
[ACTIONS.COMMENT_MODERATION_UN_BLOCK_FAILED]: (state: CommentsState, action: any) => ({
|
||||
case BLOCK_LEVEL.MODERATOR:
|
||||
const newMap = Object.assign({}, state.togglingForDelegatorMap);
|
||||
const togglingDelegatorsForBlockedUri = newMap[blockedUri];
|
||||
if (togglingDelegatorsForBlockedUri) {
|
||||
newMap[blockedUri] = togglingDelegatorsForBlockedUri.filter((x) => x !== creatorUri);
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
togglingForDelegatorMap: newMap,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
[ACTIONS.COMMENT_MODERATION_UN_BLOCK_FAILED]: (state: CommentsState, action: any) => {
|
||||
const { blockedUri, creatorUri, blockLevel } = action.data;
|
||||
|
||||
switch (blockLevel) {
|
||||
default:
|
||||
case BLOCK_LEVEL.SELF:
|
||||
case BLOCK_LEVEL.ADMIN:
|
||||
return {
|
||||
...state,
|
||||
unBlockingByUri: {
|
||||
...state.unBlockingByUri,
|
||||
[action.data.uri]: false,
|
||||
[blockedUri]: false,
|
||||
},
|
||||
};
|
||||
|
||||
case BLOCK_LEVEL.MODERATOR:
|
||||
const newMap = Object.assign({}, state.togglingForDelegatorMap);
|
||||
const togglingDelegatorsForBlockedUri = newMap[blockedUri];
|
||||
if (togglingDelegatorsForBlockedUri) {
|
||||
newMap[blockedUri] = togglingDelegatorsForBlockedUri.filter((x) => x !== creatorUri);
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
togglingForDelegatorMap: newMap,
|
||||
};
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
||||
[ACTIONS.COMMENT_MODERATION_BLOCK_COMPLETE]: (state: CommentsState, action: any) => {
|
||||
const { channelUri } = action.data;
|
||||
const { blockedUri, creatorUri, blockLevel } = action.data;
|
||||
const commentById = Object.assign({}, state.commentById);
|
||||
const blockingByUri = Object.assign({}, state.blockingByUri);
|
||||
const moderationBlockList = state.moderationBlockList || [];
|
||||
const newModerationBlockList = moderationBlockList.slice();
|
||||
|
||||
for (const commentId in commentById) {
|
||||
const comment = commentById[commentId];
|
||||
|
||||
if (channelUri === comment.channel_url) {
|
||||
if (blockedUri === comment.channel_url) {
|
||||
delete commentById[comment.comment_id];
|
||||
}
|
||||
}
|
||||
|
||||
delete blockingByUri[channelUri];
|
||||
|
||||
newModerationBlockList.push(channelUri);
|
||||
switch (blockLevel) {
|
||||
case BLOCK_LEVEL.SELF: {
|
||||
const blockList = state.moderationBlockList || [];
|
||||
const newBlockList = blockList.slice();
|
||||
newBlockList.push(blockedUri);
|
||||
delete blockingByUri[blockedUri];
|
||||
|
||||
return {
|
||||
...state,
|
||||
commentById,
|
||||
blockingByUri,
|
||||
moderationBlockList: newModerationBlockList,
|
||||
moderationBlockList: newBlockList,
|
||||
};
|
||||
},
|
||||
[ACTIONS.COMMENT_MODERATION_UN_BLOCK_COMPLETE]: (state: CommentsState, action: any) => {
|
||||
const { channelUri } = action.data;
|
||||
const unBlockingByUri = Object.assign(state.unBlockingByUri, {});
|
||||
const moderationBlockList = state.moderationBlockList || [];
|
||||
const newModerationBlockList = moderationBlockList.slice().filter((uri) => uri !== channelUri);
|
||||
}
|
||||
|
||||
delete unBlockingByUri[channelUri];
|
||||
case BLOCK_LEVEL.MODERATOR: {
|
||||
const blockList = state.moderatorBlockList || [];
|
||||
const newBlockList = blockList.slice();
|
||||
|
||||
// Update main block list
|
||||
if (!newBlockList.includes(blockedUri)) {
|
||||
newBlockList.push(blockedUri);
|
||||
}
|
||||
|
||||
// Update list of delegators
|
||||
const moderatorBlockListDelegatorsMap = Object.assign({}, state.moderatorBlockListDelegatorsMap);
|
||||
const delegatorUrisForBlockedUri = moderatorBlockListDelegatorsMap[blockedUri];
|
||||
if (delegatorUrisForBlockedUri) {
|
||||
if (!delegatorUrisForBlockedUri.includes(creatorUri)) {
|
||||
delegatorUrisForBlockedUri.push(creatorUri);
|
||||
}
|
||||
} else {
|
||||
moderatorBlockListDelegatorsMap[blockedUri] = [creatorUri];
|
||||
}
|
||||
|
||||
// Remove "toggling" flag
|
||||
const togglingMap = Object.assign({}, state.togglingForDelegatorMap);
|
||||
const togglingDelegatorsForBlockedUri = togglingMap[blockedUri];
|
||||
if (togglingDelegatorsForBlockedUri) {
|
||||
togglingMap[blockedUri] = togglingDelegatorsForBlockedUri.filter((x) => x !== creatorUri);
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
commentById,
|
||||
moderatorBlockList: newBlockList,
|
||||
moderatorBlockListDelegatorsMap,
|
||||
togglingForDelegatorMap: togglingMap,
|
||||
};
|
||||
}
|
||||
|
||||
case BLOCK_LEVEL.ADMIN:
|
||||
const blockList = state.adminBlockList || [];
|
||||
const newBlockList = blockList.slice();
|
||||
newBlockList.push(blockedUri);
|
||||
delete blockingByUri[blockedUri];
|
||||
|
||||
return {
|
||||
...state,
|
||||
commentById,
|
||||
blockingByUri,
|
||||
adminBlockList: newBlockList,
|
||||
};
|
||||
}
|
||||
},
|
||||
[ACTIONS.COMMENT_MODERATION_UN_BLOCK_COMPLETE]: (state: CommentsState, action: any) => {
|
||||
const { blockedUri, creatorUri, blockLevel } = action.data;
|
||||
const unBlockingByUri = Object.assign(state.unBlockingByUri, {});
|
||||
|
||||
switch (blockLevel) {
|
||||
case BLOCK_LEVEL.SELF: {
|
||||
const blockList = state.moderationBlockList || [];
|
||||
delete unBlockingByUri[blockedUri];
|
||||
return {
|
||||
...state,
|
||||
unBlockingByUri,
|
||||
moderationBlockList: newModerationBlockList,
|
||||
moderationBlockList: blockList.slice().filter((uri) => uri !== blockedUri),
|
||||
};
|
||||
}
|
||||
|
||||
case BLOCK_LEVEL.ADMIN: {
|
||||
const blockList = state.adminBlockList || [];
|
||||
delete unBlockingByUri[blockedUri];
|
||||
return {
|
||||
...state,
|
||||
unBlockingByUri,
|
||||
adminBlockList: blockList.slice().filter((uri) => uri !== blockedUri),
|
||||
};
|
||||
}
|
||||
|
||||
case BLOCK_LEVEL.MODERATOR: {
|
||||
const blockList = state.moderatorBlockList || [];
|
||||
const newBlockList = blockList.slice();
|
||||
const togglingMap = Object.assign({}, state.togglingForDelegatorMap);
|
||||
|
||||
const moderatorBlockListDelegatorsMap = Object.assign({}, state.moderatorBlockListDelegatorsMap);
|
||||
const delegatorUrisForBlockedUri = moderatorBlockListDelegatorsMap[blockedUri];
|
||||
if (delegatorUrisForBlockedUri) {
|
||||
const index = delegatorUrisForBlockedUri.indexOf(creatorUri);
|
||||
if (index > -1) {
|
||||
// Remove from delegators list
|
||||
delegatorUrisForBlockedUri.splice(index, 1);
|
||||
|
||||
// // Remove blocked entry if it was removed for all delegators
|
||||
// if (delegatorUrisForBlockedUri.length === 0) {
|
||||
// delete moderatorBlockListDelegatorsMap[blockedUri];
|
||||
// newBlockList = newBlockList.filter((uri) => uri !== blockedUri);
|
||||
// }
|
||||
|
||||
// Remove from "toggling" flag
|
||||
const togglingDelegatorsForBlockedUri = togglingMap[blockedUri];
|
||||
if (togglingDelegatorsForBlockedUri) {
|
||||
togglingMap[blockedUri] = togglingDelegatorsForBlockedUri.filter((x) => x !== creatorUri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
moderatorBlockList: newBlockList,
|
||||
togglingForDelegatorMap: togglingMap,
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
[ACTIONS.COMMENT_FETCH_MODERATION_DELEGATES_STARTED]: (state: CommentsState, action: any) => ({
|
||||
...state,
|
||||
fetchingModerationDelegates: true,
|
||||
}),
|
||||
[ACTIONS.COMMENT_FETCH_MODERATION_DELEGATES_FAILED]: (state: CommentsState, action: any) => ({
|
||||
...state,
|
||||
fetchingModerationDelegates: false,
|
||||
}),
|
||||
[ACTIONS.COMMENT_FETCH_MODERATION_DELEGATES_COMPLETED]: (state: CommentsState, action: any) => {
|
||||
const moderationDelegatesById = Object.assign({}, state.moderationDelegatesById);
|
||||
if (action.data.delegates) {
|
||||
moderationDelegatesById[action.data.id] = action.data.delegates.map((delegate) => {
|
||||
return {
|
||||
channelId: delegate.channel_id,
|
||||
channelName: delegate.channel_name,
|
||||
};
|
||||
});
|
||||
} else {
|
||||
moderationDelegatesById[action.data.id] = [];
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
fetchingModerationDelegates: false,
|
||||
moderationDelegatesById: moderationDelegatesById,
|
||||
};
|
||||
},
|
||||
|
||||
[ACTIONS.COMMENT_MODERATION_AM_I_LIST_STARTED]: (state: CommentsState, action: any) => ({
|
||||
...state,
|
||||
fetchingModerationDelegators: true,
|
||||
}),
|
||||
|
||||
[ACTIONS.COMMENT_MODERATION_AM_I_LIST_FAILED]: (state: CommentsState, action: any) => ({
|
||||
...state,
|
||||
fetchingModerationDelegators: true,
|
||||
}),
|
||||
|
||||
[ACTIONS.COMMENT_MODERATION_AM_I_LIST_COMPLETED]: (state: CommentsState, action: any) => {
|
||||
return {
|
||||
...state,
|
||||
fetchingModerationDelegators: true,
|
||||
moderationDelegatorsById: action.data,
|
||||
};
|
||||
},
|
||||
|
||||
|
|
|
@ -16,9 +16,24 @@ export const selectCommentsDisabledChannelIds = createSelector(
|
|||
(state) => state.commentsDisabledChannelIds
|
||||
);
|
||||
export const selectOthersReactsById = createSelector(selectState, (state) => state.othersReactsByCommentId);
|
||||
|
||||
export const selectModerationBlockList = createSelector(selectState, (state) =>
|
||||
state.moderationBlockList ? state.moderationBlockList.reverse() : []
|
||||
);
|
||||
export const selectAdminBlockList = createSelector(selectState, (state) =>
|
||||
state.adminBlockList ? state.adminBlockList.reverse() : []
|
||||
);
|
||||
export const selectModeratorBlockList = createSelector(selectState, (state) =>
|
||||
state.moderatorBlockList ? state.moderatorBlockList.reverse() : []
|
||||
);
|
||||
|
||||
export const selectModeratorBlockListDelegatorsMap = createSelector(
|
||||
selectState,
|
||||
(state) => state.moderatorBlockListDelegatorsMap
|
||||
);
|
||||
|
||||
export const selectTogglingForDelegatorMap = createSelector(selectState, (state) => state.togglingForDelegatorMap);
|
||||
|
||||
export const selectBlockingByUri = createSelector(selectState, (state) => state.blockingByUri);
|
||||
export const selectUnBlockingByUri = createSelector(selectState, (state) => state.unBlockingByUri);
|
||||
export const selectFetchingModerationBlockList = createSelector(
|
||||
|
@ -26,6 +41,32 @@ export const selectFetchingModerationBlockList = createSelector(
|
|||
(state) => state.fetchingModerationBlockList
|
||||
);
|
||||
|
||||
export const selectModerationDelegatesById = createSelector(selectState, (state) => state.moderationDelegatesById);
|
||||
export const selectIsFetchingModerationDelegates = createSelector(
|
||||
selectState,
|
||||
(state) => state.fetchingModerationDelegates
|
||||
);
|
||||
|
||||
export const selectModerationDelegatorsById = createSelector(selectState, (state) => state.moderationDelegatorsById);
|
||||
export const selectIsFetchingModerationDelegators = createSelector(
|
||||
selectState,
|
||||
(state) => state.fetchingModerationDelegators
|
||||
);
|
||||
|
||||
export const selectHasAdminChannel = createSelector(selectState, (state) => {
|
||||
const myChannelIds = Object.keys(state.moderationDelegatorsById);
|
||||
for (let i = 0; i < myChannelIds.length; ++i) {
|
||||
const id = myChannelIds[i];
|
||||
if (state.moderationDelegatorsById[id] && state.moderationDelegatorsById[id].global) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
/// Lint doesn't like this:
|
||||
// return Object.values(state.moderationDelegatorsById).some((x) => x.global);
|
||||
});
|
||||
|
||||
export const selectCommentsByClaimId = createSelector(selectState, selectCommentsById, (state, byId) => {
|
||||
const byClaimId = state.byId || {};
|
||||
const comments = {};
|
||||
|
@ -298,6 +339,7 @@ export const makeSelectTotalCommentsCountForUri = (uri: string) =>
|
|||
return comments ? comments.length : 0;
|
||||
});
|
||||
|
||||
// Personal list
|
||||
export const makeSelectChannelIsBlocked = (uri: string) =>
|
||||
createSelector(selectModerationBlockList, (blockedChannelUris) => {
|
||||
if (!blockedChannelUris || !blockedChannelUris) {
|
||||
|
@ -307,6 +349,27 @@ export const makeSelectChannelIsBlocked = (uri: string) =>
|
|||
return blockedChannelUris.includes(uri);
|
||||
});
|
||||
|
||||
export const makeSelectChannelIsAdminBlocked = (uri: string) =>
|
||||
createSelector(selectAdminBlockList, (list) => {
|
||||
return list ? list.includes(uri) : false;
|
||||
});
|
||||
|
||||
export const makeSelectChannelIsModeratorBlocked = (uri: string) =>
|
||||
createSelector(selectModeratorBlockList, (list) => {
|
||||
return list ? list.includes(uri) : false;
|
||||
});
|
||||
|
||||
export const makeSelectChannelIsModeratorBlockedForCreator = (uri: string, creatorUri: string) =>
|
||||
createSelector(selectModeratorBlockList, selectModeratorBlockListDelegatorsMap, (blockList, delegatorsMap) => {
|
||||
if (!blockList) return false;
|
||||
return blockList.includes(uri) && delegatorsMap[uri] && delegatorsMap[uri].includes(creatorUri);
|
||||
});
|
||||
|
||||
export const makeSelectIsTogglingForDelegator = (uri: string, creatorUri: string) =>
|
||||
createSelector(selectTogglingForDelegatorMap, (togglingForDelegatorMap) => {
|
||||
return togglingForDelegatorMap[uri] && togglingForDelegatorMap[uri].includes(creatorUri);
|
||||
});
|
||||
|
||||
export const makeSelectUriIsBlockingOrUnBlocking = (uri: string) =>
|
||||
createSelector(selectBlockingByUri, selectUnBlockingByUri, (blockingByUri, unBlockingByUri) => {
|
||||
return blockingByUri[uri] || unBlockingByUri[uri];
|
||||
|
|
Loading…
Reference in a new issue