doCheckPublishNameAvailability: case-insensitive version

## Issue
??

## Behavioral Changes
- Use `claim_search` instead of `claim_list` to retrieve all all own claims with the same name (case-insensitive).
  - Caveat: annonymous posts will be excluded.
- When a clash occurs, there is a possibility that we have multiple existing entries (e.g. "xxX", "xXx"). Since we don't know which one is best to fall back, I removed the "edit" button for this and replaced with a simpler text

## Code Note
- If not mistaken, the rest of the code still needs `selectMyClaimForUri` to be case-sensitive, so augment the selector to support both through an optional parameter.
This commit is contained in:
infinite-persistence 2022-04-18 10:52:40 +08:00 committed by Thomas Zarebczan
parent 4e9e55e32f
commit 3f805a6189
6 changed files with 50 additions and 20 deletions

View file

@ -1056,6 +1056,7 @@
"Edit existing claim instead": "Edit existing claim instead", "Edit existing claim instead": "Edit existing claim instead",
"You already have a claim at %existing_uri%. Publishing will update (overwrite) your existing claim.": "You already have a claim at %existing_uri%. Publishing will update (overwrite) your existing claim.", "You already have a claim at %existing_uri%. Publishing will update (overwrite) your existing claim.": "You already have a claim at %existing_uri%. Publishing will update (overwrite) your existing claim.",
"You already have a pending upload at %existing_uri%.": "You already have a pending upload at %existing_uri%.", "You already have a pending upload at %existing_uri%.": "You already have a pending upload at %existing_uri%.",
"You already have an upload with that name.": "You already have an upload with that name.",
"Save": "Save", "Save": "Save",
"Saved": "Saved", "Saved": "Saved",
"Saving...": "Saving...", "Saving...": "Saving...",

View file

