We won’t append a unique string to the filename if the settings are configured to do so (#41621)

* Create media library component

* Use media library component instead of the MediaUpload from the @wordpress/media-utils

* Remove UploadFilesMenuItemm from the DownloadsMenu until we solve the insecure file upload using the wp/v2/media endpoint

* Remove the @woocommerce/components/MediaUploader from downloads block until we solve the insecure file upload using the wp/v2/media endpoint

* Remove the FormFileUpload from EditDownloadsModal until we solve the insecure file upload using the wp/v2/media endpoint

* Add changelog file
This commit is contained in:
Maikel David Pérez Gómez 2023-11-22 11:53:34 -03:00 committed by GitHub
parent 633bf40f13
commit 5a513cc9a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 169 additions and 117 deletions

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
append a unique string to the filename if the settings are configured to do so

View File

@ -10,13 +10,11 @@ import { chevronDown, chevronUp } from '@wordpress/icons';
* Internal dependencies * Internal dependencies
*/ */
import { DownloadsMenuProps } from './types'; import { DownloadsMenuProps } from './types';
import { UploadFilesMenuItem } from '../upload-files-menu-item';
import { MediaLibraryMenuItem } from '../media-library-menu-item'; import { MediaLibraryMenuItem } from '../media-library-menu-item';
import { InsertUrlMenuItem } from '../insert-url-menu-item'; import { InsertUrlMenuItem } from '../insert-url-menu-item';
export function DownloadsMenu( { export function DownloadsMenu( {
allowedTypes, allowedTypes,
maxUploadFileSize,
onUploadSuccess, onUploadSuccess,
onUploadError, onUploadError,
}: DownloadsMenuProps ) { }: DownloadsMenuProps ) {
@ -38,16 +36,6 @@ export function DownloadsMenu( {
renderContent={ ( { onClose } ) => ( renderContent={ ( { onClose } ) => (
<div className="components-dropdown-menu__menu"> <div className="components-dropdown-menu__menu">
<MenuGroup> <MenuGroup>
<UploadFilesMenuItem
allowedTypes={ allowedTypes }
maxUploadFileSize={ maxUploadFileSize }
onUploadSuccess={ ( files ) => {
onUploadSuccess( files );
onClose();
} }
onUploadError={ onUploadError }
/>
<MediaLibraryMenuItem <MediaLibraryMenuItem
allowedTypes={ allowedTypes } allowedTypes={ allowedTypes }
onUploadSuccess={ ( files ) => { onUploadSuccess={ ( files ) => {

View File

@ -1,17 +1,14 @@
/** /**
* External dependencies * External dependencies
*/ */
import { ChangeEvent } from 'react';
import { __, sprintf } from '@wordpress/i18n'; import { __, sprintf } from '@wordpress/i18n';
import { createElement, useState } from '@wordpress/element'; import { createElement, useState } from '@wordpress/element';
import { trash } from '@wordpress/icons'; import { trash } from '@wordpress/icons';
import { useDispatch, useSelect } from '@wordpress/data'; import { useDispatch } from '@wordpress/data';
import { recordEvent } from '@woocommerce/tracks'; import { recordEvent } from '@woocommerce/tracks';
import { ImageGallery, ImageGalleryItem } from '@woocommerce/components'; import { ImageGallery, ImageGalleryItem } from '@woocommerce/components';
import { uploadMedia } from '@wordpress/media-utils';
import { import {
Button, Button,
FormFileUpload,
Modal, Modal,
BaseControl, BaseControl,
// @ts-expect-error `__experimentalInputControl` does exist. // @ts-expect-error `__experimentalInputControl` does exist.
@ -34,28 +31,14 @@ export interface Image {
export const EditDownloadsModal: React.FC< EditDownloadsModalProps > = ( { export const EditDownloadsModal: React.FC< EditDownloadsModalProps > = ( {
downloableItem, downloableItem,
maxUploadFileSize = 10000000,
onCancel, onCancel,
onChange, onChange,
onRemove, onRemove,
onSave, onSave,
onUploadSuccess,
onUploadError,
} ) => { } ) => {
const { createNotice } = useDispatch( 'core/notices' ); const { createNotice } = useDispatch( 'core/notices' );
const [ isCopingToClipboard, setIsCopingToClipboard ] = const [ isCopingToClipboard, setIsCopingToClipboard ] =
useState< boolean >( false ); useState< boolean >( false );
const [ isFileUploading, setIsFileUploading ] =
useState< boolean >( false );
const { allowedMimeTypes } = useSelect( ( select ) => {
const { getEditorSettings } = select( 'core/editor' );
return getEditorSettings();
} );
const allowedTypes = allowedMimeTypes
? Object.values( allowedMimeTypes )
: [];
const { id = 0, file = '', name = '' } = downloableItem; const { id = 0, file = '', name = '' } = downloableItem;
@ -96,21 +79,6 @@ export const EditDownloadsModal: React.FC< EditDownloadsModalProps > = ( {
setIsCopingToClipboard( false ); setIsCopingToClipboard( false );
} }
async function handleFormFileUploadChange(
event: ChangeEvent< HTMLInputElement >
) {
setIsFileUploading( true );
const filesList = event.currentTarget.files as FileList;
await uploadMedia( {
allowedTypes,
filesList,
maxUploadFileSize,
onFileChange: onUploadSuccess,
onError: onUploadError,
} );
setIsFileUploading( false );
}
return ( return (
<Modal <Modal
title={ sprintf( title={ sprintf(
@ -145,21 +113,10 @@ export const EditDownloadsModal: React.FC< EditDownloadsModalProps > = ( {
<DownloadsCustomImage /> <DownloadsCustomImage />
) } ) }
</ImageGallery> </ImageGallery>
<FormFileUpload
onChange={ handleFormFileUploadChange } <div className="components-form-file-upload">
render={ ( { openFileDialog } ) => ( <p>{ name }</p>
<div> </div>
<p>{ name }</p>
<Button
onClick={ openFileDialog }
isBusy={ isFileUploading }
disabled={ isFileUploading }
>
{ __( 'Replace', 'woocommerce' ) }
</Button>
</div>
) }
/>
</div> </div>
<BaseControl <BaseControl
id={ 'file-name-help' } id={ 'file-name-help' }

View File

@ -13,7 +13,7 @@ import {
import { closeSmall } from '@wordpress/icons'; import { closeSmall } from '@wordpress/icons';
import { MediaItem } from '@wordpress/media-utils'; import { MediaItem } from '@wordpress/media-utils';
import { useWooBlockProps } from '@woocommerce/block-templates'; import { useWooBlockProps } from '@woocommerce/block-templates';
import { ListItem, MediaUploader, Sortable } from '@woocommerce/components'; import { ListItem, Sortable } from '@woocommerce/components';
import { Product, ProductDownload } from '@woocommerce/data'; import { Product, ProductDownload } from '@woocommerce/data';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore No types for this exist yet. // @ts-ignore No types for this exist yet.
@ -24,7 +24,6 @@ import { useEntityProp } from '@wordpress/core-data';
* Internal dependencies * Internal dependencies
*/ */
import { UploadsBlockAttributes } from './types'; import { UploadsBlockAttributes } from './types';
import { UploadImage } from './upload-image';
import { DownloadsMenu } from './downloads-menu'; import { DownloadsMenu } from './downloads-menu';
import { ProductEditorBlockEditProps } from '../../../types'; import { ProductEditorBlockEditProps } from '../../../types';
import { import {
@ -250,50 +249,36 @@ export function Edit( {
</div> </div>
<div className="wp-block-woocommerce-product-downloads-field__body"> <div className="wp-block-woocommerce-product-downloads-field__body">
<MediaUploader { ! Boolean( downloads.length ) && (
label={ <div className="wp-block-woocommerce-product-downloads-field__drop-zone-content">
! Boolean( downloads.length ) ? ( <p className="wp-block-woocommerce-product-downloads-field__drop-zone-label">
<div className="wp-block-woocommerce-product-downloads-field__drop-zone-content"> { createInterpolateElement(
<UploadImage /> __(
<p className="wp-block-woocommerce-product-downloads-field__drop-zone-label"> 'Supported file types: <Types /> and more. <link>View all</link>',
{ createInterpolateElement( 'woocommerce'
__( ),
'Supported file types: <Types /> and more. <link>View all</link>', {
'woocommerce' Types: (
), <Fragment>
{ PNG, JPG, PDF, PPT, DOC, MP3, MP4
Types: ( </Fragment>
<Fragment> ),
PNG, JPG, PDF, PPT, DOC, link: (
MP3, MP4 // eslint-disable-next-line jsx-a11y/anchor-has-content
</Fragment> <a
), href="https://codex.wordpress.org/Uploading_Files"
link: ( target="_blank"
// eslint-disable-next-line jsx-a11y/anchor-has-content rel="noreferrer"
<a onClick={ ( event ) =>
href="https://codex.wordpress.org/Uploading_Files" event.stopPropagation()
target="_blank" }
rel="noreferrer" />
onClick={ ( event ) => ),
event.stopPropagation() }
} ) }
/> </p>
), </div>
} ) }
) }
</p>
</div>
) : (
''
)
}
buttonText=""
allowedMediaTypes={ allowedTypes }
multipleSelect={ 'add' }
onUpload={ handleFileUpload }
onFileUploadChange={ handleFileUpload }
onError={ handleUploadError }
/>
{ Boolean( downloads.length ) && ( { Boolean( downloads.length ) && (
<Sortable className="wp-block-woocommerce-product-downloads-field__table"> <Sortable className="wp-block-woocommerce-product-downloads-field__table">

View File

@ -1,17 +1,17 @@
/** /**
* External dependencies * External dependencies
*/ */
import { MenuItem } from '@wordpress/components'; import { MenuItem } from '@wordpress/components';
import { createElement, useEffect, useState } from '@wordpress/element'; import { createElement, useEffect, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n'; import { __ } from '@wordpress/i18n';
import { media } from '@wordpress/icons'; import { media } from '@wordpress/icons';
import { MediaItem, MediaUpload } from '@wordpress/media-utils'; import { MediaItem } from '@wordpress/media-utils';
/** /**
* Internal dependencies * Internal dependencies
*/ */
import { MediaLibraryMenuItemProps } from './types'; import { MediaLibraryMenuItemProps } from './types';
import { MediaLibrary } from '../media-library';
const MODAL_CLASS_NAME = const MODAL_CLASS_NAME =
'woocommerce-media-library-menu-item__upload_files_modal'; 'woocommerce-media-library-menu-item__upload_files_modal';
@ -39,8 +39,8 @@ export function MediaLibraryMenuItem( {
[ uploadFilesModalOpen ] [ uploadFilesModalOpen ]
); );
function handleMediaUploadSelect( value: unknown ) { function handleMediaUploadSelect( value: MediaItem[] ) {
onUploadSuccess( value as MediaItem[] ); onUploadSuccess( value );
} }
function uploadFilesClickHandler( openMediaUploadModal: () => void ) { function uploadFilesClickHandler( openMediaUploadModal: () => void ) {
@ -51,13 +51,16 @@ export function MediaLibraryMenuItem( {
} }
return ( return (
<MediaUpload <MediaLibrary
modalClass={ MODAL_CLASS_NAME } className={ MODAL_CLASS_NAME }
onSelect={ handleMediaUploadSelect }
allowedTypes={ allowedTypes } allowedTypes={ allowedTypes }
// @ts-expect-error - TODO multiple also accepts string. multiple="add"
multiple={ 'add' } uploaderParams={ {
render={ ( { open } ) => ( type: 'downloadable_product',
} }
onSelect={ handleMediaUploadSelect }
>
{ ( { open } ) => (
<MenuItem <MenuItem
icon={ media } icon={ media }
iconPosition="left" iconPosition="left"
@ -67,6 +70,6 @@ export function MediaLibraryMenuItem( {
{ __( 'Media Library', 'woocommerce' ) } { __( 'Media Library', 'woocommerce' ) }
</MenuItem> </MenuItem>
) } ) }
/> </MediaLibrary>
); );
} }

View File

@ -0,0 +1,2 @@
export * from './media-library';
export * from './types';

View File

@ -0,0 +1,94 @@
/**
* External dependencies
*/
import { useEffect, useMemo } from '@wordpress/element';
/**
* Internal dependencies
*/
import { MediaLibraryProps } from './types';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
declare const wp: any;
export function MediaLibrary( {
allowedTypes,
modalTitle,
modalButtonText,
multiple,
className,
uploaderParams,
children,
onSelect,
}: MediaLibraryProps ) {
const mediaLibraryModal = useMemo(
function createMediaLibraryModal() {
const media = wp.media( {
title: modalTitle,
library: {
type: allowedTypes,
},
button: {
text: modalButtonText,
},
multiple,
states: [
new wp.media.controller.Library( {
title: modalTitle,
library: wp.media.query(),
multiple,
priority: 20,
filterable: 'all',
} ),
],
} );
return media;
},
[ allowedTypes, modalTitle, modalButtonText, multiple ]
);
useEffect(
function initializeEvents() {
function handleSelect() {
const mediaItems = mediaLibraryModal
.state()
.get( 'selection' )
.toJSON();
onSelect( mediaItems );
}
function handleReady() {
mediaLibraryModal.uploader.options.uploader.params =
uploaderParams;
}
mediaLibraryModal.on( 'select', handleSelect );
mediaLibraryModal.on( 'ready', handleReady );
return function unmountMediaLibraryModal() {
mediaLibraryModal.off( 'select', handleSelect );
mediaLibraryModal.off( 'ready', handleReady );
};
},
[ mediaLibraryModal, uploaderParams, onSelect ]
);
useEffect(
() =>
function unmountMediaLibraryModal() {
mediaLibraryModal.remove();
},
[ mediaLibraryModal ]
);
function openMediaLibraryModal() {
mediaLibraryModal.$el.addClass( className );
mediaLibraryModal.open();
}
return children( {
open: openMediaLibraryModal,
} );
}

View File

@ -0,0 +1,19 @@
/**
* External dependencies
*/
import { MediaItem } from '@wordpress/media-utils';
export type ChildrenProps = {
open(): void;
};
export type MediaLibraryProps = {
allowedTypes?: string[];
modalTitle?: string;
modalButtonText?: string;
multiple?: boolean | 'add';
className?: string;
uploaderParams?: Record< string, string >;
children( props: ChildrenProps ): JSX.Element;
onSelect( selection: MediaItem[] ): void;
};