Limit channel-creation count from the UI (#886)

## Issue
534 prevent new channel creation over x channels

## Notes
Also handled from the API call (`doCreateChannel`) in case there are other UI components that create channels.
This commit is contained in:
infinite-persistence 2022-02-16 06:14:08 -08:00 committed by GitHub
parent 0774090bdc
commit 80d4d8c57c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 44 additions and 4 deletions

View file

@ -88,6 +88,7 @@ ENABLE_NO_SOURCE_CLAIMS=true
ENABLE_PREROLL_ADS=true ENABLE_PREROLL_ADS=true
CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS=4 CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS=4
CHANNEL_STAKED_LEVEL_LIVESTREAM=5 CHANNEL_STAKED_LEVEL_LIVESTREAM=5
CHANNEL_CREATION_LIMIT=5
WEB_PUBLISH_SIZE_LIMIT_GB=4 WEB_PUBLISH_SIZE_LIMIT_GB=4
LIGHTHOUSE_DEFAULT_TYPES=audio,video LIGHTHOUSE_DEFAULT_TYPES=audio,video

View file

@ -61,9 +61,10 @@ const config = {
ENABLE_PREROLL_ADS: process.env.ENABLE_PREROLL_ADS === 'true', ENABLE_PREROLL_ADS: process.env.ENABLE_PREROLL_ADS === 'true',
CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS: process.env.CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS, CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS: process.env.CHANNEL_STAKED_LEVEL_VIDEO_COMMENTS,
CHANNEL_STAKED_LEVEL_LIVESTREAM: process.env.CHANNEL_STAKED_LEVEL_LIVESTREAM, CHANNEL_STAKED_LEVEL_LIVESTREAM: process.env.CHANNEL_STAKED_LEVEL_LIVESTREAM,
CHANNEL_CREATION_LIMIT: process.env.CHANNEL_CREATION_LIMIT,
WEB_PUBLISH_SIZE_LIMIT_GB: process.env.WEB_PUBLISH_SIZE_LIMIT_GB, WEB_PUBLISH_SIZE_LIMIT_GB: process.env.WEB_PUBLISH_SIZE_LIMIT_GB,
LOADING_BAR_COLOR: process.env.LOADING_BAR_COLOR, LOADING_BAR_COLOR: process.env.LOADING_BAR_COLOR,
SIMPLE_SITE: process.env.SIMPLE_SITE === 'true', SIMPLE_SITE: process.env.SIMPLE_SITE === 'true',
SHOW_ADS: process.env.SHOW_ADS === 'true', SHOW_ADS: process.env.SHOW_ADS === 'true',
PINNED_URI_1: process.env.PINNED_URI_1, PINNED_URI_1: process.env.PINNED_URI_1,
PINNED_LABEL_1: process.env.PINNED_LABEL_1, PINNED_LABEL_1: process.env.PINNED_LABEL_1,

View file

@ -1413,6 +1413,7 @@
"Change to list layout": "Change to list layout", "Change to list layout": "Change to list layout",
"Change to tile layout": "Change to tile layout", "Change to tile layout": "Change to tile layout",
"Create a channel": "Create a channel", "Create a channel": "Create a channel",
"Sorry, you have exceeded the channel creation limit.": "Sorry, you have exceeded the channel creation limit.",
"Credit Details": "Credit Details", "Credit Details": "Credit Details",
"LBRY Credits": "LBRY Credits", "LBRY Credits": "LBRY Credits",
"Mark as read": "Mark as read", "Mark as read": "Mark as read",

View file

@ -3,11 +3,13 @@ import { connect } from 'react-redux';
import { selectBalance } from 'redux/selectors/wallet'; import { selectBalance } from 'redux/selectors/wallet';
import { selectUserVerifiedEmail } from 'redux/selectors/user'; import { selectUserVerifiedEmail } from 'redux/selectors/user';
import { doClaimRewardType } from 'redux/actions/rewards'; import { doClaimRewardType } from 'redux/actions/rewards';
import { selectIsMyChannelCountOverLimit } from 'redux/selectors/claims';
import ChannelNew from './view'; import ChannelNew from './view';
const select = (state) => ({ const select = (state) => ({
balance: selectBalance(state), balance: selectBalance(state),
isAuthenticated: selectUserVerifiedEmail(state), isAuthenticated: selectUserVerifiedEmail(state),
channelCountOverLimit: selectIsMyChannelCountOverLimit(state),
}); });
export default connect(select, (dispatch) => ({ export default connect(select, (dispatch) => ({

View file

@ -10,10 +10,11 @@ type Props = {
balance: number, balance: number,
claimConfirmEmailReward: () => void, claimConfirmEmailReward: () => void,
isAuthenticated: boolean, isAuthenticated: boolean,
channelCountOverLimit: boolean,
}; };
function ChannelNew(props: Props) { function ChannelNew(props: Props) {
const { balance, claimConfirmEmailReward, isAuthenticated } = props; const { balance, claimConfirmEmailReward, isAuthenticated, channelCountOverLimit } = props;
const { push, location } = useHistory(); const { push, location } = useHistory();
const urlSearchParams = new URLSearchParams(location.search); const urlSearchParams = new URLSearchParams(location.search);
const redirectUrl = urlSearchParams.get('redirect'); const redirectUrl = urlSearchParams.get('redirect');
@ -29,8 +30,12 @@ function ChannelNew(props: Props) {
<Page noSideNavigation noFooter backout={{ title: __('Create a channel'), backLabel: __('Cancel') }}> <Page noSideNavigation noFooter backout={{ title: __('Create a channel'), backLabel: __('Cancel') }}>
{emptyBalance && <YrblWalletEmpty />} {emptyBalance && <YrblWalletEmpty />}
{channelCountOverLimit && (
<div className="empty empty--centered">{__('Sorry, you have exceeded the channel creation limit.')}</div>
)}
<ChannelEdit <ChannelEdit
disabled={emptyBalance} disabled={emptyBalance || channelCountOverLimit}
onDone={() => { onDone={() => {
push(redirectUrl || `/$/${PAGES.CHANNELS}`); push(redirectUrl || `/$/${PAGES.CHANNELS}`);
}} }}

View file

@ -11,6 +11,7 @@ import {
selectMyChannelClaims, selectMyChannelClaims,
selectPendingClaimsById, selectPendingClaimsById,
selectClaimIsMine, selectClaimIsMine,
selectIsMyChannelCountOverLimit,
} from 'redux/selectors/claims'; } from 'redux/selectors/claims';
import { doFetchTxoPage } from 'redux/actions/wallet'; import { doFetchTxoPage } from 'redux/actions/wallet';
@ -390,11 +391,22 @@ export function doClearChannelErrors() {
} }
export function doCreateChannel(name: string, amount: number, optionalParams: any, onConfirm: any) { export function doCreateChannel(name: string, amount: number, optionalParams: any, onConfirm: any) {
return (dispatch: Dispatch) => { return (dispatch: Dispatch, getState: GetState) => {
const state = getState();
const channelCountOverLimit = selectIsMyChannelCountOverLimit(state);
dispatch({ dispatch({
type: ACTIONS.CREATE_CHANNEL_STARTED, type: ACTIONS.CREATE_CHANNEL_STARTED,
}); });
if (channelCountOverLimit) {
dispatch({
type: ACTIONS.CREATE_CHANNEL_FAILED,
data: 'Channel limit exceeded',
});
return;
}
const createParams: { const createParams: {
name: string, name: string,
bid: string, bid: string,

View file

@ -1,5 +1,7 @@
// @flow // @flow
import { CHANNEL_CREATION_LIMIT } from 'config';
import { normalizeURI, parseURI, isURIValid } from 'util/lbryURI'; import { normalizeURI, parseURI, isURIValid } from 'util/lbryURI';
import { selectYoutubeChannels } from 'redux/selectors/user';
import { selectSupportsByOutpoint } from 'redux/selectors/wallet'; import { selectSupportsByOutpoint } from 'redux/selectors/wallet';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { createCachedSelector } from 're-reselect'; import { createCachedSelector } from 're-reselect';
@ -773,3 +775,19 @@ export const selectUpdatingCollection = (state: State) => selectState(state).upd
export const selectUpdateCollectionError = (state: State) => selectState(state).updateCollectionError; export const selectUpdateCollectionError = (state: State) => selectState(state).updateCollectionError;
export const selectCreatingCollection = (state: State) => selectState(state).creatingCollection; export const selectCreatingCollection = (state: State) => selectState(state).creatingCollection;
export const selectCreateCollectionError = (state: State) => selectState(state).createCollectionError; export const selectCreateCollectionError = (state: State) => selectState(state).createCollectionError;
export const selectIsMyChannelCountOverLimit = createSelector(
selectMyChannelClaimIds,
selectYoutubeChannels,
(myClaimIds, ytChannels: ?Array<{ channel_claim_id: string }>) => {
if (myClaimIds) {
if (ytChannels && ytChannels.length > 0) {
// $FlowFixMe - null 'ytChannels' already excluded
const ids = myClaimIds.filter((id) => !ytChannels.some((yt) => yt.channel_claim_id === id));
return ids.length > CHANNEL_CREATION_LIMIT;
}
return myClaimIds.length > CHANNEL_CREATION_LIMIT;
}
return false;
}
);