@ -16,6 +16,7 @@ const select = (state) => ({
uri: makeSelectPublishFormValue('uri')(state), uri: makeSelectPublishFormValue('uri')(state),
isStillEditing: selectIsStillEditing(state), isStillEditing: selectIsStillEditing(state),
myClaimForUri: selectMyClaimForUri(state), myClaimForUri: selectMyClaimForUri(state),
myClaimForUriCaseInsensitive: selectMyClaimForUri(state, false),
currentUploads: selectCurrentUploads(state), currentUploads: selectCurrentUploads(state),
activeChannelClaim: selectActiveChannelClaim(state), activeChannelClaim: selectActiveChannelClaim(state),
incognito: selectIncognito(state), incognito: selectIncognito(state),

View file

@ -13,13 +13,14 @@ function isUriPendingUpload(uri: ?string, currentUploadNames: Array<string>) {
type Props = { type Props = {
uri: ?string, uri: ?string,
myClaimForUri: ?StreamClaim, myClaimForUri: ?StreamClaim,
myClaimForUriCaseInsensitive: ?StreamClaim,
currentUploads: { [key: string]: FileUploadItem }, currentUploads: { [key: string]: FileUploadItem },
isStillEditing: boolean, isStillEditing: boolean,
onEditMyClaim: (any, string) => void, onEditMyClaim: (any, string) => void,
}; };
function NameHelpText(props: Props) { function NameHelpText(props: Props) {
const { uri, myClaimForUri, currentUploads, onEditMyClaim, isStillEditing } = props; const { uri, myClaimForUri, myClaimForUriCaseInsensitive, currentUploads, onEditMyClaim, isStillEditing } = props;
const currentUploadNames: Array<string> = React.useMemo(() => { const currentUploadNames: Array<string> = React.useMemo(() => {
// $FlowFixMe - unable to resolve mixed // $FlowFixMe - unable to resolve mixed
@ -67,6 +68,8 @@ function NameHelpText(props: Props) {
/> />
</React.Fragment> </React.Fragment>
); );
} else if (uri && myClaimForUriCaseInsensitive) {
nameHelpText = <div className="error__text">{__('You already have an upload with that name.')}</div>;
} }
return ( return (

View file

@ -11,6 +11,7 @@ type Props = {
uri: string, uri: string,
isStillEditing: boolean, isStillEditing: boolean,
myClaimForUri: ?StreamClaim, myClaimForUri: ?StreamClaim,
myClaimForUriCaseInsensitive: ?StreamClaim,
amountNeededForTakeover: number, amountNeededForTakeover: number,
prepareEdit: ({}, string) => void, prepareEdit: ({}, string) => void,
updatePublishForm: ({}) => void, updatePublishForm: ({}) => void,
@ -25,6 +26,7 @@ function PublishName(props: Props) {
uri, uri,
isStillEditing, isStillEditing,
myClaimForUri, myClaimForUri,
myClaimForUriCaseInsensitive,
prepareEdit, prepareEdit,
updatePublishForm, updatePublishForm,
activeChannelClaim, activeChannelClaim,
@ -86,6 +88,7 @@ function PublishName(props: Props) {
uri={uri} uri={uri}
isStillEditing={isStillEditing} isStillEditing={isStillEditing}
myClaimForUri={myClaimForUri} myClaimForUri={myClaimForUri}
myClaimForUriCaseInsensitive={myClaimForUriCaseInsensitive}
currentUploads={currentUploads} currentUploads={currentUploads}
onEditMyClaim={editExistingClaim} onEditMyClaim={editExistingClaim}
/> />

View file

@ -13,6 +13,7 @@ import {
selectClaimIsMine, selectClaimIsMine,
selectIsMyChannelCountOverLimit, selectIsMyChannelCountOverLimit,
selectById, selectById,
selectMyChannelClaimIds,
} from 'redux/selectors/claims'; } from 'redux/selectors/claims';
import { doFetchTxoPage } from 'redux/actions/wallet'; import { doFetchTxoPage } from 'redux/actions/wallet';
@ -1001,25 +1002,32 @@ export function doCollectionPublishUpdate(
} }
export function doCheckPublishNameAvailability(name: string) { export function doCheckPublishNameAvailability(name: string) {
return (dispatch: Dispatch) => { return (dispatch: Dispatch, getState: GetState) => {
dispatch({ dispatch({
type: ACTIONS.CHECK_PUBLISH_NAME_STARTED, type: ACTIONS.CHECK_PUBLISH_NAME_STARTED,
}); });
return Lbry.claim_list({ name: name }).then((result) => { const state = getState();
const myChannelClaimIds = selectMyChannelClaimIds(state);
return dispatch(
doClaimSearch(
{
name,
channel_ids: myChannelClaimIds,
page: 1,
page_size: 50,
no_totals: true,
include_is_my_output: true,
},
{
useAutoPagination: true,
}
)
).then(() => {
dispatch({ dispatch({
type: ACTIONS.CHECK_PUBLISH_NAME_COMPLETED, type: ACTIONS.CHECK_PUBLISH_NAME_COMPLETED,
}); });
if (result.items.length) {
dispatch({
type: ACTIONS.FETCH_CLAIM_LIST_MINE_COMPLETED,
data: {
result,
resolve: false,
},
});
}
return !(result && result.items && result.items.length);
}); });
}; };
} }

View file

@ -1,4 +1,5 @@
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { createCachedSelector } from 're-reselect';
import { parseURI, buildURI } from 'util/lbryURI'; import { parseURI, buildURI } from 'util/lbryURI';
import { import {
selectClaimsById, selectClaimsById,
@ -51,26 +52,39 @@ export const selectPublishFormValues = createSelector(
export const makeSelectPublishFormValue = (item) => createSelector(selectState, (state) => state[item]); export const makeSelectPublishFormValue = (item) => createSelector(selectState, (state) => state[item]);
export const selectMyClaimForUri = createSelector( export const selectMyClaimForUri = createCachedSelector(
selectPublishFormValues, selectPublishFormValues,
selectIsStillEditing, selectIsStillEditing,
selectClaimsById, selectClaimsById,
selectMyClaimsWithoutChannels, selectMyClaimsWithoutChannels,
({ editingURI, uri }, isStillEditing, claimsById, myClaims) => { (state, caseSensitive) => caseSensitive,
const { channelName: contentName, streamName: claimName } = parseURI(uri); ({ editingURI, uri }, isStillEditing, claimsById, myClaims, caseSensitive = true) => {
let { channelName: contentName, streamName: claimName } = parseURI(uri);
const { streamClaimId: editClaimId } = parseURI(editingURI); const { streamClaimId: editClaimId } = parseURI(editingURI);
// If isStillEditing // If isStillEditing
// They clicked "edit" from the file page // They clicked "edit" from the file page
// They haven't changed the channel/name after clicking edit // They haven't changed the channel/name after clicking edit
// Get the claim so they can edit without re-uploading a new file // Get the claim so they can edit without re-uploading a new file
return isStillEditing if (isStillEditing) {
? claimsById[editClaimId] return claimsById[editClaimId];
: myClaims.find((claim) => } else {
if (caseSensitive) {
return myClaims.find((claim) =>
!contentName ? claim.name === claimName : claim.name === contentName || claim.name === claimName !contentName ? claim.name === claimName : claim.name === contentName || claim.name === claimName
); );
} else {
contentName = contentName ? contentName.toLowerCase() : contentName;
claimName = claimName ? claimName.toLowerCase() : claimName;
return myClaims.find((claim) => {
const n = claim && claim.name ? claim.name.toLowerCase() : null;
return !contentName ? n === claimName : n === contentName || n === claimName;
});
} }
); }
}
)((state, caseSensitive = true) => `selectMyClaimForUri-${caseSensitive ? '1' : '0'}`);
export const selectIsResolvingPublishUris = createSelector( export const selectIsResolvingPublishUris = createSelector(
selectState, selectState,