@strapi/upload 5.37.0 → 5.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/ai/components/AIAssetCard.js.map +1 -1
- package/dist/admin/ai/components/AIAssetCard.mjs +1 -1
- package/dist/admin/ai/components/AIAssetCard.mjs.map +1 -1
- package/dist/admin/ai/components/AIUploadModal.js.map +1 -1
- package/dist/admin/ai/components/AIUploadModal.mjs +1 -1
- package/dist/admin/ai/components/AIUploadModal.mjs.map +1 -1
- package/dist/admin/components/AssetCard/AssetCard.js.map +1 -1
- package/dist/admin/components/AssetCard/AssetCard.mjs.map +1 -1
- package/dist/admin/components/AssetCard/AssetCardBase.js.map +1 -1
- package/dist/admin/components/AssetCard/AssetCardBase.mjs.map +1 -1
- package/dist/admin/components/AssetCard/AudioAssetCard.js.map +1 -1
- package/dist/admin/components/AssetCard/AudioAssetCard.mjs.map +1 -1
- package/dist/admin/components/AssetCard/AudioPreview.js.map +1 -1
- package/dist/admin/components/AssetCard/AudioPreview.mjs.map +1 -1
- package/dist/admin/components/AssetCard/DocAssetCard.js.map +1 -1
- package/dist/admin/components/AssetCard/DocAssetCard.mjs.map +1 -1
- package/dist/admin/components/AssetCard/ImageAssetCard.js.map +1 -1
- package/dist/admin/components/AssetCard/ImageAssetCard.mjs.map +1 -1
- package/dist/admin/components/AssetCard/UploadingAssetCard.js.map +1 -1
- package/dist/admin/components/AssetCard/UploadingAssetCard.mjs.map +1 -1
- package/dist/admin/components/AssetCard/VideoAssetCard.js.map +1 -1
- package/dist/admin/components/AssetCard/VideoAssetCard.mjs.map +1 -1
- package/dist/admin/components/AssetCard/VideoPreview.js.map +1 -1
- package/dist/admin/components/AssetCard/VideoPreview.mjs.map +1 -1
- package/dist/admin/components/AssetDialog/AssetDialog.js.map +1 -1
- package/dist/admin/components/AssetDialog/AssetDialog.mjs.map +1 -1
- package/dist/admin/components/AssetDialog/BrowseStep/BrowseStep.js +1 -1
- package/dist/admin/components/AssetDialog/BrowseStep/BrowseStep.js.map +1 -1
- package/dist/admin/components/AssetDialog/BrowseStep/BrowseStep.mjs +1 -1
- package/dist/admin/components/AssetDialog/BrowseStep/BrowseStep.mjs.map +1 -1
- package/dist/admin/components/AssetDialog/BrowseStep/Filters.js.map +1 -1
- package/dist/admin/components/AssetDialog/BrowseStep/Filters.mjs.map +1 -1
- package/dist/admin/components/AssetDialog/BrowseStep/PageSize.js.map +1 -1
- package/dist/admin/components/AssetDialog/BrowseStep/PageSize.mjs.map +1 -1
- package/dist/admin/components/AssetDialog/BrowseStep/PaginationFooter/Pagination.js.map +1 -1
- package/dist/admin/components/AssetDialog/BrowseStep/PaginationFooter/Pagination.mjs.map +1 -1
- package/dist/admin/components/AssetDialog/BrowseStep/PaginationFooter/PaginationFooter.js.map +1 -1
- package/dist/admin/components/AssetDialog/BrowseStep/PaginationFooter/PaginationFooter.mjs.map +1 -1
- package/dist/admin/components/AssetDialog/BrowseStep/SearchAsset/SearchAsset.js.map +1 -1
- package/dist/admin/components/AssetDialog/BrowseStep/SearchAsset/SearchAsset.mjs.map +1 -1
- package/dist/admin/components/AssetDialog/BrowseStep/utils/isSelectable.js.map +1 -1
- package/dist/admin/components/AssetDialog/BrowseStep/utils/isSelectable.mjs.map +1 -1
- package/dist/admin/components/AssetDialog/DialogFooter.js.map +1 -1
- package/dist/admin/components/AssetDialog/DialogFooter.mjs.map +1 -1
- package/dist/admin/components/AssetDialog/SelectedStep/SelectedStep.js.map +1 -1
- package/dist/admin/components/AssetDialog/SelectedStep/SelectedStep.mjs.map +1 -1
- package/dist/admin/components/AssetGridList/AssetGridList.js.map +1 -1
- package/dist/admin/components/AssetGridList/AssetGridList.mjs.map +1 -1
- package/dist/admin/components/AssetGridList/Draggable.js.map +1 -1
- package/dist/admin/components/AssetGridList/Draggable.mjs.map +1 -1
- package/dist/admin/components/Breadcrumbs/Breadcrumbs.js.map +1 -1
- package/dist/admin/components/Breadcrumbs/Breadcrumbs.mjs.map +1 -1
- package/dist/admin/components/Breadcrumbs/CrumbSimpleMenuAsync.js.map +1 -1
- package/dist/admin/components/Breadcrumbs/CrumbSimpleMenuAsync.mjs.map +1 -1
- package/dist/admin/components/BulkMoveDialog/BulkMoveDialog.js.map +1 -1
- package/dist/admin/components/BulkMoveDialog/BulkMoveDialog.mjs.map +1 -1
- package/dist/admin/components/ContextInfo/ContextInfo.js.map +1 -1
- package/dist/admin/components/ContextInfo/ContextInfo.mjs.map +1 -1
- package/dist/admin/components/CopyLinkButton/CopyLinkButton.js.map +1 -1
- package/dist/admin/components/CopyLinkButton/CopyLinkButton.mjs.map +1 -1
- package/dist/admin/components/EditAssetDialog/DialogHeader.js.map +1 -1
- package/dist/admin/components/EditAssetDialog/DialogHeader.mjs.map +1 -1
- package/dist/admin/components/EditAssetDialog/EditAssetContent.js.map +1 -1
- package/dist/admin/components/EditAssetDialog/EditAssetContent.mjs.map +1 -1
- package/dist/admin/components/EditAssetDialog/PreviewBox/AssetPreview.js.map +1 -1
- package/dist/admin/components/EditAssetDialog/PreviewBox/AssetPreview.mjs.map +1 -1
- package/dist/admin/components/EditAssetDialog/PreviewBox/CroppingActions.js.map +1 -1
- package/dist/admin/components/EditAssetDialog/PreviewBox/CroppingActions.mjs.map +1 -1
- package/dist/admin/components/EditAssetDialog/PreviewBox/FocalPointActions.js.map +1 -1
- package/dist/admin/components/EditAssetDialog/PreviewBox/FocalPointActions.mjs.map +1 -1
- package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewBox.js +1 -4
- package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewBox.js.map +1 -1
- package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewBox.mjs +1 -4
- package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewBox.mjs.map +1 -1
- package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewComponents.js.map +1 -1
- package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewComponents.mjs.map +1 -1
- package/dist/admin/components/EditAssetDialog/RemoveAssetDialog.js.map +1 -1
- package/dist/admin/components/EditAssetDialog/RemoveAssetDialog.mjs.map +1 -1
- package/dist/admin/components/EditAssetDialog/ReplaceMediaButton.js.map +1 -1
- package/dist/admin/components/EditAssetDialog/ReplaceMediaButton.mjs.map +1 -1
- package/dist/admin/components/EditFolderDialog/EditFolderDialog.js.map +1 -1
- package/dist/admin/components/EditFolderDialog/EditFolderDialog.mjs.map +1 -1
- package/dist/admin/components/EditFolderDialog/ModalHeader/ModalHeader.js.map +1 -1
- package/dist/admin/components/EditFolderDialog/ModalHeader/ModalHeader.mjs.map +1 -1
- package/dist/admin/components/EditFolderDialog/RemoveFolderDialog.js.map +1 -1
- package/dist/admin/components/EditFolderDialog/RemoveFolderDialog.mjs.map +1 -1
- package/dist/admin/components/EmptyAssets/EmptyAssetGrid.js.map +1 -1
- package/dist/admin/components/EmptyAssets/EmptyAssetGrid.mjs.map +1 -1
- package/dist/admin/components/EmptyAssets/EmptyAssets.js.map +1 -1
- package/dist/admin/components/EmptyAssets/EmptyAssets.mjs.map +1 -1
- package/dist/admin/components/FilterList/FilterList.js.map +1 -1
- package/dist/admin/components/FilterList/FilterList.mjs.map +1 -1
- package/dist/admin/components/FilterList/FilterTag.js.map +1 -1
- package/dist/admin/components/FilterList/FilterTag.mjs.map +1 -1
- package/dist/admin/components/FilterPopover/FilterPopover.js.map +1 -1
- package/dist/admin/components/FilterPopover/FilterPopover.mjs.map +1 -1
- package/dist/admin/components/FilterPopover/FilterValueInput.js.map +1 -1
- package/dist/admin/components/FilterPopover/FilterValueInput.mjs.map +1 -1
- package/dist/admin/components/FilterPopover/utils/getFilterList.js.map +1 -1
- package/dist/admin/components/FilterPopover/utils/getFilterList.mjs.map +1 -1
- package/dist/admin/components/FolderCard/FolderCard/FolderCard.js.map +1 -1
- package/dist/admin/components/FolderCard/FolderCard/FolderCard.mjs.map +1 -1
- package/dist/admin/components/FolderCard/FolderCardBody/FolderCardBody.js.map +1 -1
- package/dist/admin/components/FolderCard/FolderCardBody/FolderCardBody.mjs.map +1 -1
- package/dist/admin/components/FolderCard/FolderCardBodyAction/FolderCardBodyAction.js.map +1 -1
- package/dist/admin/components/FolderCard/FolderCardBodyAction/FolderCardBodyAction.mjs.map +1 -1
- package/dist/admin/components/FolderCard/FolderCardCheckbox/FolderCardCheckbox.js.map +1 -1
- package/dist/admin/components/FolderCard/FolderCardCheckbox/FolderCardCheckbox.mjs.map +1 -1
- package/dist/admin/components/FolderCard/contexts/FolderCard.js.map +1 -1
- package/dist/admin/components/FolderCard/contexts/FolderCard.mjs.map +1 -1
- package/dist/admin/components/FolderGridList/FolderGridList.js.map +1 -1
- package/dist/admin/components/FolderGridList/FolderGridList.mjs.map +1 -1
- package/dist/admin/components/MediaLibraryDialog/MediaLibraryDialog.js.map +1 -1
- package/dist/admin/components/MediaLibraryDialog/MediaLibraryDialog.mjs.map +1 -1
- package/dist/admin/components/MediaLibraryInput/Carousel/CarouselAsset.js.map +1 -1
- package/dist/admin/components/MediaLibraryInput/Carousel/CarouselAsset.mjs.map +1 -1
- package/dist/admin/components/MediaLibraryInput/Carousel/CarouselAssetActions.js.map +1 -1
- package/dist/admin/components/MediaLibraryInput/Carousel/CarouselAssetActions.mjs.map +1 -1
- package/dist/admin/components/MediaLibraryInput/Carousel/CarouselAssets.js.map +1 -1
- package/dist/admin/components/MediaLibraryInput/Carousel/CarouselAssets.mjs.map +1 -1
- package/dist/admin/components/MediaLibraryInput/Carousel/EmptyStateAsset.js.map +1 -1
- package/dist/admin/components/MediaLibraryInput/Carousel/EmptyStateAsset.mjs.map +1 -1
- package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.js.map +1 -1
- package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.mjs.map +1 -1
- package/dist/admin/components/SelectTree/Option.js.map +1 -1
- package/dist/admin/components/SelectTree/Option.mjs.map +1 -1
- package/dist/admin/components/SelectTree/SelectTree.js.map +1 -1
- package/dist/admin/components/SelectTree/SelectTree.mjs +1 -1
- package/dist/admin/components/SelectTree/SelectTree.mjs.map +1 -1
- package/dist/admin/components/SelectTree/utils/flattenTree.js.map +1 -1
- package/dist/admin/components/SelectTree/utils/flattenTree.mjs.map +1 -1
- package/dist/admin/components/SelectTree/utils/getOpenValues.js.map +1 -1
- package/dist/admin/components/SelectTree/utils/getOpenValues.mjs.map +1 -1
- package/dist/admin/components/SelectTree/utils/getValuesToClose.js.map +1 -1
- package/dist/admin/components/SelectTree/utils/getValuesToClose.mjs.map +1 -1
- package/dist/admin/components/SortPicker/SortPicker.js.map +1 -1
- package/dist/admin/components/SortPicker/SortPicker.mjs.map +1 -1
- package/dist/admin/components/TableList/CellContent.js.map +1 -1
- package/dist/admin/components/TableList/CellContent.mjs.map +1 -1
- package/dist/admin/components/TableList/PreviewCell.js.map +1 -1
- package/dist/admin/components/TableList/PreviewCell.mjs +1 -1
- package/dist/admin/components/TableList/PreviewCell.mjs.map +1 -1
- package/dist/admin/components/TableList/TableList.js.map +1 -1
- package/dist/admin/components/TableList/TableList.mjs +1 -1
- package/dist/admin/components/TableList/TableList.mjs.map +1 -1
- package/dist/admin/components/TableList/TableRows.js.map +1 -1
- package/dist/admin/components/TableList/TableRows.mjs.map +1 -1
- package/dist/admin/components/UploadAssetDialog/AddAssetStep/AddAssetStep.js.map +1 -1
- package/dist/admin/components/UploadAssetDialog/AddAssetStep/AddAssetStep.mjs.map +1 -1
- package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromComputerForm.js.map +1 -1
- package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromComputerForm.mjs.map +1 -1
- package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromUrlForm.js.map +1 -1
- package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromUrlForm.mjs.map +1 -1
- package/dist/admin/components/UploadAssetDialog/PendingAssetStep/PendingAssetStep.js.map +1 -1
- package/dist/admin/components/UploadAssetDialog/PendingAssetStep/PendingAssetStep.mjs.map +1 -1
- package/dist/admin/components/UploadAssetDialog/UploadAssetDialog.js.map +1 -1
- package/dist/admin/components/UploadAssetDialog/UploadAssetDialog.mjs.map +1 -1
- package/dist/admin/components/UploadProgress/UploadProgress.js.map +1 -1
- package/dist/admin/components/UploadProgress/UploadProgress.mjs.map +1 -1
- package/dist/admin/constants.js.map +1 -1
- package/dist/admin/constants.mjs.map +1 -1
- package/dist/admin/future/App.js.map +1 -1
- package/dist/admin/future/App.mjs.map +1 -1
- package/dist/admin/future/components/Drawer.js +189 -0
- package/dist/admin/future/components/Drawer.js.map +1 -0
- package/dist/admin/future/components/Drawer.mjs +166 -0
- package/dist/admin/future/components/Drawer.mjs.map +1 -0
- package/dist/admin/future/components/UploadProgressDialog.js +60 -101
- package/dist/admin/future/components/UploadProgressDialog.js.map +1 -1
- package/dist/admin/future/components/UploadProgressDialog.mjs +62 -84
- package/dist/admin/future/components/UploadProgressDialog.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/AssetsPage.js +155 -100
- package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -1
- package/dist/admin/future/pages/Assets/AssetsPage.mjs +160 -105
- package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js +406 -0
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs +384 -0
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.js +215 -0
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.mjs +194 -0
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/AssetsGrid.js +37 -8
- package/dist/admin/future/pages/Assets/components/AssetsGrid.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs +38 -9
- package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsTable.js +35 -5
- package/dist/admin/future/pages/Assets/components/AssetsTable.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsTable.mjs +37 -7
- package/dist/admin/future/pages/Assets/components/AssetsTable.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/CreateFolderDialog.js +143 -0
- package/dist/admin/future/pages/Assets/components/CreateFolderDialog.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/CreateFolderDialog.mjs +141 -0
- package/dist/admin/future/pages/Assets/components/CreateFolderDialog.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZone.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZone.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZoneContext.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZoneContext.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/ImportFromUrlDialog.js +127 -0
- package/dist/admin/future/pages/Assets/components/ImportFromUrlDialog.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/ImportFromUrlDialog.mjs +106 -0
- package/dist/admin/future/pages/Assets/components/ImportFromUrlDialog.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/constants.js.map +1 -1
- package/dist/admin/future/pages/Assets/constants.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useFolderInfo.js.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useFolderInfo.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useFolderNavigation.js.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useFolderNavigation.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.js.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.mjs.map +1 -1
- package/dist/admin/future/services/api.js +181 -97
- package/dist/admin/future/services/api.js.map +1 -1
- package/dist/admin/future/services/api.mjs +181 -98
- package/dist/admin/future/services/api.mjs.map +1 -1
- package/dist/admin/future/services/assets.js +14 -1
- package/dist/admin/future/services/assets.js.map +1 -1
- package/dist/admin/future/services/assets.mjs +14 -2
- package/dist/admin/future/services/assets.mjs.map +1 -1
- package/dist/admin/future/services/folders.js +16 -1
- package/dist/admin/future/services/folders.js.map +1 -1
- package/dist/admin/future/services/folders.mjs +16 -2
- package/dist/admin/future/services/folders.mjs.map +1 -1
- package/dist/admin/future/store/hooks.js.map +1 -1
- package/dist/admin/future/store/hooks.mjs.map +1 -1
- package/dist/admin/future/store/uploadProgress.js +7 -4
- package/dist/admin/future/store/uploadProgress.js.map +1 -1
- package/dist/admin/future/store/uploadProgress.mjs +7 -4
- package/dist/admin/future/store/uploadProgress.mjs.map +1 -1
- package/dist/admin/future/utils/files.js +105 -3
- package/dist/admin/future/utils/files.js.map +1 -1
- package/dist/admin/future/utils/files.mjs +104 -4
- package/dist/admin/future/utils/files.mjs.map +1 -1
- package/dist/admin/future/utils/getAssetIcon.js +3 -3
- package/dist/admin/future/utils/getAssetIcon.js.map +1 -1
- package/dist/admin/future/utils/getAssetIcon.mjs +4 -4
- package/dist/admin/future/utils/getAssetIcon.mjs.map +1 -1
- package/dist/admin/future/utils/translations.js.map +1 -1
- package/dist/admin/future/utils/translations.mjs.map +1 -1
- package/dist/admin/hooks/useAIMetadataJob.js.map +1 -1
- package/dist/admin/hooks/useAIMetadataJob.mjs.map +1 -1
- package/dist/admin/hooks/useAiAvailability.js.map +1 -1
- package/dist/admin/hooks/useAiAvailability.mjs.map +1 -1
- package/dist/admin/hooks/useAssets.js.map +1 -1
- package/dist/admin/hooks/useAssets.mjs.map +1 -1
- package/dist/admin/hooks/useBulkEdit.js.map +1 -1
- package/dist/admin/hooks/useBulkEdit.mjs.map +1 -1
- package/dist/admin/hooks/useBulkMove.js.map +1 -1
- package/dist/admin/hooks/useBulkMove.mjs.map +1 -1
- package/dist/admin/hooks/useBulkRemove.js.map +1 -1
- package/dist/admin/hooks/useBulkRemove.mjs.map +1 -1
- package/dist/admin/hooks/useConfig.js.map +1 -1
- package/dist/admin/hooks/useConfig.mjs.map +1 -1
- package/dist/admin/hooks/useCropImg.js.map +1 -1
- package/dist/admin/hooks/useCropImg.mjs.map +1 -1
- package/dist/admin/hooks/useEditAsset.js.map +1 -1
- package/dist/admin/hooks/useEditAsset.mjs.map +1 -1
- package/dist/admin/hooks/useEditFolder.js.map +1 -1
- package/dist/admin/hooks/useEditFolder.mjs.map +1 -1
- package/dist/admin/hooks/useFolder.js.map +1 -1
- package/dist/admin/hooks/useFolder.mjs.map +1 -1
- package/dist/admin/hooks/useFolderStructure.js.map +1 -1
- package/dist/admin/hooks/useFolderStructure.mjs.map +1 -1
- package/dist/admin/hooks/useFolders.js.map +1 -1
- package/dist/admin/hooks/useFolders.mjs.map +1 -1
- package/dist/admin/hooks/useMediaLibraryPermissions.js.map +1 -1
- package/dist/admin/hooks/useMediaLibraryPermissions.mjs.map +1 -1
- package/dist/admin/hooks/useModalQueryParams.js.map +1 -1
- package/dist/admin/hooks/useModalQueryParams.mjs.map +1 -1
- package/dist/admin/hooks/usePersistentState.js.map +1 -1
- package/dist/admin/hooks/usePersistentState.mjs.map +1 -1
- package/dist/admin/hooks/useRemoveAsset.js.map +1 -1
- package/dist/admin/hooks/useRemoveAsset.mjs.map +1 -1
- package/dist/admin/hooks/useSelectionState.js.map +1 -1
- package/dist/admin/hooks/useSelectionState.mjs.map +1 -1
- package/dist/admin/hooks/useSettings.js.map +1 -1
- package/dist/admin/hooks/useSettings.mjs.map +1 -1
- package/dist/admin/hooks/useTracking.js.map +1 -1
- package/dist/admin/hooks/useTracking.mjs.map +1 -1
- package/dist/admin/hooks/useUpload.js.map +1 -1
- package/dist/admin/hooks/useUpload.mjs.map +1 -1
- package/dist/admin/hooks/utils/renameKeys.js.map +1 -1
- package/dist/admin/hooks/utils/renameKeys.mjs.map +1 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs.map +1 -1
- package/dist/admin/package.json.js +1 -152
- package/dist/admin/package.json.js.map +1 -1
- package/dist/admin/package.json.mjs +2 -141
- package/dist/admin/package.json.mjs.map +1 -1
- package/dist/admin/pages/App/App.js.map +1 -1
- package/dist/admin/pages/App/App.mjs.map +1 -1
- package/dist/admin/pages/App/ConfigureTheView/ConfigureTheView.js.map +1 -1
- package/dist/admin/pages/App/ConfigureTheView/ConfigureTheView.mjs +3 -3
- package/dist/admin/pages/App/ConfigureTheView/ConfigureTheView.mjs.map +1 -1
- package/dist/admin/pages/App/ConfigureTheView/components/Settings.js.map +1 -1
- package/dist/admin/pages/App/ConfigureTheView/components/Settings.mjs.map +1 -1
- package/dist/admin/pages/App/ConfigureTheView/state/actionTypes.js.map +1 -1
- package/dist/admin/pages/App/ConfigureTheView/state/actionTypes.mjs.map +1 -1
- package/dist/admin/pages/App/ConfigureTheView/state/actions.js.map +1 -1
- package/dist/admin/pages/App/ConfigureTheView/state/actions.mjs.map +1 -1
- package/dist/admin/pages/App/ConfigureTheView/state/init.js.map +1 -1
- package/dist/admin/pages/App/ConfigureTheView/state/init.mjs.map +1 -1
- package/dist/admin/pages/App/ConfigureTheView/state/reducer.js.map +1 -1
- package/dist/admin/pages/App/ConfigureTheView/state/reducer.mjs +1 -1
- package/dist/admin/pages/App/ConfigureTheView/state/reducer.mjs.map +1 -1
- package/dist/admin/pages/App/MediaLibrary.js +1 -1
- package/dist/admin/pages/App/MediaLibrary.js.map +1 -1
- package/dist/admin/pages/App/MediaLibrary.mjs +2 -2
- package/dist/admin/pages/App/MediaLibrary.mjs.map +1 -1
- package/dist/admin/pages/App/components/BulkActions.js.map +1 -1
- package/dist/admin/pages/App/components/BulkActions.mjs.map +1 -1
- package/dist/admin/pages/App/components/BulkDeleteButton.js.map +1 -1
- package/dist/admin/pages/App/components/BulkDeleteButton.mjs.map +1 -1
- package/dist/admin/pages/App/components/BulkMoveButton.js.map +1 -1
- package/dist/admin/pages/App/components/BulkMoveButton.mjs.map +1 -1
- package/dist/admin/pages/App/components/EmptyOrNoPermissions.js.map +1 -1
- package/dist/admin/pages/App/components/EmptyOrNoPermissions.mjs.map +1 -1
- package/dist/admin/pages/App/components/Filters.js.map +1 -1
- package/dist/admin/pages/App/components/Filters.mjs.map +1 -1
- package/dist/admin/pages/App/components/Header.js.map +1 -1
- package/dist/admin/pages/App/components/Header.mjs +2 -2
- package/dist/admin/pages/App/components/Header.mjs.map +1 -1
- package/dist/admin/pages/SettingsPage/SettingsPage.js.map +1 -1
- package/dist/admin/pages/SettingsPage/SettingsPage.mjs.map +1 -1
- package/dist/admin/pages/SettingsPage/reducer.js.map +1 -1
- package/dist/admin/pages/SettingsPage/reducer.mjs.map +1 -1
- package/dist/admin/pluginId.js.map +1 -1
- package/dist/admin/pluginId.mjs.map +1 -1
- package/dist/admin/src/future/components/Drawer.d.ts +32 -0
- package/dist/admin/src/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.d.ts +8 -0
- package/dist/admin/src/future/pages/Assets/components/AssetDetails/AssetPreview.d.ts +6 -0
- package/dist/admin/src/future/pages/Assets/components/AssetsGrid.d.ts +2 -1
- package/dist/admin/src/future/pages/Assets/components/AssetsTable.d.ts +2 -1
- package/dist/admin/src/future/pages/Assets/components/CreateFolderDialog.d.ts +8 -0
- package/dist/admin/src/future/pages/Assets/components/ImportFromUrlDialog.d.ts +7 -0
- package/dist/admin/src/future/services/api.d.ts +10 -1
- package/dist/admin/src/future/services/assets.d.ts +2 -2
- package/dist/admin/src/future/services/folders.d.ts +1 -1
- package/dist/admin/src/future/store/uploadProgress.d.ts +1 -1
- package/dist/admin/src/future/utils/files.d.ts +70 -0
- package/dist/admin/translations/en.json.js +35 -3
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +35 -3
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/admin/translations/es.json.js +1 -1
- package/dist/admin/translations/es.json.mjs +1 -1
- package/dist/admin/utils/appendSearchParamsToUrl.js.map +1 -1
- package/dist/admin/utils/appendSearchParamsToUrl.mjs.map +1 -1
- package/dist/admin/utils/containsAssetFilter.js.map +1 -1
- package/dist/admin/utils/containsAssetFilter.mjs.map +1 -1
- package/dist/admin/utils/createAssetUrl.js.map +1 -1
- package/dist/admin/utils/createAssetUrl.mjs.map +1 -1
- package/dist/admin/utils/displayedFilters.js.map +1 -1
- package/dist/admin/utils/displayedFilters.mjs.map +1 -1
- package/dist/admin/utils/downloadFile.js.map +1 -1
- package/dist/admin/utils/downloadFile.mjs.map +1 -1
- package/dist/admin/utils/findRecursiveFolderByValue.js.map +1 -1
- package/dist/admin/utils/findRecursiveFolderByValue.mjs.map +1 -1
- package/dist/admin/utils/formatBytes.js.map +1 -1
- package/dist/admin/utils/formatBytes.mjs.map +1 -1
- package/dist/admin/utils/formatDuration.js.map +1 -1
- package/dist/admin/utils/formatDuration.mjs.map +1 -1
- package/dist/admin/utils/getAPIInnerErrors.js.map +1 -1
- package/dist/admin/utils/getAPIInnerErrors.mjs.map +1 -1
- package/dist/admin/utils/getAllowedFiles.js.map +1 -1
- package/dist/admin/utils/getAllowedFiles.mjs.map +1 -1
- package/dist/admin/utils/getBreadcrumbDataCM.js.map +1 -1
- package/dist/admin/utils/getBreadcrumbDataCM.mjs.map +1 -1
- package/dist/admin/utils/getBreadcrumbDataML.js.map +1 -1
- package/dist/admin/utils/getBreadcrumbDataML.mjs.map +1 -1
- package/dist/admin/utils/getFileExtension.js.map +1 -1
- package/dist/admin/utils/getFileExtension.mjs.map +1 -1
- package/dist/admin/utils/getFolderParents.js.map +1 -1
- package/dist/admin/utils/getFolderParents.mjs.map +1 -1
- package/dist/admin/utils/getFolderURL.js.map +1 -1
- package/dist/admin/utils/getFolderURL.mjs.map +1 -1
- package/dist/admin/utils/getTrad.js.map +1 -1
- package/dist/admin/utils/getTrad.mjs.map +1 -1
- package/dist/admin/utils/icons.js.map +1 -1
- package/dist/admin/utils/icons.mjs +1 -1
- package/dist/admin/utils/icons.mjs.map +1 -1
- package/dist/admin/utils/moveElement.js.map +1 -1
- package/dist/admin/utils/moveElement.mjs.map +1 -1
- package/dist/admin/utils/normalizeAPIError.js.map +1 -1
- package/dist/admin/utils/normalizeAPIError.mjs.map +1 -1
- package/dist/admin/utils/prefixFileUrlWithBackendUrl.js.map +1 -1
- package/dist/admin/utils/prefixFileUrlWithBackendUrl.mjs.map +1 -1
- package/dist/admin/utils/prefixPluginTranslations.js.map +1 -1
- package/dist/admin/utils/prefixPluginTranslations.mjs.map +1 -1
- package/dist/admin/utils/rawFileToAsset.js.map +1 -1
- package/dist/admin/utils/rawFileToAsset.mjs.map +1 -1
- package/dist/admin/utils/toSingularTypes.js.map +1 -1
- package/dist/admin/utils/toSingularTypes.mjs.map +1 -1
- package/dist/admin/utils/typeFromMime.js.map +1 -1
- package/dist/admin/utils/typeFromMime.mjs.map +1 -1
- package/dist/admin/utils/urlYupSchema.js.map +1 -1
- package/dist/admin/utils/urlYupSchema.mjs.map +1 -1
- package/dist/admin/utils/urlsToAssets.js.map +1 -1
- package/dist/admin/utils/urlsToAssets.mjs.map +1 -1
- package/dist/server/bootstrap.js.map +1 -1
- package/dist/server/bootstrap.mjs.map +1 -1
- package/dist/server/config.js.map +1 -1
- package/dist/server/config.mjs.map +1 -1
- package/dist/server/constants.js.map +1 -1
- package/dist/server/constants.mjs.map +1 -1
- package/dist/server/content-types/file.js.map +1 -1
- package/dist/server/content-types/file.mjs.map +1 -1
- package/dist/server/content-types/folder.js.map +1 -1
- package/dist/server/content-types/folder.mjs +1 -1
- package/dist/server/content-types/folder.mjs.map +1 -1
- package/dist/server/content-types/index.js.map +1 -1
- package/dist/server/content-types/index.mjs.map +1 -1
- package/dist/server/controllers/admin-file.js.map +1 -1
- package/dist/server/controllers/admin-file.mjs +1 -1
- package/dist/server/controllers/admin-file.mjs.map +1 -1
- package/dist/server/controllers/admin-folder-file.js.map +1 -1
- package/dist/server/controllers/admin-folder-file.mjs +2 -2
- package/dist/server/controllers/admin-folder-file.mjs.map +1 -1
- package/dist/server/controllers/admin-folder.js.map +1 -1
- package/dist/server/controllers/admin-folder.mjs +1 -1
- package/dist/server/controllers/admin-folder.mjs.map +1 -1
- package/dist/server/controllers/admin-settings.js.map +1 -1
- package/dist/server/controllers/admin-settings.mjs.map +1 -1
- package/dist/server/controllers/admin-upload.js +144 -0
- package/dist/server/controllers/admin-upload.js.map +1 -1
- package/dist/server/controllers/admin-upload.mjs +147 -3
- package/dist/server/controllers/admin-upload.mjs.map +1 -1
- package/dist/server/controllers/content-api.js.map +1 -1
- package/dist/server/controllers/content-api.mjs.map +1 -1
- package/dist/server/controllers/index.js.map +1 -1
- package/dist/server/controllers/index.mjs.map +1 -1
- package/dist/server/controllers/utils/find-entity-and-check-permissions.js.map +1 -1
- package/dist/server/controllers/utils/find-entity-and-check-permissions.mjs.map +1 -1
- package/dist/server/controllers/utils/folders.js.map +1 -1
- package/dist/server/controllers/utils/folders.mjs.map +1 -1
- package/dist/server/controllers/validation/admin/configureView.js.map +1 -1
- package/dist/server/controllers/validation/admin/configureView.mjs.map +1 -1
- package/dist/server/controllers/validation/admin/folder-file.js.map +1 -1
- package/dist/server/controllers/validation/admin/folder-file.mjs.map +1 -1
- package/dist/server/controllers/validation/admin/folder.js.map +1 -1
- package/dist/server/controllers/validation/admin/folder.mjs.map +1 -1
- package/dist/server/controllers/validation/admin/settings.js.map +1 -1
- package/dist/server/controllers/validation/admin/settings.mjs.map +1 -1
- package/dist/server/controllers/validation/admin/upload.js.map +1 -1
- package/dist/server/controllers/validation/admin/upload.mjs.map +1 -1
- package/dist/server/controllers/validation/admin/utils.js.map +1 -1
- package/dist/server/controllers/validation/admin/utils.mjs.map +1 -1
- package/dist/server/controllers/validation/content-api/upload.js.map +1 -1
- package/dist/server/controllers/validation/content-api/upload.mjs.map +1 -1
- package/dist/server/controllers/view-configuration.js.map +1 -1
- package/dist/server/controllers/view-configuration.mjs.map +1 -1
- package/dist/server/graphql.js.map +1 -1
- package/dist/server/graphql.mjs.map +1 -1
- package/dist/server/index.js +8 -8
- package/dist/server/middlewares/upload.js.map +1 -1
- package/dist/server/middlewares/upload.mjs.map +1 -1
- package/dist/server/models/ai-metadata-job.js.map +1 -1
- package/dist/server/models/ai-metadata-job.mjs.map +1 -1
- package/dist/server/register.js.map +1 -1
- package/dist/server/register.mjs.map +1 -1
- package/dist/server/routes/admin.js +10 -0
- package/dist/server/routes/admin.js.map +1 -1
- package/dist/server/routes/admin.mjs +10 -0
- package/dist/server/routes/admin.mjs.map +1 -1
- package/dist/server/routes/content-api.js.map +1 -1
- package/dist/server/routes/content-api.mjs.map +1 -1
- package/dist/server/routes/index.js.map +1 -1
- package/dist/server/routes/index.mjs +4 -4
- package/dist/server/routes/index.mjs.map +1 -1
- package/dist/server/routes/validation/upload.js.map +1 -1
- package/dist/server/routes/validation/upload.mjs.map +1 -1
- package/dist/server/routes/view-configuration.js.map +1 -1
- package/dist/server/routes/view-configuration.mjs.map +1 -1
- package/dist/server/services/ai-metadata-jobs.js.map +1 -1
- package/dist/server/services/ai-metadata-jobs.mjs.map +1 -1
- package/dist/server/services/ai-metadata.js.map +1 -1
- package/dist/server/services/ai-metadata.mjs.map +1 -1
- package/dist/server/services/api-upload-folder.js.map +1 -1
- package/dist/server/services/api-upload-folder.mjs.map +1 -1
- package/dist/server/services/extensions/index.js.map +1 -1
- package/dist/server/services/extensions/index.mjs.map +1 -1
- package/dist/server/services/extensions/utils.js.map +1 -1
- package/dist/server/services/extensions/utils.mjs.map +1 -1
- package/dist/server/services/file.js +120 -1
- package/dist/server/services/file.js.map +1 -1
- package/dist/server/services/file.mjs +122 -3
- package/dist/server/services/file.mjs.map +1 -1
- package/dist/server/services/folder.js.map +1 -1
- package/dist/server/services/folder.mjs +1 -1
- package/dist/server/services/folder.mjs.map +1 -1
- package/dist/server/services/image-manipulation.js.map +1 -1
- package/dist/server/services/image-manipulation.mjs +1 -1
- package/dist/server/services/image-manipulation.mjs.map +1 -1
- package/dist/server/services/index.js.map +1 -1
- package/dist/server/services/index.mjs.map +1 -1
- package/dist/server/services/metrics.js.map +1 -1
- package/dist/server/services/metrics.mjs.map +1 -1
- package/dist/server/services/provider.js.map +1 -1
- package/dist/server/services/provider.mjs.map +1 -1
- package/dist/server/services/upload.js.map +1 -1
- package/dist/server/services/upload.mjs +1 -1
- package/dist/server/services/upload.mjs.map +1 -1
- package/dist/server/services/weekly-metrics.js.map +1 -1
- package/dist/server/services/weekly-metrics.mjs.map +1 -1
- package/dist/server/src/controllers/admin-upload.d.ts +13 -0
- package/dist/server/src/controllers/admin-upload.d.ts.map +1 -1
- package/dist/server/src/controllers/index.d.ts +1 -0
- package/dist/server/src/controllers/index.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +2 -0
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/routes/admin.d.ts.map +1 -1
- package/dist/server/src/services/file.d.ts +15 -0
- package/dist/server/src/services/file.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +1 -0
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/utils/cron.js.map +1 -1
- package/dist/server/utils/cron.mjs.map +1 -1
- package/dist/server/utils/images.js.map +1 -1
- package/dist/server/utils/images.mjs.map +1 -1
- package/dist/server/utils/index.js.map +1 -1
- package/dist/server/utils/index.mjs.map +1 -1
- package/dist/server/utils/mime-validation.js.map +1 -1
- package/dist/server/utils/mime-validation.mjs.map +1 -1
- package/dist/shared/contracts/files.d.ts +11 -0
- package/dist/shared/contracts/files.d.ts.map +1 -1
- package/package.json +8 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-upload-folder.mjs","sources":["../../../server/src/services/api-upload-folder.ts"],"sourcesContent":["import { isNil, get } from 'lodash/fp';\nimport { getService } from '../utils';\nimport { FOLDER_MODEL_UID, API_UPLOAD_FOLDER_BASE_NAME } from '../constants';\n\nconst getStore = () => strapi.store({ type: 'plugin', name: 'upload', key: 'api-folder' });\n\nconst createApiUploadFolder = async () => {\n let name = API_UPLOAD_FOLDER_BASE_NAME;\n const folderService = getService('folder');\n\n let exists = true;\n let index = 1;\n while (exists) {\n exists = await folderService.exists({ name, parent: null });\n if (exists) {\n name = `${API_UPLOAD_FOLDER_BASE_NAME} (${index})`;\n index += 1;\n }\n }\n\n const folder = await folderService.create({ name });\n\n await getStore().set({ value: { id: folder.id } });\n\n return folder;\n};\n\nconst getAPIUploadFolder = async () => {\n const storeValue = await getStore().get({});\n const folderId = get('id', storeValue);\n\n const folder = folderId\n ? await strapi.db.query(FOLDER_MODEL_UID).findOne({ where: { id: folderId } })\n : null;\n\n return isNil(folder) ? createApiUploadFolder() : folder;\n};\n\nexport default {\n getAPIUploadFolder,\n};\n"],"names":["getStore","strapi","store","type","name","key","createApiUploadFolder","API_UPLOAD_FOLDER_BASE_NAME","folderService","getService","exists","index","parent","folder","create","set","value","id","getAPIUploadFolder","storeValue","get","folderId","db","query","FOLDER_MODEL_UID","findOne","where","isNil"],"mappings":";;;;AAIA,MAAMA,
|
|
1
|
+
{"version":3,"file":"api-upload-folder.mjs","sources":["../../../server/src/services/api-upload-folder.ts"],"sourcesContent":["import { isNil, get } from 'lodash/fp';\nimport { getService } from '../utils';\nimport { FOLDER_MODEL_UID, API_UPLOAD_FOLDER_BASE_NAME } from '../constants';\n\nconst getStore = () => strapi.store({ type: 'plugin', name: 'upload', key: 'api-folder' });\n\nconst createApiUploadFolder = async () => {\n let name = API_UPLOAD_FOLDER_BASE_NAME;\n const folderService = getService('folder');\n\n let exists = true;\n let index = 1;\n while (exists) {\n exists = await folderService.exists({ name, parent: null });\n if (exists) {\n name = `${API_UPLOAD_FOLDER_BASE_NAME} (${index})`;\n index += 1;\n }\n }\n\n const folder = await folderService.create({ name });\n\n await getStore().set({ value: { id: folder.id } });\n\n return folder;\n};\n\nconst getAPIUploadFolder = async () => {\n const storeValue = await getStore().get({});\n const folderId = get('id', storeValue);\n\n const folder = folderId\n ? await strapi.db.query(FOLDER_MODEL_UID).findOne({ where: { id: folderId } })\n : null;\n\n return isNil(folder) ? createApiUploadFolder() : folder;\n};\n\nexport default {\n getAPIUploadFolder,\n};\n"],"names":["getStore","strapi","store","type","name","key","createApiUploadFolder","API_UPLOAD_FOLDER_BASE_NAME","folderService","getService","exists","index","parent","folder","create","set","value","id","getAPIUploadFolder","storeValue","get","folderId","db","query","FOLDER_MODEL_UID","findOne","where","isNil"],"mappings":";;;;AAIA,MAAMA,QAAAA,GAAW,IAAMC,MAAAA,CAAOC,KAAK,CAAC;QAAEC,IAAAA,EAAM,QAAA;QAAUC,IAAAA,EAAM,QAAA;QAAUC,GAAAA,EAAK;AAAa,KAAA,CAAA;AAExF,MAAMC,qBAAAA,GAAwB,UAAA;AAC5B,IAAA,IAAIF,IAAAA,GAAOG,2BAAAA;AACX,IAAA,MAAMC,gBAAgBC,UAAAA,CAAW,QAAA,CAAA;AAEjC,IAAA,IAAIC,MAAAA,GAAS,IAAA;AACb,IAAA,IAAIC,KAAAA,GAAQ,CAAA;AACZ,IAAA,MAAOD,MAAAA,CAAQ;QACbA,MAAAA,GAAS,MAAMF,aAAAA,CAAcE,MAAM,CAAC;AAAEN,YAAAA,IAAAA;YAAMQ,MAAAA,EAAQ;AAAK,SAAA,CAAA;AACzD,QAAA,IAAIF,MAAAA,EAAQ;AACVN,YAAAA,IAAAA,GAAO,GAAGG,2BAAAA,CAA4B,EAAE,EAAEI,KAAAA,CAAM,CAAC,CAAC;YAClDA,KAAAA,IAAS,CAAA;AACX,QAAA;AACF,IAAA;AAEA,IAAA,MAAME,MAAAA,GAAS,MAAML,aAAAA,CAAcM,MAAM,CAAC;AAAEV,QAAAA;AAAK,KAAA,CAAA;IAEjD,MAAMJ,QAAAA,EAAAA,CAAWe,GAAG,CAAC;QAAEC,KAAAA,EAAO;AAAEC,YAAAA,EAAAA,EAAIJ,OAAOI;AAAG;AAAE,KAAA,CAAA;IAEhD,OAAOJ,MAAAA;AACT,CAAA;AAEA,MAAMK,kBAAAA,GAAqB,UAAA;AACzB,IAAA,MAAMC,UAAAA,GAAa,MAAMnB,QAAAA,EAAAA,CAAWoB,GAAG,CAAC,EAAC,CAAA;IACzC,MAAMC,QAAAA,GAAWD,IAAI,IAAA,EAAMD,UAAAA,CAAAA;IAE3B,MAAMN,MAAAA,GAASQ,QAAAA,GACX,MAAMpB,MAAAA,CAAOqB,EAAE,CAACC,KAAK,CAACC,gBAAAA,CAAAA,CAAkBC,OAAO,CAAC;QAAEC,KAAAA,EAAO;YAAET,EAAAA,EAAII;AAAS;KAAE,CAAA,GAC1E,IAAA;IAEJ,OAAOM,KAAAA,CAAMd,UAAUP,qBAAAA,EAAAA,GAA0BO,MAAAA;AACnD,CAAA;AAEA,sBAAe;AACbK,IAAAA;AACF,CAAA;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../server/src/services/extensions/index.ts"],"sourcesContent":["import { async } from '@strapi/utils';\nimport { signEntityMedia } from './utils';\n\nconst signFileUrlsOnDocumentService = async () => {\n const { provider } = strapi.plugins.upload;\n const isPrivate = await provider.isPrivate();\n\n // We only need to sign the file urls if the provider is private\n if (!isPrivate) {\n return;\n }\n\n strapi.documents.use(async (ctx, next) => {\n const uid = ctx.uid;\n const result: any = await next();\n\n if (ctx.action === 'findMany') {\n // Shape: [ entry ]\n return async.map(result, (entry: any) => signEntityMedia(entry, uid));\n }\n\n if (\n ctx.action === 'findFirst' ||\n ctx.action === 'findOne' ||\n ctx.action === 'create' ||\n ctx.action === 'update'\n ) {\n // Shape: entry\n return signEntityMedia(result, uid);\n }\n\n if (\n ctx.action === 'delete' ||\n ctx.action === 'clone' ||\n ctx.action === 'publish' ||\n ctx.action === 'unpublish' ||\n ctx.action === 'discardDraft'\n ) {\n // Shape: { entries: [ entry ] }\n // ...\n return {\n ...result,\n entries: await async.map(result.entries, (entry: any) => signEntityMedia(entry, uid)),\n };\n }\n\n return result;\n });\n};\n\nexport default {\n signFileUrlsOnDocumentService,\n};\n"],"names":["signFileUrlsOnDocumentService","provider","strapi","plugins","upload","isPrivate","documents","use","ctx","next","uid","result","action","async","map","entry","signEntityMedia","entries"],"mappings":";;;;;AAGA,MAAMA,
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../server/src/services/extensions/index.ts"],"sourcesContent":["import { async } from '@strapi/utils';\nimport { signEntityMedia } from './utils';\n\nconst signFileUrlsOnDocumentService = async () => {\n const { provider } = strapi.plugins.upload;\n const isPrivate = await provider.isPrivate();\n\n // We only need to sign the file urls if the provider is private\n if (!isPrivate) {\n return;\n }\n\n strapi.documents.use(async (ctx, next) => {\n const uid = ctx.uid;\n const result: any = await next();\n\n if (ctx.action === 'findMany') {\n // Shape: [ entry ]\n return async.map(result, (entry: any) => signEntityMedia(entry, uid));\n }\n\n if (\n ctx.action === 'findFirst' ||\n ctx.action === 'findOne' ||\n ctx.action === 'create' ||\n ctx.action === 'update'\n ) {\n // Shape: entry\n return signEntityMedia(result, uid);\n }\n\n if (\n ctx.action === 'delete' ||\n ctx.action === 'clone' ||\n ctx.action === 'publish' ||\n ctx.action === 'unpublish' ||\n ctx.action === 'discardDraft'\n ) {\n // Shape: { entries: [ entry ] }\n // ...\n return {\n ...result,\n entries: await async.map(result.entries, (entry: any) => signEntityMedia(entry, uid)),\n };\n }\n\n return result;\n });\n};\n\nexport default {\n signFileUrlsOnDocumentService,\n};\n"],"names":["signFileUrlsOnDocumentService","provider","strapi","plugins","upload","isPrivate","documents","use","ctx","next","uid","result","action","async","map","entry","signEntityMedia","entries"],"mappings":";;;;;AAGA,MAAMA,6BAAAA,GAAgC,UAAA;AACpC,IAAA,MAAM,EAAEC,QAAQ,EAAE,GAAGC,MAAAA,CAAOC,OAAO,CAACC,MAAM;IAC1C,MAAMC,SAAAA,GAAY,MAAMJ,QAAAA,CAASI,SAAS,EAAA;;AAG1C,IAAA,IAAI,CAACA,SAAAA,EAAW;AACd,QAAA;AACF,IAAA;AAEAH,IAAAA,MAAAA,CAAOI,SAAS,CAACC,GAAG,CAAC,OAAOC,GAAAA,EAAKC,IAAAA,GAAAA;QAC/B,MAAMC,GAAAA,GAAMF,IAAIE,GAAG;AACnB,QAAA,MAAMC,SAAc,MAAMF,IAAAA,EAAAA;QAE1B,IAAID,GAAAA,CAAII,MAAM,KAAK,UAAA,EAAY;;AAE7B,YAAA,OAAOC,YAAMC,GAAG,CAACH,QAAQ,CAACI,KAAAA,GAAeC,wBAAgBD,KAAAA,EAAOL,GAAAA,CAAAA,CAAAA;AAClE,QAAA;AAEA,QAAA,IACEF,GAAAA,CAAII,MAAM,KAAK,WAAA,IACfJ,IAAII,MAAM,KAAK,SAAA,IACfJ,GAAAA,CAAII,MAAM,KAAK,QAAA,IACfJ,GAAAA,CAAII,MAAM,KAAK,QAAA,EACf;;AAEA,YAAA,OAAOI,wBAAgBL,MAAAA,EAAQD,GAAAA,CAAAA;AACjC,QAAA;AAEA,QAAA,IACEF,IAAII,MAAM,KAAK,YACfJ,GAAAA,CAAII,MAAM,KAAK,OAAA,IACfJ,GAAAA,CAAII,MAAM,KAAK,SAAA,IACfJ,IAAII,MAAM,KAAK,eACfJ,GAAAA,CAAII,MAAM,KAAK,cAAA,EACf;;;YAGA,OAAO;AACL,gBAAA,GAAGD,MAAM;gBACTM,OAAAA,EAAS,MAAMJ,WAAAA,CAAMC,GAAG,CAACH,MAAAA,CAAOM,OAAO,EAAE,CAACF,KAAAA,GAAeC,uBAAAA,CAAgBD,KAAAA,EAAOL,GAAAA,CAAAA;AAClF,aAAA;AACF,QAAA;QAEA,OAAOC,MAAAA;AACT,IAAA,CAAA,CAAA;AACF,CAAA;AAEA,iBAAe;AACbX,IAAAA;AACF,CAAA;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../../../../server/src/services/extensions/index.ts"],"sourcesContent":["import { async } from '@strapi/utils';\nimport { signEntityMedia } from './utils';\n\nconst signFileUrlsOnDocumentService = async () => {\n const { provider } = strapi.plugins.upload;\n const isPrivate = await provider.isPrivate();\n\n // We only need to sign the file urls if the provider is private\n if (!isPrivate) {\n return;\n }\n\n strapi.documents.use(async (ctx, next) => {\n const uid = ctx.uid;\n const result: any = await next();\n\n if (ctx.action === 'findMany') {\n // Shape: [ entry ]\n return async.map(result, (entry: any) => signEntityMedia(entry, uid));\n }\n\n if (\n ctx.action === 'findFirst' ||\n ctx.action === 'findOne' ||\n ctx.action === 'create' ||\n ctx.action === 'update'\n ) {\n // Shape: entry\n return signEntityMedia(result, uid);\n }\n\n if (\n ctx.action === 'delete' ||\n ctx.action === 'clone' ||\n ctx.action === 'publish' ||\n ctx.action === 'unpublish' ||\n ctx.action === 'discardDraft'\n ) {\n // Shape: { entries: [ entry ] }\n // ...\n return {\n ...result,\n entries: await async.map(result.entries, (entry: any) => signEntityMedia(entry, uid)),\n };\n }\n\n return result;\n });\n};\n\nexport default {\n signFileUrlsOnDocumentService,\n};\n"],"names":["signFileUrlsOnDocumentService","provider","strapi","plugins","upload","isPrivate","documents","use","ctx","next","uid","result","action","async","map","entry","signEntityMedia","entries"],"mappings":";;;AAGA,MAAMA,
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../../../../server/src/services/extensions/index.ts"],"sourcesContent":["import { async } from '@strapi/utils';\nimport { signEntityMedia } from './utils';\n\nconst signFileUrlsOnDocumentService = async () => {\n const { provider } = strapi.plugins.upload;\n const isPrivate = await provider.isPrivate();\n\n // We only need to sign the file urls if the provider is private\n if (!isPrivate) {\n return;\n }\n\n strapi.documents.use(async (ctx, next) => {\n const uid = ctx.uid;\n const result: any = await next();\n\n if (ctx.action === 'findMany') {\n // Shape: [ entry ]\n return async.map(result, (entry: any) => signEntityMedia(entry, uid));\n }\n\n if (\n ctx.action === 'findFirst' ||\n ctx.action === 'findOne' ||\n ctx.action === 'create' ||\n ctx.action === 'update'\n ) {\n // Shape: entry\n return signEntityMedia(result, uid);\n }\n\n if (\n ctx.action === 'delete' ||\n ctx.action === 'clone' ||\n ctx.action === 'publish' ||\n ctx.action === 'unpublish' ||\n ctx.action === 'discardDraft'\n ) {\n // Shape: { entries: [ entry ] }\n // ...\n return {\n ...result,\n entries: await async.map(result.entries, (entry: any) => signEntityMedia(entry, uid)),\n };\n }\n\n return result;\n });\n};\n\nexport default {\n signFileUrlsOnDocumentService,\n};\n"],"names":["signFileUrlsOnDocumentService","provider","strapi","plugins","upload","isPrivate","documents","use","ctx","next","uid","result","action","async","map","entry","signEntityMedia","entries"],"mappings":";;;AAGA,MAAMA,6BAAAA,GAAgC,UAAA;AACpC,IAAA,MAAM,EAAEC,QAAQ,EAAE,GAAGC,MAAAA,CAAOC,OAAO,CAACC,MAAM;IAC1C,MAAMC,SAAAA,GAAY,MAAMJ,QAAAA,CAASI,SAAS,EAAA;;AAG1C,IAAA,IAAI,CAACA,SAAAA,EAAW;AACd,QAAA;AACF,IAAA;AAEAH,IAAAA,MAAAA,CAAOI,SAAS,CAACC,GAAG,CAAC,OAAOC,GAAAA,EAAKC,IAAAA,GAAAA;QAC/B,MAAMC,GAAAA,GAAMF,IAAIE,GAAG;AACnB,QAAA,MAAMC,SAAc,MAAMF,IAAAA,EAAAA;QAE1B,IAAID,GAAAA,CAAII,MAAM,KAAK,UAAA,EAAY;;AAE7B,YAAA,OAAOC,MAAMC,GAAG,CAACH,QAAQ,CAACI,KAAAA,GAAeC,gBAAgBD,KAAAA,EAAOL,GAAAA,CAAAA,CAAAA;AAClE,QAAA;AAEA,QAAA,IACEF,GAAAA,CAAII,MAAM,KAAK,WAAA,IACfJ,IAAII,MAAM,KAAK,SAAA,IACfJ,GAAAA,CAAII,MAAM,KAAK,QAAA,IACfJ,GAAAA,CAAII,MAAM,KAAK,QAAA,EACf;;AAEA,YAAA,OAAOI,gBAAgBL,MAAAA,EAAQD,GAAAA,CAAAA;AACjC,QAAA;AAEA,QAAA,IACEF,IAAII,MAAM,KAAK,YACfJ,GAAAA,CAAII,MAAM,KAAK,OAAA,IACfJ,GAAAA,CAAII,MAAM,KAAK,SAAA,IACfJ,IAAII,MAAM,KAAK,eACfJ,GAAAA,CAAII,MAAM,KAAK,cAAA,EACf;;;YAGA,OAAO;AACL,gBAAA,GAAGD,MAAM;gBACTM,OAAAA,EAAS,MAAMJ,KAAAA,CAAMC,GAAG,CAACH,MAAAA,CAAOM,OAAO,EAAE,CAACF,KAAAA,GAAeC,eAAAA,CAAgBD,KAAAA,EAAOL,GAAAA,CAAAA;AAClF,aAAA;AACF,QAAA;QAEA,OAAOC,MAAAA;AACT,IAAA,CAAA,CAAA;AACF,CAAA;AAEA,iBAAe;AACbX,IAAAA;AACF,CAAA;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../../../../server/src/services/extensions/utils.ts"],"sourcesContent":["import { async, traverseEntity } from '@strapi/utils';\n\nimport type { Schema, UID } from '@strapi/types';\n\nimport { getService } from '../../utils';\nimport { FILE_MODEL_UID } from '../../constants';\n\nimport type { File } from '../../types';\n\ntype SignEntityMediaVisitor = (\n args: {\n key: string;\n value: unknown;\n attribute: Schema.Attribute.AnyAttribute;\n },\n utils: {\n set: (key: string, value: unknown) => void;\n }\n) => Promise<void>;\n\nfunction isFile(value: unknown, attribute: Schema.Attribute.AnyAttribute): value is File {\n if (!value || attribute.type !== 'media') {\n return false;\n }\n\n return true;\n}\n\n/**\n * Visitor function to sign media URLs\n */\nconst signEntityMediaVisitor: SignEntityMediaVisitor = async (\n { key, value, attribute },\n { set }\n) => {\n const { signFileUrls } = getService('file');\n\n if (!attribute) {\n return;\n }\n\n if (attribute.type !== 'media') {\n return;\n }\n\n if (isFile(value, attribute)) {\n // If the attribute is repeatable sign each file\n if (attribute.multiple) {\n const signedFiles = await async.map(value, signFileUrls);\n set(key, signedFiles);\n return;\n }\n\n // If the attribute is not repeatable only sign a single file\n const signedFile = await signFileUrls(value);\n set(key, signedFile);\n }\n};\n\n/**\n *\n * Iterate through an entity manager result\n * Check which modelAttributes are media and pre sign the image URLs\n * if they are from the current upload provider\n *\n * @param {Object} entity\n * @param {Object} modelAttributes\n * @returns\n */\nconst signEntityMedia = async (entity: any, uid: UID.Schema) => {\n if (!entity) {\n return entity;\n }\n\n // If the entity itself is a file, sign it directly\n if (uid === FILE_MODEL_UID) {\n const { signFileUrls } = getService('file');\n return signFileUrls(entity);\n }\n\n // If the entity is a regular content type, look for media attributes\n const model = strapi.getModel(uid);\n return traverseEntity(\n // @ts-expect-error - FIXME: fix traverseEntity using wrong types\n signEntityMediaVisitor,\n { schema: model, getModel: strapi.getModel.bind(strapi) },\n entity\n );\n};\n\nexport { signEntityMedia };\n"],"names":["isFile","value","attribute","type","signEntityMediaVisitor","key","set","signFileUrls","getService","multiple","signedFiles","async","map","signedFile","signEntityMedia","entity","uid","FILE_MODEL_UID","model","strapi","getModel","traverseEntity","schema","bind"],"mappings":";;;;;;AAoBA,SAASA,MAAAA,CAAOC,KAAc,EAAEC,SAAwC,EAAA;AACtE,IAAA,IAAI,CAACD,KAAAA,IAASC,
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../../../server/src/services/extensions/utils.ts"],"sourcesContent":["import { async, traverseEntity } from '@strapi/utils';\n\nimport type { Schema, UID } from '@strapi/types';\n\nimport { getService } from '../../utils';\nimport { FILE_MODEL_UID } from '../../constants';\n\nimport type { File } from '../../types';\n\ntype SignEntityMediaVisitor = (\n args: {\n key: string;\n value: unknown;\n attribute: Schema.Attribute.AnyAttribute;\n },\n utils: {\n set: (key: string, value: unknown) => void;\n }\n) => Promise<void>;\n\nfunction isFile(value: unknown, attribute: Schema.Attribute.AnyAttribute): value is File {\n if (!value || attribute.type !== 'media') {\n return false;\n }\n\n return true;\n}\n\n/**\n * Visitor function to sign media URLs\n */\nconst signEntityMediaVisitor: SignEntityMediaVisitor = async (\n { key, value, attribute },\n { set }\n) => {\n const { signFileUrls } = getService('file');\n\n if (!attribute) {\n return;\n }\n\n if (attribute.type !== 'media') {\n return;\n }\n\n if (isFile(value, attribute)) {\n // If the attribute is repeatable sign each file\n if (attribute.multiple) {\n const signedFiles = await async.map(value, signFileUrls);\n set(key, signedFiles);\n return;\n }\n\n // If the attribute is not repeatable only sign a single file\n const signedFile = await signFileUrls(value);\n set(key, signedFile);\n }\n};\n\n/**\n *\n * Iterate through an entity manager result\n * Check which modelAttributes are media and pre sign the image URLs\n * if they are from the current upload provider\n *\n * @param {Object} entity\n * @param {Object} modelAttributes\n * @returns\n */\nconst signEntityMedia = async (entity: any, uid: UID.Schema) => {\n if (!entity) {\n return entity;\n }\n\n // If the entity itself is a file, sign it directly\n if (uid === FILE_MODEL_UID) {\n const { signFileUrls } = getService('file');\n return signFileUrls(entity);\n }\n\n // If the entity is a regular content type, look for media attributes\n const model = strapi.getModel(uid);\n return traverseEntity(\n // @ts-expect-error - FIXME: fix traverseEntity using wrong types\n signEntityMediaVisitor,\n { schema: model, getModel: strapi.getModel.bind(strapi) },\n entity\n );\n};\n\nexport { signEntityMedia };\n"],"names":["isFile","value","attribute","type","signEntityMediaVisitor","key","set","signFileUrls","getService","multiple","signedFiles","async","map","signedFile","signEntityMedia","entity","uid","FILE_MODEL_UID","model","strapi","getModel","traverseEntity","schema","bind"],"mappings":";;;;;;AAoBA,SAASA,MAAAA,CAAOC,KAAc,EAAEC,SAAwC,EAAA;AACtE,IAAA,IAAI,CAACD,KAAAA,IAASC,SAAAA,CAAUC,IAAI,KAAK,OAAA,EAAS;QACxC,OAAO,KAAA;AACT,IAAA;IAEA,OAAO,IAAA;AACT;AAEA;;AAEC,IACD,MAAMC,sBAAAA,GAAiD,OACrD,EAAEC,GAAG,EAAEJ,KAAK,EAAEC,SAAS,EAAE,EACzB,EAAEI,GAAG,EAAE,GAAA;AAEP,IAAA,MAAM,EAAEC,YAAY,EAAE,GAAGC,gBAAAA,CAAW,MAAA,CAAA;AAEpC,IAAA,IAAI,CAACN,SAAAA,EAAW;AACd,QAAA;AACF,IAAA;IAEA,IAAIA,SAAAA,CAAUC,IAAI,KAAK,OAAA,EAAS;AAC9B,QAAA;AACF,IAAA;IAEA,IAAIH,MAAAA,CAAOC,OAAOC,SAAAA,CAAAA,EAAY;;QAE5B,IAAIA,SAAAA,CAAUO,QAAQ,EAAE;AACtB,YAAA,MAAMC,WAAAA,GAAc,MAAMC,WAAAA,CAAMC,GAAG,CAACX,KAAAA,EAAOM,YAAAA,CAAAA;AAC3CD,YAAAA,GAAAA,CAAID,GAAAA,EAAKK,WAAAA,CAAAA;AACT,YAAA;AACF,QAAA;;QAGA,MAAMG,UAAAA,GAAa,MAAMN,YAAAA,CAAaN,KAAAA,CAAAA;AACtCK,QAAAA,GAAAA,CAAID,GAAAA,EAAKQ,UAAAA,CAAAA;AACX,IAAA;AACF,CAAA;AAEA;;;;;;;;;IAUA,MAAMC,eAAAA,GAAkB,OAAOC,MAAAA,EAAaC,GAAAA,GAAAA;AAC1C,IAAA,IAAI,CAACD,MAAAA,EAAQ;QACX,OAAOA,MAAAA;AACT,IAAA;;AAGA,IAAA,IAAIC,QAAQC,wBAAAA,EAAgB;AAC1B,QAAA,MAAM,EAAEV,YAAY,EAAE,GAAGC,gBAAAA,CAAW,MAAA,CAAA;AACpC,QAAA,OAAOD,YAAAA,CAAaQ,MAAAA,CAAAA;AACtB,IAAA;;IAGA,MAAMG,KAAAA,GAAQC,MAAAA,CAAOC,QAAQ,CAACJ,GAAAA,CAAAA;AAC9B,IAAA,OAAOK;IAELjB,sBAAAA,EACA;QAAEkB,MAAAA,EAAQJ,KAAAA;AAAOE,QAAAA,QAAAA,EAAUD,MAAAA,CAAOC,QAAQ,CAACG,IAAI,CAACJ,MAAAA;KAAQ,EACxDJ,MAAAA,CAAAA;AAEJ;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.mjs","sources":["../../../../server/src/services/extensions/utils.ts"],"sourcesContent":["import { async, traverseEntity } from '@strapi/utils';\n\nimport type { Schema, UID } from '@strapi/types';\n\nimport { getService } from '../../utils';\nimport { FILE_MODEL_UID } from '../../constants';\n\nimport type { File } from '../../types';\n\ntype SignEntityMediaVisitor = (\n args: {\n key: string;\n value: unknown;\n attribute: Schema.Attribute.AnyAttribute;\n },\n utils: {\n set: (key: string, value: unknown) => void;\n }\n) => Promise<void>;\n\nfunction isFile(value: unknown, attribute: Schema.Attribute.AnyAttribute): value is File {\n if (!value || attribute.type !== 'media') {\n return false;\n }\n\n return true;\n}\n\n/**\n * Visitor function to sign media URLs\n */\nconst signEntityMediaVisitor: SignEntityMediaVisitor = async (\n { key, value, attribute },\n { set }\n) => {\n const { signFileUrls } = getService('file');\n\n if (!attribute) {\n return;\n }\n\n if (attribute.type !== 'media') {\n return;\n }\n\n if (isFile(value, attribute)) {\n // If the attribute is repeatable sign each file\n if (attribute.multiple) {\n const signedFiles = await async.map(value, signFileUrls);\n set(key, signedFiles);\n return;\n }\n\n // If the attribute is not repeatable only sign a single file\n const signedFile = await signFileUrls(value);\n set(key, signedFile);\n }\n};\n\n/**\n *\n * Iterate through an entity manager result\n * Check which modelAttributes are media and pre sign the image URLs\n * if they are from the current upload provider\n *\n * @param {Object} entity\n * @param {Object} modelAttributes\n * @returns\n */\nconst signEntityMedia = async (entity: any, uid: UID.Schema) => {\n if (!entity) {\n return entity;\n }\n\n // If the entity itself is a file, sign it directly\n if (uid === FILE_MODEL_UID) {\n const { signFileUrls } = getService('file');\n return signFileUrls(entity);\n }\n\n // If the entity is a regular content type, look for media attributes\n const model = strapi.getModel(uid);\n return traverseEntity(\n // @ts-expect-error - FIXME: fix traverseEntity using wrong types\n signEntityMediaVisitor,\n { schema: model, getModel: strapi.getModel.bind(strapi) },\n entity\n );\n};\n\nexport { signEntityMedia };\n"],"names":["isFile","value","attribute","type","signEntityMediaVisitor","key","set","signFileUrls","getService","multiple","signedFiles","async","map","signedFile","signEntityMedia","entity","uid","FILE_MODEL_UID","model","strapi","getModel","traverseEntity","schema","bind"],"mappings":";;;;AAoBA,SAASA,MAAAA,CAAOC,KAAc,EAAEC,SAAwC,EAAA;AACtE,IAAA,IAAI,CAACD,KAAAA,IAASC,
|
|
1
|
+
{"version":3,"file":"utils.mjs","sources":["../../../../server/src/services/extensions/utils.ts"],"sourcesContent":["import { async, traverseEntity } from '@strapi/utils';\n\nimport type { Schema, UID } from '@strapi/types';\n\nimport { getService } from '../../utils';\nimport { FILE_MODEL_UID } from '../../constants';\n\nimport type { File } from '../../types';\n\ntype SignEntityMediaVisitor = (\n args: {\n key: string;\n value: unknown;\n attribute: Schema.Attribute.AnyAttribute;\n },\n utils: {\n set: (key: string, value: unknown) => void;\n }\n) => Promise<void>;\n\nfunction isFile(value: unknown, attribute: Schema.Attribute.AnyAttribute): value is File {\n if (!value || attribute.type !== 'media') {\n return false;\n }\n\n return true;\n}\n\n/**\n * Visitor function to sign media URLs\n */\nconst signEntityMediaVisitor: SignEntityMediaVisitor = async (\n { key, value, attribute },\n { set }\n) => {\n const { signFileUrls } = getService('file');\n\n if (!attribute) {\n return;\n }\n\n if (attribute.type !== 'media') {\n return;\n }\n\n if (isFile(value, attribute)) {\n // If the attribute is repeatable sign each file\n if (attribute.multiple) {\n const signedFiles = await async.map(value, signFileUrls);\n set(key, signedFiles);\n return;\n }\n\n // If the attribute is not repeatable only sign a single file\n const signedFile = await signFileUrls(value);\n set(key, signedFile);\n }\n};\n\n/**\n *\n * Iterate through an entity manager result\n * Check which modelAttributes are media and pre sign the image URLs\n * if they are from the current upload provider\n *\n * @param {Object} entity\n * @param {Object} modelAttributes\n * @returns\n */\nconst signEntityMedia = async (entity: any, uid: UID.Schema) => {\n if (!entity) {\n return entity;\n }\n\n // If the entity itself is a file, sign it directly\n if (uid === FILE_MODEL_UID) {\n const { signFileUrls } = getService('file');\n return signFileUrls(entity);\n }\n\n // If the entity is a regular content type, look for media attributes\n const model = strapi.getModel(uid);\n return traverseEntity(\n // @ts-expect-error - FIXME: fix traverseEntity using wrong types\n signEntityMediaVisitor,\n { schema: model, getModel: strapi.getModel.bind(strapi) },\n entity\n );\n};\n\nexport { signEntityMedia };\n"],"names":["isFile","value","attribute","type","signEntityMediaVisitor","key","set","signFileUrls","getService","multiple","signedFiles","async","map","signedFile","signEntityMedia","entity","uid","FILE_MODEL_UID","model","strapi","getModel","traverseEntity","schema","bind"],"mappings":";;;;AAoBA,SAASA,MAAAA,CAAOC,KAAc,EAAEC,SAAwC,EAAA;AACtE,IAAA,IAAI,CAACD,KAAAA,IAASC,SAAAA,CAAUC,IAAI,KAAK,OAAA,EAAS;QACxC,OAAO,KAAA;AACT,IAAA;IAEA,OAAO,IAAA;AACT;AAEA;;AAEC,IACD,MAAMC,sBAAAA,GAAiD,OACrD,EAAEC,GAAG,EAAEJ,KAAK,EAAEC,SAAS,EAAE,EACzB,EAAEI,GAAG,EAAE,GAAA;AAEP,IAAA,MAAM,EAAEC,YAAY,EAAE,GAAGC,UAAAA,CAAW,MAAA,CAAA;AAEpC,IAAA,IAAI,CAACN,SAAAA,EAAW;AACd,QAAA;AACF,IAAA;IAEA,IAAIA,SAAAA,CAAUC,IAAI,KAAK,OAAA,EAAS;AAC9B,QAAA;AACF,IAAA;IAEA,IAAIH,MAAAA,CAAOC,OAAOC,SAAAA,CAAAA,EAAY;;QAE5B,IAAIA,SAAAA,CAAUO,QAAQ,EAAE;AACtB,YAAA,MAAMC,WAAAA,GAAc,MAAMC,KAAAA,CAAMC,GAAG,CAACX,KAAAA,EAAOM,YAAAA,CAAAA;AAC3CD,YAAAA,GAAAA,CAAID,GAAAA,EAAKK,WAAAA,CAAAA;AACT,YAAA;AACF,QAAA;;QAGA,MAAMG,UAAAA,GAAa,MAAMN,YAAAA,CAAaN,KAAAA,CAAAA;AACtCK,QAAAA,GAAAA,CAAID,GAAAA,EAAKQ,UAAAA,CAAAA;AACX,IAAA;AACF,CAAA;AAEA;;;;;;;;;IAUA,MAAMC,eAAAA,GAAkB,OAAOC,MAAAA,EAAaC,GAAAA,GAAAA;AAC1C,IAAA,IAAI,CAACD,MAAAA,EAAQ;QACX,OAAOA,MAAAA;AACT,IAAA;;AAGA,IAAA,IAAIC,QAAQC,cAAAA,EAAgB;AAC1B,QAAA,MAAM,EAAEV,YAAY,EAAE,GAAGC,UAAAA,CAAW,MAAA,CAAA;AACpC,QAAA,OAAOD,YAAAA,CAAaQ,MAAAA,CAAAA;AACtB,IAAA;;IAGA,MAAMG,KAAAA,GAAQC,MAAAA,CAAOC,QAAQ,CAACJ,GAAAA,CAAAA;AAC9B,IAAA,OAAOK;IAELjB,sBAAAA,EACA;QAAEkB,MAAAA,EAAQJ,KAAAA;AAAOE,QAAAA,QAAAA,EAAUD,MAAAA,CAAOC,QAAQ,CAACG,IAAI,CAACJ,MAAAA;KAAQ,EACxDJ,MAAAA,CAAAA;AAEJ;;;;"}
|
|
@@ -1,10 +1,128 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var path = require('path');
|
|
4
|
+
var dns = require('dns/promises');
|
|
5
|
+
var net = require('net');
|
|
6
|
+
var fse = require('fs-extra');
|
|
3
7
|
var fp = require('lodash/fp');
|
|
4
8
|
var utils = require('@strapi/utils');
|
|
5
9
|
var constants = require('../constants.js');
|
|
6
10
|
var index = require('../utils/index.js');
|
|
7
11
|
|
|
12
|
+
const { ApplicationError } = utils.errors;
|
|
13
|
+
const FETCH_TIMEOUT_MS = 60000; // 60 seconds
|
|
14
|
+
// Blocks loopback, link-local (cloud metadata), and RFC-1918 private ranges to prevent SSRF
|
|
15
|
+
const SSRF_BLOCK_LIST = new net.BlockList();
|
|
16
|
+
SSRF_BLOCK_LIST.addSubnet('127.0.0.0', 8); // loopback
|
|
17
|
+
SSRF_BLOCK_LIST.addSubnet('10.0.0.0', 8); // RFC-1918
|
|
18
|
+
SSRF_BLOCK_LIST.addSubnet('172.16.0.0', 12); // RFC-1918
|
|
19
|
+
SSRF_BLOCK_LIST.addSubnet('192.168.0.0', 16); // RFC-1918
|
|
20
|
+
SSRF_BLOCK_LIST.addSubnet('169.254.0.0', 16); // link-local / cloud metadata (AWS, GCP, Azure)
|
|
21
|
+
SSRF_BLOCK_LIST.addSubnet('::1', 128, 'ipv6'); // IPv6 loopback
|
|
22
|
+
SSRF_BLOCK_LIST.addSubnet('fc00::', 7, 'ipv6'); // IPv6 unique local
|
|
23
|
+
SSRF_BLOCK_LIST.addSubnet('fe80::', 10, 'ipv6'); // IPv6 link-local
|
|
24
|
+
/**
|
|
25
|
+
* Extracts filename from a URL path or Content-Disposition header
|
|
26
|
+
*/ const getFilenameFromUrl = (url, contentDisposition)=>{
|
|
27
|
+
// Try Content-Disposition header first
|
|
28
|
+
if (contentDisposition) {
|
|
29
|
+
// Extracts filename from Content-Disposition header (e.g. filename="photo.jpg" or filename*=UTF-8''photo.jpg)
|
|
30
|
+
const filenameMatch = contentDisposition.match(/filename\*?=['"]?(?:UTF-\d['"]*)?([^;\r\n"']*)['"]?/i);
|
|
31
|
+
if (filenameMatch?.[1]) {
|
|
32
|
+
// Use path.basename to prevent path traversal attacks
|
|
33
|
+
return path.basename(decodeURIComponent(filenameMatch[1]));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Fall back to URL path
|
|
37
|
+
try {
|
|
38
|
+
const urlObj = new URL(url);
|
|
39
|
+
const pathname = urlObj.pathname;
|
|
40
|
+
const filename = pathname.split('/').pop();
|
|
41
|
+
if (filename && filename.length > 0) {
|
|
42
|
+
// Use path.basename to prevent path traversal attacks (e.g., URL-encoded separators)
|
|
43
|
+
return path.basename(decodeURIComponent(filename));
|
|
44
|
+
}
|
|
45
|
+
} catch {
|
|
46
|
+
// Invalid URL, use default
|
|
47
|
+
}
|
|
48
|
+
// Generate a timestamp-based default filename
|
|
49
|
+
const now = new Date();
|
|
50
|
+
const date = now.toISOString().split('T')[0]; // 2024-02-23
|
|
51
|
+
const time = now.toTimeString().split(' ')[0].replace(/:/g, ''); // 143052
|
|
52
|
+
return `untitled_${date}_${time}`;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Fetches a URL and saves it as a temporary file
|
|
56
|
+
* Returns an InputFile-compatible object for use with the upload pipeline
|
|
57
|
+
*/ const fetchUrlToInputFile = async (url, tmpWorkingDirectory, sizeLimit)=>{
|
|
58
|
+
// Validate URL protocol
|
|
59
|
+
let parsedUrl;
|
|
60
|
+
try {
|
|
61
|
+
parsedUrl = new URL(url);
|
|
62
|
+
} catch {
|
|
63
|
+
throw new ApplicationError(`Invalid URL: ${url}`);
|
|
64
|
+
}
|
|
65
|
+
if (![
|
|
66
|
+
'http:',
|
|
67
|
+
'https:'
|
|
68
|
+
].includes(parsedUrl.protocol)) {
|
|
69
|
+
throw new ApplicationError(`Invalid URL protocol. Only http and https are allowed: ${url}`);
|
|
70
|
+
}
|
|
71
|
+
// Resolve hostname and block private/internal IP ranges to prevent SSRF
|
|
72
|
+
try {
|
|
73
|
+
const { address, family } = await dns.lookup(parsedUrl.hostname);
|
|
74
|
+
const type = family === 6 ? 'ipv6' : 'ipv4';
|
|
75
|
+
if (SSRF_BLOCK_LIST.check(address, type)) {
|
|
76
|
+
throw new ApplicationError(`URL resolves to a blocked address: ${url}`);
|
|
77
|
+
}
|
|
78
|
+
} catch (error) {
|
|
79
|
+
if (error instanceof ApplicationError) throw error;
|
|
80
|
+
throw new ApplicationError(`Could not resolve hostname: ${parsedUrl.hostname}`);
|
|
81
|
+
}
|
|
82
|
+
// Fetch the URL with timeout
|
|
83
|
+
let response;
|
|
84
|
+
try {
|
|
85
|
+
response = await fetch(url, {
|
|
86
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
87
|
+
});
|
|
88
|
+
} catch (error) {
|
|
89
|
+
if (error instanceof Error && error.name === 'TimeoutError') {
|
|
90
|
+
throw new ApplicationError(`Request timed out while fetching URL: ${url}`);
|
|
91
|
+
}
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
if (!response.ok) {
|
|
95
|
+
throw new ApplicationError(`Failed to fetch URL: ${url} (${response.status} ${response.statusText})`);
|
|
96
|
+
}
|
|
97
|
+
// Check Content-Length header for early rejection of large files
|
|
98
|
+
if (sizeLimit) {
|
|
99
|
+
const contentLength = response.headers.get('content-length');
|
|
100
|
+
if (contentLength && parseInt(contentLength, 10) > sizeLimit) {
|
|
101
|
+
throw new ApplicationError(`File too large: maximum allowed size is ${Math.round(sizeLimit / (1024 * 1024))}MB`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Get content type and filename
|
|
105
|
+
const contentType = response.headers.get('content-type')?.split(';')[0] || 'application/octet-stream';
|
|
106
|
+
const contentDisposition = response.headers.get('content-disposition');
|
|
107
|
+
const filename = getFilenameFromUrl(response.url, contentDisposition);
|
|
108
|
+
// Read response body
|
|
109
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
110
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
111
|
+
// Write to temp file
|
|
112
|
+
const tmpFilePath = path.join(tmpWorkingDirectory, filename);
|
|
113
|
+
await fse.writeFile(tmpFilePath, buffer);
|
|
114
|
+
// Create file object compatible with upload pipeline
|
|
115
|
+
const fetchedFile = {
|
|
116
|
+
filepath: tmpFilePath,
|
|
117
|
+
originalFilename: filename,
|
|
118
|
+
mimetype: contentType,
|
|
119
|
+
size: buffer.length,
|
|
120
|
+
tmpWorkingDirectory
|
|
121
|
+
};
|
|
122
|
+
return {
|
|
123
|
+
file: fetchedFile
|
|
124
|
+
};
|
|
125
|
+
};
|
|
8
126
|
const getFolderPath = async (folderId)=>{
|
|
9
127
|
if (!folderId) return '/';
|
|
10
128
|
const parentFolder = await strapi.db.query(constants.FOLDER_MODEL_UID).findOne({
|
|
@@ -50,7 +168,8 @@ const signFileUrls = async (file)=>{
|
|
|
50
168
|
var file = {
|
|
51
169
|
getFolderPath,
|
|
52
170
|
deleteByIds,
|
|
53
|
-
signFileUrls
|
|
171
|
+
signFileUrls,
|
|
172
|
+
fetchUrlToInputFile
|
|
54
173
|
};
|
|
55
174
|
|
|
56
175
|
module.exports = file;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file.js","sources":["../../../server/src/services/file.ts"],"sourcesContent":["import { cloneDeep } from 'lodash/fp';\nimport { async } from '@strapi/utils';\n\nimport { FOLDER_MODEL_UID, FILE_MODEL_UID } from '../constants';\nimport { getService } from '../utils';\n\nimport { Config, type File } from '../types';\n\nconst getFolderPath = async (folderId?: number | null) => {\n if (!folderId) return '/';\n\n const parentFolder = await strapi.db.query(FOLDER_MODEL_UID).findOne({ where: { id: folderId } });\n\n return parentFolder.path;\n};\n\nconst deleteByIds = async (ids: number[] = []) => {\n const filesToDelete = await strapi.db\n .query(FILE_MODEL_UID)\n .findMany({ where: { id: { $in: ids } } });\n\n await Promise.all(filesToDelete.map((file: File) => getService('upload').remove(file)));\n\n return filesToDelete;\n};\n\nconst signFileUrls = async (file: File) => {\n const { provider } = strapi.plugins.upload;\n const { provider: providerConfig } = strapi.config.get<Config>('plugin::upload');\n const isPrivate = await provider.isPrivate();\n file.isUrlSigned = false;\n\n // Check file provider and if provider is private\n if (file.provider !== providerConfig || !isPrivate) {\n return file;\n }\n\n const signUrl = async (file: File) => {\n const signedUrl = await provider.getSignedUrl(file);\n file.url = signedUrl.url;\n file.isUrlSigned = true;\n };\n\n const signedFile = cloneDeep(file);\n\n // Sign each file format\n await signUrl(signedFile);\n if (file.formats) {\n await async.map(Object.values(signedFile.formats ?? {}), signUrl);\n }\n\n return signedFile;\n};\n\nexport default { getFolderPath, deleteByIds, signFileUrls };\n"],"names":["getFolderPath","folderId","parentFolder","strapi","db","query","FOLDER_MODEL_UID","findOne","where","id","path","deleteByIds","ids","filesToDelete","FILE_MODEL_UID","findMany","$in","Promise","all","map","file","getService","remove","signFileUrls","provider","plugins","upload","providerConfig","config","get","isPrivate","isUrlSigned","signUrl","signedUrl","getSignedUrl","url","signedFile","cloneDeep","formats","async","Object","values"],"mappings":";;;;;;;AAQA,MAAMA,gBAAgB,OAAOC,QAAAA,GAAAA;IAC3B,IAAI,CAACA,UAAU,OAAO,GAAA;IAEtB,MAAMC,YAAAA,GAAe,MAAMC,MAAOC,CAAAA,EAAE,CAACC,KAAK,CAACC,0BAAkBC,CAAAA,CAAAA,OAAO,CAAC;QAAEC,KAAO,EAAA;YAAEC,EAAIR,EAAAA;AAAS;AAAE,KAAA,CAAA;AAE/F,IAAA,OAAOC,aAAaQ,IAAI;AAC1B,CAAA;AAEA,MAAMC,WAAAA,GAAc,OAAOC,GAAAA,GAAgB,EAAE,GAAA;IAC3C,MAAMC,aAAAA,GAAgB,MAAMV,MAAOC,CAAAA,EAAE,CAClCC,KAAK,CAACS,wBACNC,CAAAA,CAAAA,QAAQ,CAAC;QAAEP,KAAO,EAAA;YAAEC,EAAI,EAAA;gBAAEO,GAAKJ,EAAAA;AAAI;AAAE;AAAE,KAAA,CAAA;IAE1C,MAAMK,OAAAA,CAAQC,GAAG,CAACL,aAAcM,CAAAA,GAAG,CAAC,CAACC,IAAeC,GAAAA,gBAAAA,CAAW,QAAUC,CAAAA,CAAAA,MAAM,CAACF,IAAAA,CAAAA,CAAAA,CAAAA;IAEhF,OAAOP,aAAAA;AACT,CAAA;AAEA,MAAMU,eAAe,OAAOH,IAAAA,GAAAA;AAC1B,IAAA,MAAM,EAAEI,QAAQ,EAAE,GAAGrB,MAAOsB,CAAAA,OAAO,CAACC,MAAM;IAC1C,MAAM,EAAEF,UAAUG,cAAc,EAAE,GAAGxB,MAAOyB,CAAAA,MAAM,CAACC,GAAG,CAAS,gBAAA,CAAA;IAC/D,MAAMC,SAAAA,GAAY,MAAMN,QAAAA,CAASM,SAAS,EAAA;AAC1CV,IAAAA,IAAAA,CAAKW,WAAW,GAAG,KAAA;;AAGnB,IAAA,IAAIX,IAAKI,CAAAA,QAAQ,KAAKG,cAAAA,IAAkB,CAACG,SAAW,EAAA;QAClD,OAAOV,IAAAA;AACT;AAEA,IAAA,MAAMY,UAAU,OAAOZ,IAAAA,GAAAA;AACrB,QAAA,MAAMa,SAAY,GAAA,MAAMT,QAASU,CAAAA,YAAY,CAACd,IAAAA,CAAAA;QAC9CA,IAAKe,CAAAA,GAAG,GAAGF,SAAAA,CAAUE,GAAG;AACxBf,QAAAA,IAAAA,CAAKW,WAAW,GAAG,IAAA;AACrB,KAAA;AAEA,IAAA,MAAMK,aAAaC,YAAUjB,CAAAA,IAAAA,CAAAA;;AAG7B,IAAA,MAAMY,OAAQI,CAAAA,UAAAA,CAAAA;IACd,IAAIhB,IAAAA,CAAKkB,OAAO,EAAE;QAChB,MAAMC,WAAAA,CAAMpB,GAAG,CAACqB,MAAOC,CAAAA,MAAM,CAACL,UAAWE,CAAAA,OAAO,IAAI,EAAKN,CAAAA,EAAAA,OAAAA,CAAAA;AAC3D;IAEA,OAAOI,UAAAA;AACT,CAAA;AAEA,WAAe;AAAEpC,IAAAA,aAAAA;AAAeW,IAAAA,WAAAA;AAAaY,IAAAA;AAAa,CAAE;;;;"}
|
|
1
|
+
{"version":3,"file":"file.js","sources":["../../../server/src/services/file.ts"],"sourcesContent":["import path from 'path';\nimport dns from 'dns/promises';\nimport net from 'net';\nimport fse from 'fs-extra';\nimport { cloneDeep } from 'lodash/fp';\nimport { async, errors } from '@strapi/utils';\n\nimport { FOLDER_MODEL_UID, FILE_MODEL_UID } from '../constants';\nimport { getService } from '../utils';\n\nimport { Config, type File } from '../types';\n\nconst { ApplicationError } = errors;\n\nconst FETCH_TIMEOUT_MS = 60_000; // 60 seconds\n\n// Blocks loopback, link-local (cloud metadata), and RFC-1918 private ranges to prevent SSRF\nconst SSRF_BLOCK_LIST = new net.BlockList();\nSSRF_BLOCK_LIST.addSubnet('127.0.0.0', 8); // loopback\nSSRF_BLOCK_LIST.addSubnet('10.0.0.0', 8); // RFC-1918\nSSRF_BLOCK_LIST.addSubnet('172.16.0.0', 12); // RFC-1918\nSSRF_BLOCK_LIST.addSubnet('192.168.0.0', 16); // RFC-1918\nSSRF_BLOCK_LIST.addSubnet('169.254.0.0', 16); // link-local / cloud metadata (AWS, GCP, Azure)\nSSRF_BLOCK_LIST.addSubnet('::1', 128, 'ipv6'); // IPv6 loopback\nSSRF_BLOCK_LIST.addSubnet('fc00::', 7, 'ipv6'); // IPv6 unique local\nSSRF_BLOCK_LIST.addSubnet('fe80::', 10, 'ipv6'); // IPv6 link-local\n\n/**\n * Represents a file fetched from a URL, compatible with the upload pipeline\n */\ninterface UrlFetchedFile {\n filepath: string;\n originalFilename: string;\n mimetype: string;\n size: number;\n tmpWorkingDirectory?: string;\n}\n\ninterface FetchUrlResult {\n file: UrlFetchedFile;\n}\n\n/**\n * Extracts filename from a URL path or Content-Disposition header\n */\nconst getFilenameFromUrl = (url: string, contentDisposition?: string | null): string => {\n // Try Content-Disposition header first\n if (contentDisposition) {\n // Extracts filename from Content-Disposition header (e.g. filename=\"photo.jpg\" or filename*=UTF-8''photo.jpg)\n const filenameMatch = contentDisposition.match(\n /filename\\*?=['\"]?(?:UTF-\\d['\"]*)?([^;\\r\\n\"']*)['\"]?/i\n );\n if (filenameMatch?.[1]) {\n // Use path.basename to prevent path traversal attacks\n return path.basename(decodeURIComponent(filenameMatch[1]));\n }\n }\n\n // Fall back to URL path\n try {\n const urlObj = new URL(url);\n const pathname = urlObj.pathname;\n const filename = pathname.split('/').pop();\n if (filename && filename.length > 0) {\n // Use path.basename to prevent path traversal attacks (e.g., URL-encoded separators)\n return path.basename(decodeURIComponent(filename));\n }\n } catch {\n // Invalid URL, use default\n }\n\n // Generate a timestamp-based default filename\n const now = new Date();\n const date = now.toISOString().split('T')[0]; // 2024-02-23\n const time = now.toTimeString().split(' ')[0].replace(/:/g, ''); // 143052\n return `untitled_${date}_${time}`;\n};\n\n/**\n * Fetches a URL and saves it as a temporary file\n * Returns an InputFile-compatible object for use with the upload pipeline\n */\nconst fetchUrlToInputFile = async (\n url: string,\n tmpWorkingDirectory: string,\n sizeLimit?: number\n): Promise<FetchUrlResult> => {\n // Validate URL protocol\n let parsedUrl: URL;\n try {\n parsedUrl = new URL(url);\n } catch {\n throw new ApplicationError(`Invalid URL: ${url}`);\n }\n\n if (!['http:', 'https:'].includes(parsedUrl.protocol)) {\n throw new ApplicationError(`Invalid URL protocol. Only http and https are allowed: ${url}`);\n }\n\n // Resolve hostname and block private/internal IP ranges to prevent SSRF\n try {\n const { address, family } = await dns.lookup(parsedUrl.hostname);\n const type = family === 6 ? 'ipv6' : 'ipv4';\n if (SSRF_BLOCK_LIST.check(address, type)) {\n throw new ApplicationError(`URL resolves to a blocked address: ${url}`);\n }\n } catch (error) {\n if (error instanceof ApplicationError) throw error;\n throw new ApplicationError(`Could not resolve hostname: ${parsedUrl.hostname}`);\n }\n\n // Fetch the URL with timeout\n let response: Response;\n try {\n response = await fetch(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });\n } catch (error) {\n if (error instanceof Error && error.name === 'TimeoutError') {\n throw new ApplicationError(`Request timed out while fetching URL: ${url}`);\n }\n throw error;\n }\n\n if (!response.ok) {\n throw new ApplicationError(\n `Failed to fetch URL: ${url} (${response.status} ${response.statusText})`\n );\n }\n\n // Check Content-Length header for early rejection of large files\n if (sizeLimit) {\n const contentLength = response.headers.get('content-length');\n if (contentLength && parseInt(contentLength, 10) > sizeLimit) {\n throw new ApplicationError(\n `File too large: maximum allowed size is ${Math.round(sizeLimit / (1024 * 1024))}MB`\n );\n }\n }\n\n // Get content type and filename\n const contentType =\n response.headers.get('content-type')?.split(';')[0] || 'application/octet-stream';\n const contentDisposition = response.headers.get('content-disposition');\n const filename = getFilenameFromUrl(response.url, contentDisposition);\n\n // Read response body\n const arrayBuffer = await response.arrayBuffer();\n const buffer = Buffer.from(arrayBuffer);\n\n // Write to temp file\n const tmpFilePath = path.join(tmpWorkingDirectory, filename);\n await fse.writeFile(tmpFilePath, buffer);\n\n // Create file object compatible with upload pipeline\n const fetchedFile: UrlFetchedFile = {\n filepath: tmpFilePath,\n originalFilename: filename,\n mimetype: contentType,\n size: buffer.length,\n tmpWorkingDirectory,\n };\n\n return { file: fetchedFile };\n};\n\nconst getFolderPath = async (folderId?: number | null) => {\n if (!folderId) return '/';\n\n const parentFolder = await strapi.db.query(FOLDER_MODEL_UID).findOne({ where: { id: folderId } });\n\n return parentFolder.path;\n};\n\nconst deleteByIds = async (ids: number[] = []) => {\n const filesToDelete = await strapi.db\n .query(FILE_MODEL_UID)\n .findMany({ where: { id: { $in: ids } } });\n\n await Promise.all(filesToDelete.map((file: File) => getService('upload').remove(file)));\n\n return filesToDelete;\n};\n\nconst signFileUrls = async (file: File) => {\n const { provider } = strapi.plugins.upload;\n const { provider: providerConfig } = strapi.config.get<Config>('plugin::upload');\n const isPrivate = await provider.isPrivate();\n file.isUrlSigned = false;\n\n // Check file provider and if provider is private\n if (file.provider !== providerConfig || !isPrivate) {\n return file;\n }\n\n const signUrl = async (file: File) => {\n const signedUrl = await provider.getSignedUrl(file);\n file.url = signedUrl.url;\n file.isUrlSigned = true;\n };\n\n const signedFile = cloneDeep(file);\n\n // Sign each file format\n await signUrl(signedFile);\n if (file.formats) {\n await async.map(Object.values(signedFile.formats ?? {}), signUrl);\n }\n\n return signedFile;\n};\n\nexport type { UrlFetchedFile, FetchUrlResult };\nexport default { getFolderPath, deleteByIds, signFileUrls, fetchUrlToInputFile };\n"],"names":["ApplicationError","errors","FETCH_TIMEOUT_MS","SSRF_BLOCK_LIST","net","BlockList","addSubnet","getFilenameFromUrl","url","contentDisposition","filenameMatch","match","path","basename","decodeURIComponent","urlObj","URL","pathname","filename","split","pop","length","now","Date","date","toISOString","time","toTimeString","replace","fetchUrlToInputFile","tmpWorkingDirectory","sizeLimit","parsedUrl","includes","protocol","address","family","dns","lookup","hostname","type","check","error","response","fetch","signal","AbortSignal","timeout","Error","name","ok","status","statusText","contentLength","headers","get","parseInt","Math","round","contentType","arrayBuffer","buffer","Buffer","from","tmpFilePath","join","fse","writeFile","fetchedFile","filepath","originalFilename","mimetype","size","file","getFolderPath","folderId","parentFolder","strapi","db","query","FOLDER_MODEL_UID","findOne","where","id","deleteByIds","ids","filesToDelete","FILE_MODEL_UID","findMany","$in","Promise","all","map","getService","remove","signFileUrls","provider","plugins","upload","providerConfig","config","isPrivate","isUrlSigned","signUrl","signedUrl","getSignedUrl","signedFile","cloneDeep","formats","async","Object","values"],"mappings":"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"}
|
|
@@ -1,8 +1,126 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import dns from 'dns/promises';
|
|
3
|
+
import net from 'net';
|
|
4
|
+
import fse from 'fs-extra';
|
|
1
5
|
import { cloneDeep } from 'lodash/fp';
|
|
2
|
-
import { async } from '@strapi/utils';
|
|
3
|
-
import {
|
|
6
|
+
import { errors, async } from '@strapi/utils';
|
|
7
|
+
import { FILE_MODEL_UID, FOLDER_MODEL_UID } from '../constants.mjs';
|
|
4
8
|
import { getService } from '../utils/index.mjs';
|
|
5
9
|
|
|
10
|
+
const { ApplicationError } = errors;
|
|
11
|
+
const FETCH_TIMEOUT_MS = 60000; // 60 seconds
|
|
12
|
+
// Blocks loopback, link-local (cloud metadata), and RFC-1918 private ranges to prevent SSRF
|
|
13
|
+
const SSRF_BLOCK_LIST = new net.BlockList();
|
|
14
|
+
SSRF_BLOCK_LIST.addSubnet('127.0.0.0', 8); // loopback
|
|
15
|
+
SSRF_BLOCK_LIST.addSubnet('10.0.0.0', 8); // RFC-1918
|
|
16
|
+
SSRF_BLOCK_LIST.addSubnet('172.16.0.0', 12); // RFC-1918
|
|
17
|
+
SSRF_BLOCK_LIST.addSubnet('192.168.0.0', 16); // RFC-1918
|
|
18
|
+
SSRF_BLOCK_LIST.addSubnet('169.254.0.0', 16); // link-local / cloud metadata (AWS, GCP, Azure)
|
|
19
|
+
SSRF_BLOCK_LIST.addSubnet('::1', 128, 'ipv6'); // IPv6 loopback
|
|
20
|
+
SSRF_BLOCK_LIST.addSubnet('fc00::', 7, 'ipv6'); // IPv6 unique local
|
|
21
|
+
SSRF_BLOCK_LIST.addSubnet('fe80::', 10, 'ipv6'); // IPv6 link-local
|
|
22
|
+
/**
|
|
23
|
+
* Extracts filename from a URL path or Content-Disposition header
|
|
24
|
+
*/ const getFilenameFromUrl = (url, contentDisposition)=>{
|
|
25
|
+
// Try Content-Disposition header first
|
|
26
|
+
if (contentDisposition) {
|
|
27
|
+
// Extracts filename from Content-Disposition header (e.g. filename="photo.jpg" or filename*=UTF-8''photo.jpg)
|
|
28
|
+
const filenameMatch = contentDisposition.match(/filename\*?=['"]?(?:UTF-\d['"]*)?([^;\r\n"']*)['"]?/i);
|
|
29
|
+
if (filenameMatch?.[1]) {
|
|
30
|
+
// Use path.basename to prevent path traversal attacks
|
|
31
|
+
return path.basename(decodeURIComponent(filenameMatch[1]));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// Fall back to URL path
|
|
35
|
+
try {
|
|
36
|
+
const urlObj = new URL(url);
|
|
37
|
+
const pathname = urlObj.pathname;
|
|
38
|
+
const filename = pathname.split('/').pop();
|
|
39
|
+
if (filename && filename.length > 0) {
|
|
40
|
+
// Use path.basename to prevent path traversal attacks (e.g., URL-encoded separators)
|
|
41
|
+
return path.basename(decodeURIComponent(filename));
|
|
42
|
+
}
|
|
43
|
+
} catch {
|
|
44
|
+
// Invalid URL, use default
|
|
45
|
+
}
|
|
46
|
+
// Generate a timestamp-based default filename
|
|
47
|
+
const now = new Date();
|
|
48
|
+
const date = now.toISOString().split('T')[0]; // 2024-02-23
|
|
49
|
+
const time = now.toTimeString().split(' ')[0].replace(/:/g, ''); // 143052
|
|
50
|
+
return `untitled_${date}_${time}`;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Fetches a URL and saves it as a temporary file
|
|
54
|
+
* Returns an InputFile-compatible object for use with the upload pipeline
|
|
55
|
+
*/ const fetchUrlToInputFile = async (url, tmpWorkingDirectory, sizeLimit)=>{
|
|
56
|
+
// Validate URL protocol
|
|
57
|
+
let parsedUrl;
|
|
58
|
+
try {
|
|
59
|
+
parsedUrl = new URL(url);
|
|
60
|
+
} catch {
|
|
61
|
+
throw new ApplicationError(`Invalid URL: ${url}`);
|
|
62
|
+
}
|
|
63
|
+
if (![
|
|
64
|
+
'http:',
|
|
65
|
+
'https:'
|
|
66
|
+
].includes(parsedUrl.protocol)) {
|
|
67
|
+
throw new ApplicationError(`Invalid URL protocol. Only http and https are allowed: ${url}`);
|
|
68
|
+
}
|
|
69
|
+
// Resolve hostname and block private/internal IP ranges to prevent SSRF
|
|
70
|
+
try {
|
|
71
|
+
const { address, family } = await dns.lookup(parsedUrl.hostname);
|
|
72
|
+
const type = family === 6 ? 'ipv6' : 'ipv4';
|
|
73
|
+
if (SSRF_BLOCK_LIST.check(address, type)) {
|
|
74
|
+
throw new ApplicationError(`URL resolves to a blocked address: ${url}`);
|
|
75
|
+
}
|
|
76
|
+
} catch (error) {
|
|
77
|
+
if (error instanceof ApplicationError) throw error;
|
|
78
|
+
throw new ApplicationError(`Could not resolve hostname: ${parsedUrl.hostname}`);
|
|
79
|
+
}
|
|
80
|
+
// Fetch the URL with timeout
|
|
81
|
+
let response;
|
|
82
|
+
try {
|
|
83
|
+
response = await fetch(url, {
|
|
84
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
85
|
+
});
|
|
86
|
+
} catch (error) {
|
|
87
|
+
if (error instanceof Error && error.name === 'TimeoutError') {
|
|
88
|
+
throw new ApplicationError(`Request timed out while fetching URL: ${url}`);
|
|
89
|
+
}
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
if (!response.ok) {
|
|
93
|
+
throw new ApplicationError(`Failed to fetch URL: ${url} (${response.status} ${response.statusText})`);
|
|
94
|
+
}
|
|
95
|
+
// Check Content-Length header for early rejection of large files
|
|
96
|
+
if (sizeLimit) {
|
|
97
|
+
const contentLength = response.headers.get('content-length');
|
|
98
|
+
if (contentLength && parseInt(contentLength, 10) > sizeLimit) {
|
|
99
|
+
throw new ApplicationError(`File too large: maximum allowed size is ${Math.round(sizeLimit / (1024 * 1024))}MB`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Get content type and filename
|
|
103
|
+
const contentType = response.headers.get('content-type')?.split(';')[0] || 'application/octet-stream';
|
|
104
|
+
const contentDisposition = response.headers.get('content-disposition');
|
|
105
|
+
const filename = getFilenameFromUrl(response.url, contentDisposition);
|
|
106
|
+
// Read response body
|
|
107
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
108
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
109
|
+
// Write to temp file
|
|
110
|
+
const tmpFilePath = path.join(tmpWorkingDirectory, filename);
|
|
111
|
+
await fse.writeFile(tmpFilePath, buffer);
|
|
112
|
+
// Create file object compatible with upload pipeline
|
|
113
|
+
const fetchedFile = {
|
|
114
|
+
filepath: tmpFilePath,
|
|
115
|
+
originalFilename: filename,
|
|
116
|
+
mimetype: contentType,
|
|
117
|
+
size: buffer.length,
|
|
118
|
+
tmpWorkingDirectory
|
|
119
|
+
};
|
|
120
|
+
return {
|
|
121
|
+
file: fetchedFile
|
|
122
|
+
};
|
|
123
|
+
};
|
|
6
124
|
const getFolderPath = async (folderId)=>{
|
|
7
125
|
if (!folderId) return '/';
|
|
8
126
|
const parentFolder = await strapi.db.query(FOLDER_MODEL_UID).findOne({
|
|
@@ -48,7 +166,8 @@ const signFileUrls = async (file)=>{
|
|
|
48
166
|
var file = {
|
|
49
167
|
getFolderPath,
|
|
50
168
|
deleteByIds,
|
|
51
|
-
signFileUrls
|
|
169
|
+
signFileUrls,
|
|
170
|
+
fetchUrlToInputFile
|
|
52
171
|
};
|
|
53
172
|
|
|
54
173
|
export { file as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file.mjs","sources":["../../../server/src/services/file.ts"],"sourcesContent":["import { cloneDeep } from 'lodash/fp';\nimport { async } from '@strapi/utils';\n\nimport { FOLDER_MODEL_UID, FILE_MODEL_UID } from '../constants';\nimport { getService } from '../utils';\n\nimport { Config, type File } from '../types';\n\nconst getFolderPath = async (folderId?: number | null) => {\n if (!folderId) return '/';\n\n const parentFolder = await strapi.db.query(FOLDER_MODEL_UID).findOne({ where: { id: folderId } });\n\n return parentFolder.path;\n};\n\nconst deleteByIds = async (ids: number[] = []) => {\n const filesToDelete = await strapi.db\n .query(FILE_MODEL_UID)\n .findMany({ where: { id: { $in: ids } } });\n\n await Promise.all(filesToDelete.map((file: File) => getService('upload').remove(file)));\n\n return filesToDelete;\n};\n\nconst signFileUrls = async (file: File) => {\n const { provider } = strapi.plugins.upload;\n const { provider: providerConfig } = strapi.config.get<Config>('plugin::upload');\n const isPrivate = await provider.isPrivate();\n file.isUrlSigned = false;\n\n // Check file provider and if provider is private\n if (file.provider !== providerConfig || !isPrivate) {\n return file;\n }\n\n const signUrl = async (file: File) => {\n const signedUrl = await provider.getSignedUrl(file);\n file.url = signedUrl.url;\n file.isUrlSigned = true;\n };\n\n const signedFile = cloneDeep(file);\n\n // Sign each file format\n await signUrl(signedFile);\n if (file.formats) {\n await async.map(Object.values(signedFile.formats ?? {}), signUrl);\n }\n\n return signedFile;\n};\n\nexport default { getFolderPath, deleteByIds, signFileUrls };\n"],"names":["getFolderPath","folderId","parentFolder","strapi","db","query","FOLDER_MODEL_UID","findOne","where","id","path","deleteByIds","ids","filesToDelete","FILE_MODEL_UID","findMany","$in","Promise","all","map","file","getService","remove","signFileUrls","provider","plugins","upload","providerConfig","config","get","isPrivate","isUrlSigned","signUrl","signedUrl","getSignedUrl","url","signedFile","cloneDeep","formats","async","Object","values"],"mappings":";;;;;AAQA,MAAMA,gBAAgB,OAAOC,QAAAA,GAAAA;IAC3B,IAAI,CAACA,UAAU,OAAO,GAAA;IAEtB,MAAMC,YAAAA,GAAe,MAAMC,MAAOC,CAAAA,EAAE,CAACC,KAAK,CAACC,gBAAkBC,CAAAA,CAAAA,OAAO,CAAC;QAAEC,KAAO,EAAA;YAAEC,EAAIR,EAAAA;AAAS;AAAE,KAAA,CAAA;AAE/F,IAAA,OAAOC,aAAaQ,IAAI;AAC1B,CAAA;AAEA,MAAMC,WAAAA,GAAc,OAAOC,GAAAA,GAAgB,EAAE,GAAA;IAC3C,MAAMC,aAAAA,GAAgB,MAAMV,MAAOC,CAAAA,EAAE,CAClCC,KAAK,CAACS,cACNC,CAAAA,CAAAA,QAAQ,CAAC;QAAEP,KAAO,EAAA;YAAEC,EAAI,EAAA;gBAAEO,GAAKJ,EAAAA;AAAI;AAAE;AAAE,KAAA,CAAA;IAE1C,MAAMK,OAAAA,CAAQC,GAAG,CAACL,aAAcM,CAAAA,GAAG,CAAC,CAACC,IAAeC,GAAAA,UAAAA,CAAW,QAAUC,CAAAA,CAAAA,MAAM,CAACF,IAAAA,CAAAA,CAAAA,CAAAA;IAEhF,OAAOP,aAAAA;AACT,CAAA;AAEA,MAAMU,eAAe,OAAOH,IAAAA,GAAAA;AAC1B,IAAA,MAAM,EAAEI,QAAQ,EAAE,GAAGrB,MAAOsB,CAAAA,OAAO,CAACC,MAAM;IAC1C,MAAM,EAAEF,UAAUG,cAAc,EAAE,GAAGxB,MAAOyB,CAAAA,MAAM,CAACC,GAAG,CAAS,gBAAA,CAAA;IAC/D,MAAMC,SAAAA,GAAY,MAAMN,QAAAA,CAASM,SAAS,EAAA;AAC1CV,IAAAA,IAAAA,CAAKW,WAAW,GAAG,KAAA;;AAGnB,IAAA,IAAIX,IAAKI,CAAAA,QAAQ,KAAKG,cAAAA,IAAkB,CAACG,SAAW,EAAA;QAClD,OAAOV,IAAAA;AACT;AAEA,IAAA,MAAMY,UAAU,OAAOZ,IAAAA,GAAAA;AACrB,QAAA,MAAMa,SAAY,GAAA,MAAMT,QAASU,CAAAA,YAAY,CAACd,IAAAA,CAAAA;QAC9CA,IAAKe,CAAAA,GAAG,GAAGF,SAAAA,CAAUE,GAAG;AACxBf,QAAAA,IAAAA,CAAKW,WAAW,GAAG,IAAA;AACrB,KAAA;AAEA,IAAA,MAAMK,aAAaC,SAAUjB,CAAAA,IAAAA,CAAAA;;AAG7B,IAAA,MAAMY,OAAQI,CAAAA,UAAAA,CAAAA;IACd,IAAIhB,IAAAA,CAAKkB,OAAO,EAAE;QAChB,MAAMC,KAAAA,CAAMpB,GAAG,CAACqB,MAAOC,CAAAA,MAAM,CAACL,UAAWE,CAAAA,OAAO,IAAI,EAAKN,CAAAA,EAAAA,OAAAA,CAAAA;AAC3D;IAEA,OAAOI,UAAAA;AACT,CAAA;AAEA,WAAe;AAAEpC,IAAAA,aAAAA;AAAeW,IAAAA,WAAAA;AAAaY,IAAAA;AAAa,CAAE;;;;"}
|
|
1
|
+
{"version":3,"file":"file.mjs","sources":["../../../server/src/services/file.ts"],"sourcesContent":["import path from 'path';\nimport dns from 'dns/promises';\nimport net from 'net';\nimport fse from 'fs-extra';\nimport { cloneDeep } from 'lodash/fp';\nimport { async, errors } from '@strapi/utils';\n\nimport { FOLDER_MODEL_UID, FILE_MODEL_UID } from '../constants';\nimport { getService } from '../utils';\n\nimport { Config, type File } from '../types';\n\nconst { ApplicationError } = errors;\n\nconst FETCH_TIMEOUT_MS = 60_000; // 60 seconds\n\n// Blocks loopback, link-local (cloud metadata), and RFC-1918 private ranges to prevent SSRF\nconst SSRF_BLOCK_LIST = new net.BlockList();\nSSRF_BLOCK_LIST.addSubnet('127.0.0.0', 8); // loopback\nSSRF_BLOCK_LIST.addSubnet('10.0.0.0', 8); // RFC-1918\nSSRF_BLOCK_LIST.addSubnet('172.16.0.0', 12); // RFC-1918\nSSRF_BLOCK_LIST.addSubnet('192.168.0.0', 16); // RFC-1918\nSSRF_BLOCK_LIST.addSubnet('169.254.0.0', 16); // link-local / cloud metadata (AWS, GCP, Azure)\nSSRF_BLOCK_LIST.addSubnet('::1', 128, 'ipv6'); // IPv6 loopback\nSSRF_BLOCK_LIST.addSubnet('fc00::', 7, 'ipv6'); // IPv6 unique local\nSSRF_BLOCK_LIST.addSubnet('fe80::', 10, 'ipv6'); // IPv6 link-local\n\n/**\n * Represents a file fetched from a URL, compatible with the upload pipeline\n */\ninterface UrlFetchedFile {\n filepath: string;\n originalFilename: string;\n mimetype: string;\n size: number;\n tmpWorkingDirectory?: string;\n}\n\ninterface FetchUrlResult {\n file: UrlFetchedFile;\n}\n\n/**\n * Extracts filename from a URL path or Content-Disposition header\n */\nconst getFilenameFromUrl = (url: string, contentDisposition?: string | null): string => {\n // Try Content-Disposition header first\n if (contentDisposition) {\n // Extracts filename from Content-Disposition header (e.g. filename=\"photo.jpg\" or filename*=UTF-8''photo.jpg)\n const filenameMatch = contentDisposition.match(\n /filename\\*?=['\"]?(?:UTF-\\d['\"]*)?([^;\\r\\n\"']*)['\"]?/i\n );\n if (filenameMatch?.[1]) {\n // Use path.basename to prevent path traversal attacks\n return path.basename(decodeURIComponent(filenameMatch[1]));\n }\n }\n\n // Fall back to URL path\n try {\n const urlObj = new URL(url);\n const pathname = urlObj.pathname;\n const filename = pathname.split('/').pop();\n if (filename && filename.length > 0) {\n // Use path.basename to prevent path traversal attacks (e.g., URL-encoded separators)\n return path.basename(decodeURIComponent(filename));\n }\n } catch {\n // Invalid URL, use default\n }\n\n // Generate a timestamp-based default filename\n const now = new Date();\n const date = now.toISOString().split('T')[0]; // 2024-02-23\n const time = now.toTimeString().split(' ')[0].replace(/:/g, ''); // 143052\n return `untitled_${date}_${time}`;\n};\n\n/**\n * Fetches a URL and saves it as a temporary file\n * Returns an InputFile-compatible object for use with the upload pipeline\n */\nconst fetchUrlToInputFile = async (\n url: string,\n tmpWorkingDirectory: string,\n sizeLimit?: number\n): Promise<FetchUrlResult> => {\n // Validate URL protocol\n let parsedUrl: URL;\n try {\n parsedUrl = new URL(url);\n } catch {\n throw new ApplicationError(`Invalid URL: ${url}`);\n }\n\n if (!['http:', 'https:'].includes(parsedUrl.protocol)) {\n throw new ApplicationError(`Invalid URL protocol. Only http and https are allowed: ${url}`);\n }\n\n // Resolve hostname and block private/internal IP ranges to prevent SSRF\n try {\n const { address, family } = await dns.lookup(parsedUrl.hostname);\n const type = family === 6 ? 'ipv6' : 'ipv4';\n if (SSRF_BLOCK_LIST.check(address, type)) {\n throw new ApplicationError(`URL resolves to a blocked address: ${url}`);\n }\n } catch (error) {\n if (error instanceof ApplicationError) throw error;\n throw new ApplicationError(`Could not resolve hostname: ${parsedUrl.hostname}`);\n }\n\n // Fetch the URL with timeout\n let response: Response;\n try {\n response = await fetch(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });\n } catch (error) {\n if (error instanceof Error && error.name === 'TimeoutError') {\n throw new ApplicationError(`Request timed out while fetching URL: ${url}`);\n }\n throw error;\n }\n\n if (!response.ok) {\n throw new ApplicationError(\n `Failed to fetch URL: ${url} (${response.status} ${response.statusText})`\n );\n }\n\n // Check Content-Length header for early rejection of large files\n if (sizeLimit) {\n const contentLength = response.headers.get('content-length');\n if (contentLength && parseInt(contentLength, 10) > sizeLimit) {\n throw new ApplicationError(\n `File too large: maximum allowed size is ${Math.round(sizeLimit / (1024 * 1024))}MB`\n );\n }\n }\n\n // Get content type and filename\n const contentType =\n response.headers.get('content-type')?.split(';')[0] || 'application/octet-stream';\n const contentDisposition = response.headers.get('content-disposition');\n const filename = getFilenameFromUrl(response.url, contentDisposition);\n\n // Read response body\n const arrayBuffer = await response.arrayBuffer();\n const buffer = Buffer.from(arrayBuffer);\n\n // Write to temp file\n const tmpFilePath = path.join(tmpWorkingDirectory, filename);\n await fse.writeFile(tmpFilePath, buffer);\n\n // Create file object compatible with upload pipeline\n const fetchedFile: UrlFetchedFile = {\n filepath: tmpFilePath,\n originalFilename: filename,\n mimetype: contentType,\n size: buffer.length,\n tmpWorkingDirectory,\n };\n\n return { file: fetchedFile };\n};\n\nconst getFolderPath = async (folderId?: number | null) => {\n if (!folderId) return '/';\n\n const parentFolder = await strapi.db.query(FOLDER_MODEL_UID).findOne({ where: { id: folderId } });\n\n return parentFolder.path;\n};\n\nconst deleteByIds = async (ids: number[] = []) => {\n const filesToDelete = await strapi.db\n .query(FILE_MODEL_UID)\n .findMany({ where: { id: { $in: ids } } });\n\n await Promise.all(filesToDelete.map((file: File) => getService('upload').remove(file)));\n\n return filesToDelete;\n};\n\nconst signFileUrls = async (file: File) => {\n const { provider } = strapi.plugins.upload;\n const { provider: providerConfig } = strapi.config.get<Config>('plugin::upload');\n const isPrivate = await provider.isPrivate();\n file.isUrlSigned = false;\n\n // Check file provider and if provider is private\n if (file.provider !== providerConfig || !isPrivate) {\n return file;\n }\n\n const signUrl = async (file: File) => {\n const signedUrl = await provider.getSignedUrl(file);\n file.url = signedUrl.url;\n file.isUrlSigned = true;\n };\n\n const signedFile = cloneDeep(file);\n\n // Sign each file format\n await signUrl(signedFile);\n if (file.formats) {\n await async.map(Object.values(signedFile.formats ?? {}), signUrl);\n }\n\n return signedFile;\n};\n\nexport type { UrlFetchedFile, FetchUrlResult };\nexport default { getFolderPath, deleteByIds, signFileUrls, fetchUrlToInputFile };\n"],"names":["ApplicationError","errors","FETCH_TIMEOUT_MS","SSRF_BLOCK_LIST","net","BlockList","addSubnet","getFilenameFromUrl","url","contentDisposition","filenameMatch","match","path","basename","decodeURIComponent","urlObj","URL","pathname","filename","split","pop","length","now","Date","date","toISOString","time","toTimeString","replace","fetchUrlToInputFile","tmpWorkingDirectory","sizeLimit","parsedUrl","includes","protocol","address","family","dns","lookup","hostname","type","check","error","response","fetch","signal","AbortSignal","timeout","Error","name","ok","status","statusText","contentLength","headers","get","parseInt","Math","round","contentType","arrayBuffer","buffer","Buffer","from","tmpFilePath","join","fse","writeFile","fetchedFile","filepath","originalFilename","mimetype","size","file","getFolderPath","folderId","parentFolder","strapi","db","query","FOLDER_MODEL_UID","findOne","where","id","deleteByIds","ids","filesToDelete","FILE_MODEL_UID","findMany","$in","Promise","all","map","getService","remove","signFileUrls","provider","plugins","upload","providerConfig","config","isPrivate","isUrlSigned","signUrl","signedUrl","getSignedUrl","signedFile","cloneDeep","formats","async","Object","values"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"folder.js","sources":["../../../server/src/services/folder.ts"],"sourcesContent":["import { sortBy, map, isUndefined } from 'lodash/fp';\nimport { strings, setCreatorFields } from '@strapi/utils';\nimport { FOLDER_MODEL_UID, FILE_MODEL_UID } from '../constants';\nimport { getService } from '../utils';\n\nimport type { File, Folder } from '../types';\n\ntype FolderMap = {\n [key: string]: Partial<Folder> & {\n children: FolderNode[];\n };\n};\n\ntype FolderNode = Partial<Folder> & {\n children: FolderNode[];\n};\n\nconst setPathIdAndPath = async (folder: Pick<Folder, 'parent'>) => {\n const { max } = await strapi.db\n .queryBuilder(FOLDER_MODEL_UID)\n .max('pathId')\n .first()\n .execute<{ max: number }>();\n\n const pathId = max + 1;\n let parentPath = '/';\n if (folder.parent) {\n const parentFolder = await strapi.db\n .query(FOLDER_MODEL_UID)\n .findOne({ where: { id: folder.parent } });\n\n parentPath = parentFolder.path;\n }\n\n return Object.assign(folder, {\n pathId,\n path: strings.joinBy('/', parentPath, `${pathId}`),\n });\n};\n\nconst create = async (\n folderData: Pick<Folder, 'name' | 'parent'>,\n opts?: { user: { id: string | number } }\n) => {\n const folderService = getService('folder');\n\n const { user } = opts || {};\n\n let enrichedFolder = await folderService.setPathIdAndPath(folderData);\n if (user) {\n enrichedFolder = await setCreatorFields({ user })(enrichedFolder);\n }\n\n const folder = await strapi.db.query(FOLDER_MODEL_UID).create({ data: enrichedFolder });\n\n strapi.eventHub.emit('media-folder.create', { folder });\n\n return folder;\n};\n\n/**\n * Recursively delete folders and included files\n * @param ids ids of the folders to delete\n * @returns {Promise<Object[]>}\n */\nconst deleteByIds = async (ids = []) => {\n const folders = await strapi.db.query(FOLDER_MODEL_UID).findMany({ where: { id: { $in: ids } } });\n if (folders.length === 0) {\n return {\n folders: [],\n totalFolderNumber: 0,\n totalFileNumber: 0,\n };\n }\n\n const pathsToDelete = map('path', folders);\n\n // delete files\n const filesToDelete = await strapi.db.query(FILE_MODEL_UID).findMany({\n where: {\n $or: pathsToDelete.flatMap((path) => [\n { folderPath: { $eq: path } },\n { folderPath: { $startsWith: `${path}/` } },\n ]),\n },\n });\n\n await Promise.all(filesToDelete.map((file: File) => getService('upload').remove(file)));\n\n // delete folders and subfolders\n const { count: totalFolderNumber } = await strapi.db.query(FOLDER_MODEL_UID).deleteMany({\n where: {\n $or: pathsToDelete.flatMap((path) => [\n { path: { $eq: path } },\n { path: { $startsWith: `${path}/` } },\n ]),\n },\n });\n\n strapi.eventHub.emit('media-folder.delete', { folders });\n\n return {\n folders,\n totalFolderNumber,\n totalFileNumber: filesToDelete.length,\n };\n};\n\n/**\n * Update name and location of a folder and its belonging folders and files\n */\nconst update = async (\n id: number,\n {\n name,\n parent,\n }: {\n name: string;\n parent: number | null;\n },\n { user }: { user: { id: string | number } }\n) => {\n // only name is updated\n if (isUndefined(parent)) {\n const existingFolder = await strapi.db.query(FOLDER_MODEL_UID).findOne({ where: { id } });\n\n if (!existingFolder) {\n return undefined;\n }\n\n const newFolder = setCreatorFields({ user, isEdition: true })({ name, parent });\n\n if (isUndefined(parent)) {\n const folder = await strapi.db\n .query(FOLDER_MODEL_UID)\n .update({ where: { id }, data: newFolder });\n\n return folder;\n }\n // location is updated => using transaction\n } else {\n const trx = await strapi.db.transaction();\n try {\n // fetch existing folder\n const existingFolder = await strapi.db\n .queryBuilder(FOLDER_MODEL_UID)\n .select(['pathId', 'path'])\n .where({ id })\n .transacting(trx.get())\n .forUpdate()\n .first()\n .execute<Folder>();\n\n // update parent folder (delete + insert; upsert not possible)\n // @ts-expect-error - no dynamic types\n const { joinTable } = strapi.db.metadata.get(FOLDER_MODEL_UID).attributes.parent;\n await strapi.db\n .queryBuilder(joinTable.name)\n .transacting(trx.get())\n .delete()\n .where({ [joinTable.joinColumn.name]: id })\n .execute();\n\n if (parent !== null) {\n await strapi.db\n .queryBuilder(joinTable.name)\n .transacting(trx.get())\n .insert({ [joinTable.inverseJoinColumn.name]: parent, [joinTable.joinColumn.name]: id })\n .where({ [joinTable.joinColumn.name]: id })\n .execute();\n }\n\n // fetch destinationFolder path\n let destinationFolderPath = '/';\n if (parent !== null) {\n const destinationFolder = await strapi.db\n .queryBuilder(FOLDER_MODEL_UID)\n .select('path')\n .where({ id: parent })\n .transacting(trx.get())\n .first()\n .execute<Folder>();\n destinationFolderPath = destinationFolder.path;\n }\n\n const folderTable = strapi.getModel(FOLDER_MODEL_UID).collectionName;\n const fileTable = strapi.getModel(FILE_MODEL_UID).collectionName;\n const folderPathColumnName =\n // @ts-expect-error - no dynamic types\n strapi.db.metadata.get(FILE_MODEL_UID).attributes.folderPath.columnName;\n // @ts-expect-error - no dynamic types\n const pathColumnName = strapi.db.metadata.get(FOLDER_MODEL_UID).attributes.path.columnName;\n\n // update folders below\n await strapi.db\n .getConnection(folderTable)\n .transacting(trx.get())\n .where(pathColumnName, existingFolder.path)\n .orWhere(pathColumnName, 'like', `${existingFolder.path}/%`)\n .update(\n pathColumnName,\n strapi.db.connection.raw('REPLACE(??, ?, ?)', [\n pathColumnName,\n existingFolder.path,\n strings.joinBy('/', destinationFolderPath, `${existingFolder.pathId}`),\n ])\n );\n\n // update files below\n await strapi.db\n .getConnection(fileTable)\n .transacting(trx.get())\n .where(folderPathColumnName, existingFolder.path)\n .orWhere(folderPathColumnName, 'like', `${existingFolder.path}/%`)\n .update(\n folderPathColumnName,\n strapi.db.connection.raw('REPLACE(??, ?, ?)', [\n folderPathColumnName,\n existingFolder.path,\n strings.joinBy('/', destinationFolderPath, `${existingFolder.pathId}`),\n ])\n );\n\n await trx.commit();\n } catch (e) {\n await trx.rollback();\n throw e;\n }\n\n // update less critical information (name + updatedBy)\n const newFolder = setCreatorFields({ user, isEdition: true })({ name });\n\n const folder = await strapi.db\n .query(FOLDER_MODEL_UID)\n .update({ where: { id }, data: newFolder });\n\n strapi.eventHub.emit('media-folder.update', { folder });\n return folder;\n }\n};\n\n/**\n * Check if a folder exists in database\n * @param params query params to find the folder\n * @returns {Promise<boolean>}\n */\nconst exists = async (params = {}) => {\n const count = await strapi.db.query(FOLDER_MODEL_UID).count({ where: params });\n return count > 0;\n};\n\n/**\n * Returns the nested structure of folders\n * @returns {Promise<array>}\n */\nconst getStructure = async () => {\n // @ts-expect-error - no dynamic types\n const { joinTable } = strapi.db.metadata.get(FOLDER_MODEL_UID).attributes.parent;\n const qb = strapi.db.queryBuilder(FOLDER_MODEL_UID);\n const alias = qb.getAlias();\n const folders = (await qb\n .select(['id', 'name', `${alias}.${joinTable.inverseJoinColumn.name} as parent`])\n .join({\n alias,\n referencedTable: joinTable.name,\n referencedColumn: joinTable.joinColumn.name,\n rootColumn: joinTable.joinColumn.referencedColumn,\n rootTable: qb.alias,\n })\n .execute({ mapResults: false })) as Folder[];\n\n const folderMap: FolderMap = {\n null: { children: [] },\n };\n\n folders.forEach((f) => {\n folderMap[f.id] = { ...f, children: [] };\n });\n\n folders.forEach((f) => {\n const parentId = f.parent || 'null';\n\n if (!folderMap[parentId]) {\n folderMap[parentId] = { children: [] };\n }\n\n folderMap[parentId].children.push(folderMap[f.id]);\n folderMap[parentId].children = sortBy('name', folderMap[parentId].children);\n delete folderMap[f.id].parent;\n });\n\n return folderMap.null.children;\n};\n\nexport default {\n create,\n exists,\n deleteByIds,\n update,\n setPathIdAndPath,\n getStructure,\n};\n"],"names":["setPathIdAndPath","folder","max","strapi","db","queryBuilder","FOLDER_MODEL_UID","first","execute","pathId","parentPath","parent","parentFolder","query","findOne","where","id","path","Object","assign","strings","joinBy","create","folderData","opts","folderService","getService","user","enrichedFolder","setCreatorFields","data","eventHub","emit","deleteByIds","ids","folders","findMany","$in","length","totalFolderNumber","totalFileNumber","pathsToDelete","map","filesToDelete","FILE_MODEL_UID","$or","flatMap","folderPath","$eq","$startsWith","Promise","all","file","remove","count","deleteMany","update","name","isUndefined","existingFolder","undefined","newFolder","isEdition","trx","transaction","select","transacting","get","forUpdate","joinTable","metadata","attributes","delete","joinColumn","insert","inverseJoinColumn","destinationFolderPath","destinationFolder","folderTable","getModel","collectionName","fileTable","folderPathColumnName","columnName","pathColumnName","getConnection","orWhere","connection","raw","commit","e","rollback","exists","params","getStructure","qb","alias","getAlias","join","referencedTable","referencedColumn","rootColumn","rootTable","mapResults","folderMap","null","children","forEach","f","parentId","push","sortBy"],"mappings":";;;;;;;AAiBA,MAAMA,mBAAmB,OAAOC,MAAAA,GAAAA;AAC9B,IAAA,MAAM,EAAEC,GAAG,EAAE,GAAG,MAAMC,OAAOC,EAAE,CAC5BC,YAAY,CAACC,4BACbJ,GAAG,CAAC,QACJK,CAAAA,CAAAA,KAAK,GACLC,OAAO,EAAA;AAEV,IAAA,MAAMC,SAASP,GAAM,GAAA,CAAA;AACrB,IAAA,IAAIQ,UAAa,GAAA,GAAA;IACjB,IAAIT,MAAAA,CAAOU,MAAM,EAAE;QACjB,MAAMC,YAAAA,GAAe,MAAMT,MAAOC,CAAAA,EAAE,CACjCS,KAAK,CAACP,0BACNQ,CAAAA,CAAAA,OAAO,CAAC;YAAEC,KAAO,EAAA;AAAEC,gBAAAA,EAAAA,EAAIf,OAAOU;AAAO;AAAE,SAAA,CAAA;AAE1CD,QAAAA,UAAAA,GAAaE,aAAaK,IAAI;AAChC;IAEA,OAAOC,MAAAA,CAAOC,MAAM,CAAClB,MAAQ,EAAA;AAC3BQ,QAAAA,MAAAA;AACAQ,QAAAA,IAAAA,EAAMG,cAAQC,MAAM,CAAC,GAAKX,EAAAA,UAAAA,EAAY,GAAGD,MAAQ,CAAA,CAAA;AACnD,KAAA,CAAA;AACF,CAAA;AAEA,MAAMa,MAAAA,GAAS,OACbC,UACAC,EAAAA,IAAAA,GAAAA;AAEA,IAAA,MAAMC,gBAAgBC,gBAAW,CAAA,QAAA,CAAA;AAEjC,IAAA,MAAM,EAAEC,IAAI,EAAE,GAAGH,QAAQ,EAAC;AAE1B,IAAA,IAAII,cAAiB,GAAA,MAAMH,aAAczB,CAAAA,gBAAgB,CAACuB,UAAAA,CAAAA;AAC1D,IAAA,IAAII,IAAM,EAAA;AACRC,QAAAA,cAAAA,GAAiB,MAAMC,sBAAiB,CAAA;AAAEF,YAAAA;SAAQC,CAAAA,CAAAA,cAAAA,CAAAA;AACpD;IAEA,MAAM3B,MAAAA,GAAS,MAAME,MAAOC,CAAAA,EAAE,CAACS,KAAK,CAACP,0BAAkBgB,CAAAA,CAAAA,MAAM,CAAC;QAAEQ,IAAMF,EAAAA;AAAe,KAAA,CAAA;AAErFzB,IAAAA,MAAAA,CAAO4B,QAAQ,CAACC,IAAI,CAAC,qBAAuB,EAAA;AAAE/B,QAAAA;AAAO,KAAA,CAAA;IAErD,OAAOA,MAAAA;AACT,CAAA;AAEA;;;;AAIC,IACD,MAAMgC,WAAAA,GAAc,OAAOC,GAAAA,GAAM,EAAE,GAAA;IACjC,MAAMC,OAAAA,GAAU,MAAMhC,MAAOC,CAAAA,EAAE,CAACS,KAAK,CAACP,0BAAkB8B,CAAAA,CAAAA,QAAQ,CAAC;QAAErB,KAAO,EAAA;YAAEC,EAAI,EAAA;gBAAEqB,GAAKH,EAAAA;AAAI;AAAE;AAAE,KAAA,CAAA;IAC/F,IAAIC,OAAAA,CAAQG,MAAM,KAAK,CAAG,EAAA;QACxB,OAAO;AACLH,YAAAA,OAAAA,EAAS,EAAE;YACXI,iBAAmB,EAAA,CAAA;YACnBC,eAAiB,EAAA;AACnB,SAAA;AACF;IAEA,MAAMC,aAAAA,GAAgBC,OAAI,MAAQP,EAAAA,OAAAA,CAAAA;;IAGlC,MAAMQ,aAAAA,GAAgB,MAAMxC,MAAOC,CAAAA,EAAE,CAACS,KAAK,CAAC+B,wBAAgBR,CAAAA,CAAAA,QAAQ,CAAC;QACnErB,KAAO,EAAA;AACL8B,YAAAA,GAAAA,EAAKJ,aAAcK,CAAAA,OAAO,CAAC,CAAC7B,IAAS,GAAA;AACnC,oBAAA;wBAAE8B,UAAY,EAAA;4BAAEC,GAAK/B,EAAAA;AAAK;AAAE,qBAAA;AAC5B,oBAAA;wBAAE8B,UAAY,EAAA;4BAAEE,WAAa,EAAA,CAAA,EAAGhC,IAAK,CAAA,CAAC;AAAE;AAAE;AAC3C,iBAAA;AACH;AACF,KAAA,CAAA;IAEA,MAAMiC,OAAAA,CAAQC,GAAG,CAACR,aAAcD,CAAAA,GAAG,CAAC,CAACU,IAAe1B,GAAAA,gBAAAA,CAAW,QAAU2B,CAAAA,CAAAA,MAAM,CAACD,IAAAA,CAAAA,CAAAA,CAAAA;;AAGhF,IAAA,MAAM,EAAEE,KAAAA,EAAOf,iBAAiB,EAAE,GAAG,MAAMpC,MAAOC,CAAAA,EAAE,CAACS,KAAK,CAACP,0BAAAA,CAAAA,CAAkBiD,UAAU,CAAC;QACtFxC,KAAO,EAAA;AACL8B,YAAAA,GAAAA,EAAKJ,aAAcK,CAAAA,OAAO,CAAC,CAAC7B,IAAS,GAAA;AACnC,oBAAA;wBAAEA,IAAM,EAAA;4BAAE+B,GAAK/B,EAAAA;AAAK;AAAE,qBAAA;AACtB,oBAAA;wBAAEA,IAAM,EAAA;4BAAEgC,WAAa,EAAA,CAAA,EAAGhC,IAAK,CAAA,CAAC;AAAE;AAAE;AACrC,iBAAA;AACH;AACF,KAAA,CAAA;AAEAd,IAAAA,MAAAA,CAAO4B,QAAQ,CAACC,IAAI,CAAC,qBAAuB,EAAA;AAAEG,QAAAA;AAAQ,KAAA,CAAA;IAEtD,OAAO;AACLA,QAAAA,OAAAA;AACAI,QAAAA,iBAAAA;AACAC,QAAAA,eAAAA,EAAiBG,cAAcL;AACjC,KAAA;AACF,CAAA;AAEA;;AAEC,IACD,MAAMkB,MAAAA,GAAS,OACbxC,EAAAA,EACA,EACEyC,IAAI,EACJ9C,MAAM,EAIP,EACD,EAAEgB,IAAI,EAAqC,GAAA;;AAG3C,IAAA,IAAI+B,eAAY/C,MAAS,CAAA,EAAA;QACvB,MAAMgD,cAAAA,GAAiB,MAAMxD,MAAOC,CAAAA,EAAE,CAACS,KAAK,CAACP,0BAAkBQ,CAAAA,CAAAA,OAAO,CAAC;YAAEC,KAAO,EAAA;AAAEC,gBAAAA;AAAG;AAAE,SAAA,CAAA;AAEvF,QAAA,IAAI,CAAC2C,cAAgB,EAAA;YACnB,OAAOC,SAAAA;AACT;AAEA,QAAA,MAAMC,YAAYhC,sBAAiB,CAAA;AAAEF,YAAAA,IAAAA;YAAMmC,SAAW,EAAA;SAAQ,CAAA,CAAA;AAAEL,YAAAA,IAAAA;AAAM9C,YAAAA;AAAO,SAAA,CAAA;AAE7E,QAAA,IAAI+C,eAAY/C,MAAS,CAAA,EAAA;YACvB,MAAMV,MAAAA,GAAS,MAAME,MAAOC,CAAAA,EAAE,CAC3BS,KAAK,CAACP,0BACNkD,CAAAA,CAAAA,MAAM,CAAC;gBAAEzC,KAAO,EAAA;AAAEC,oBAAAA;AAAG,iBAAA;gBAAGc,IAAM+B,EAAAA;AAAU,aAAA,CAAA;YAE3C,OAAO5D,MAAAA;AACT;;KAEK,MAAA;AACL,QAAA,MAAM8D,GAAM,GAAA,MAAM5D,MAAOC,CAAAA,EAAE,CAAC4D,WAAW,EAAA;QACvC,IAAI;;YAEF,MAAML,cAAAA,GAAiB,MAAMxD,MAAOC,CAAAA,EAAE,CACnCC,YAAY,CAACC,0BACb2D,CAAAA,CAAAA,MAAM,CAAC;AAAC,gBAAA,QAAA;AAAU,gBAAA;AAAO,aAAA,CAAA,CACzBlD,KAAK,CAAC;AAAEC,gBAAAA;aACRkD,CAAAA,CAAAA,WAAW,CAACH,GAAII,CAAAA,GAAG,IACnBC,SAAS,EAAA,CACT7D,KAAK,EAAA,CACLC,OAAO,EAAA;;;AAIV,YAAA,MAAM,EAAE6D,SAAS,EAAE,GAAGlE,OAAOC,EAAE,CAACkE,QAAQ,CAACH,GAAG,CAAC7D,0BAAkBiE,CAAAA,CAAAA,UAAU,CAAC5D,MAAM;AAChF,YAAA,MAAMR,OAAOC,EAAE,CACZC,YAAY,CAACgE,UAAUZ,IAAI,CAAA,CAC3BS,WAAW,CAACH,IAAII,GAAG,EAAA,CAAA,CACnBK,MAAM,EAAA,CACNzD,KAAK,CAAC;AAAE,gBAAA,CAACsD,SAAUI,CAAAA,UAAU,CAAChB,IAAI,GAAGzC;AAAG,aAAA,CAAA,CACxCR,OAAO,EAAA;AAEV,YAAA,IAAIG,WAAW,IAAM,EAAA;AACnB,gBAAA,MAAMR,MAAOC,CAAAA,EAAE,CACZC,YAAY,CAACgE,SAAUZ,CAAAA,IAAI,CAC3BS,CAAAA,WAAW,CAACH,GAAAA,CAAII,GAAG,EAAA,CAAA,CACnBO,MAAM,CAAC;AAAE,oBAAA,CAACL,SAAUM,CAAAA,iBAAiB,CAAClB,IAAI,GAAG9C,MAAAA;AAAQ,oBAAA,CAAC0D,SAAUI,CAAAA,UAAU,CAAChB,IAAI,GAAGzC;AAAG,iBAAA,CAAA,CACrFD,KAAK,CAAC;AAAE,oBAAA,CAACsD,SAAUI,CAAAA,UAAU,CAAChB,IAAI,GAAGzC;AAAG,iBAAA,CAAA,CACxCR,OAAO,EAAA;AACZ;;AAGA,YAAA,IAAIoE,qBAAwB,GAAA,GAAA;AAC5B,YAAA,IAAIjE,WAAW,IAAM,EAAA;AACnB,gBAAA,MAAMkE,iBAAoB,GAAA,MAAM1E,MAAOC,CAAAA,EAAE,CACtCC,YAAY,CAACC,0BAAAA,CAAAA,CACb2D,MAAM,CAAC,MACPlD,CAAAA,CAAAA,KAAK,CAAC;oBAAEC,EAAIL,EAAAA;AAAO,iBAAA,CAAA,CACnBuD,WAAW,CAACH,GAAAA,CAAII,GAAG,EACnB5D,CAAAA,CAAAA,KAAK,GACLC,OAAO,EAAA;AACVoE,gBAAAA,qBAAAA,GAAwBC,kBAAkB5D,IAAI;AAChD;AAEA,YAAA,MAAM6D,WAAc3E,GAAAA,MAAAA,CAAO4E,QAAQ,CAACzE,4BAAkB0E,cAAc;AACpE,YAAA,MAAMC,SAAY9E,GAAAA,MAAAA,CAAO4E,QAAQ,CAACnC,0BAAgBoC,cAAc;AAChE,YAAA,MAAME;YAEJ/E,MAAOC,CAAAA,EAAE,CAACkE,QAAQ,CAACH,GAAG,CAACvB,wBAAAA,CAAAA,CAAgB2B,UAAU,CAACxB,UAAU,CAACoC,UAAU;;AAEzE,YAAA,MAAMC,cAAiBjF,GAAAA,MAAAA,CAAOC,EAAE,CAACkE,QAAQ,CAACH,GAAG,CAAC7D,0BAAkBiE,CAAAA,CAAAA,UAAU,CAACtD,IAAI,CAACkE,UAAU;;AAG1F,YAAA,MAAMhF,OAAOC,EAAE,CACZiF,aAAa,CAACP,aACdZ,WAAW,CAACH,GAAII,CAAAA,GAAG,IACnBpD,KAAK,CAACqE,gBAAgBzB,cAAe1C,CAAAA,IAAI,EACzCqE,OAAO,CAACF,cAAgB,EAAA,MAAA,EAAQ,GAAGzB,cAAe1C,CAAAA,IAAI,CAAC,EAAE,CAAC,CAC1DuC,CAAAA,MAAM,CACL4B,cAAAA,EACAjF,OAAOC,EAAE,CAACmF,UAAU,CAACC,GAAG,CAAC,mBAAqB,EAAA;AAC5CJ,gBAAAA,cAAAA;AACAzB,gBAAAA,cAAAA,CAAe1C,IAAI;AACnBG,gBAAAA,aAAAA,CAAQC,MAAM,CAAC,GAAA,EAAKuD,uBAAuB,CAAGjB,EAAAA,cAAAA,CAAelD,MAAM,CAAE,CAAA;AACtE,aAAA,CAAA,CAAA;;AAIL,YAAA,MAAMN,OAAOC,EAAE,CACZiF,aAAa,CAACJ,WACdf,WAAW,CAACH,GAAII,CAAAA,GAAG,IACnBpD,KAAK,CAACmE,sBAAsBvB,cAAe1C,CAAAA,IAAI,EAC/CqE,OAAO,CAACJ,oBAAsB,EAAA,MAAA,EAAQ,GAAGvB,cAAe1C,CAAAA,IAAI,CAAC,EAAE,CAAC,CAChEuC,CAAAA,MAAM,CACL0B,oBAAAA,EACA/E,OAAOC,EAAE,CAACmF,UAAU,CAACC,GAAG,CAAC,mBAAqB,EAAA;AAC5CN,gBAAAA,oBAAAA;AACAvB,gBAAAA,cAAAA,CAAe1C,IAAI;AACnBG,gBAAAA,aAAAA,CAAQC,MAAM,CAAC,GAAA,EAAKuD,uBAAuB,CAAGjB,EAAAA,cAAAA,CAAelD,MAAM,CAAE,CAAA;AACtE,aAAA,CAAA,CAAA;AAGL,YAAA,MAAMsD,IAAI0B,MAAM,EAAA;AAClB,SAAA,CAAE,OAAOC,CAAG,EAAA;AACV,YAAA,MAAM3B,IAAI4B,QAAQ,EAAA;YAClB,MAAMD,CAAAA;AACR;;AAGA,QAAA,MAAM7B,YAAYhC,sBAAiB,CAAA;AAAEF,YAAAA,IAAAA;YAAMmC,SAAW,EAAA;SAAQ,CAAA,CAAA;AAAEL,YAAAA;AAAK,SAAA,CAAA;QAErE,MAAMxD,MAAAA,GAAS,MAAME,MAAOC,CAAAA,EAAE,CAC3BS,KAAK,CAACP,0BACNkD,CAAAA,CAAAA,MAAM,CAAC;YAAEzC,KAAO,EAAA;AAAEC,gBAAAA;AAAG,aAAA;YAAGc,IAAM+B,EAAAA;AAAU,SAAA,CAAA;AAE3C1D,QAAAA,MAAAA,CAAO4B,QAAQ,CAACC,IAAI,CAAC,qBAAuB,EAAA;AAAE/B,YAAAA;AAAO,SAAA,CAAA;QACrD,OAAOA,MAAAA;AACT;AACF,CAAA;AAEA;;;;AAIC,IACD,MAAM2F,MAAAA,GAAS,OAAOC,MAAAA,GAAS,EAAE,GAAA;IAC/B,MAAMvC,KAAAA,GAAQ,MAAMnD,MAAOC,CAAAA,EAAE,CAACS,KAAK,CAACP,0BAAkBgD,CAAAA,CAAAA,KAAK,CAAC;QAAEvC,KAAO8E,EAAAA;AAAO,KAAA,CAAA;AAC5E,IAAA,OAAOvC,KAAQ,GAAA,CAAA;AACjB,CAAA;AAEA;;;AAGC,IACD,MAAMwC,YAAe,GAAA,UAAA;;AAEnB,IAAA,MAAM,EAAEzB,SAAS,EAAE,GAAGlE,OAAOC,EAAE,CAACkE,QAAQ,CAACH,GAAG,CAAC7D,0BAAkBiE,CAAAA,CAAAA,UAAU,CAAC5D,MAAM;AAChF,IAAA,MAAMoF,EAAK5F,GAAAA,MAAAA,CAAOC,EAAE,CAACC,YAAY,CAACC,0BAAAA,CAAAA;IAClC,MAAM0F,KAAAA,GAAQD,GAAGE,QAAQ,EAAA;AACzB,IAAA,MAAM9D,OAAW,GAAA,MAAM4D,EACpB9B,CAAAA,MAAM,CAAC;AAAC,QAAA,IAAA;AAAM,QAAA,MAAA;QAAQ,CAAG+B,EAAAA,KAAAA,CAAM,CAAC,EAAE3B,SAAAA,CAAUM,iBAAiB,CAAClB,IAAI,CAAC,UAAU;AAAE,KAAA,CAAA,CAC/EyC,IAAI,CAAC;AACJF,QAAAA,KAAAA;AACAG,QAAAA,eAAAA,EAAiB9B,UAAUZ,IAAI;QAC/B2C,gBAAkB/B,EAAAA,SAAAA,CAAUI,UAAU,CAAChB,IAAI;QAC3C4C,UAAYhC,EAAAA,SAAAA,CAAUI,UAAU,CAAC2B,gBAAgB;AACjDE,QAAAA,SAAAA,EAAWP,GAAGC;AAChB,KAAA,CAAA,CACCxF,OAAO,CAAC;QAAE+F,UAAY,EAAA;AAAM,KAAA,CAAA;AAE/B,IAAA,MAAMC,SAAuB,GAAA;QAC3BC,IAAM,EAAA;AAAEC,YAAAA,QAAAA,EAAU;AAAG;AACvB,KAAA;IAEAvE,OAAQwE,CAAAA,OAAO,CAAC,CAACC,CAAAA,GAAAA;AACfJ,QAAAA,SAAS,CAACI,CAAAA,CAAE5F,EAAE,CAAC,GAAG;AAAE,YAAA,GAAG4F,CAAC;AAAEF,YAAAA,QAAAA,EAAU;AAAG,SAAA;AACzC,KAAA,CAAA;IAEAvE,OAAQwE,CAAAA,OAAO,CAAC,CAACC,CAAAA,GAAAA;QACf,MAAMC,QAAAA,GAAWD,CAAEjG,CAAAA,MAAM,IAAI,MAAA;AAE7B,QAAA,IAAI,CAAC6F,SAAS,CAACK,QAAAA,CAAS,EAAE;YACxBL,SAAS,CAACK,SAAS,GAAG;AAAEH,gBAAAA,QAAAA,EAAU;AAAG,aAAA;AACvC;QAEAF,SAAS,CAACK,QAAS,CAAA,CAACH,QAAQ,CAACI,IAAI,CAACN,SAAS,CAACI,CAAE5F,CAAAA,EAAE,CAAC,CAAA;QACjDwF,SAAS,CAACK,QAAS,CAAA,CAACH,QAAQ,GAAGK,SAAO,CAAA,MAAA,EAAQP,SAAS,CAACK,QAAS,CAAA,CAACH,QAAQ,CAAA;AAC1E,QAAA,OAAOF,SAAS,CAACI,CAAAA,CAAE5F,EAAE,CAAC,CAACL,MAAM;AAC/B,KAAA,CAAA;IAEA,OAAO6F,SAAAA,CAAUC,IAAI,CAACC,QAAQ;AAChC,CAAA;AAEA,aAAe;AACbpF,IAAAA,MAAAA;AACAsE,IAAAA,MAAAA;AACA3D,IAAAA,WAAAA;AACAuB,IAAAA,MAAAA;AACAxD,IAAAA,gBAAAA;AACA8F,IAAAA;AACF,CAAE;;;;"}
|
|
1
|
+
{"version":3,"file":"folder.js","sources":["../../../server/src/services/folder.ts"],"sourcesContent":["import { sortBy, map, isUndefined } from 'lodash/fp';\nimport { strings, setCreatorFields } from '@strapi/utils';\nimport { FOLDER_MODEL_UID, FILE_MODEL_UID } from '../constants';\nimport { getService } from '../utils';\n\nimport type { File, Folder } from '../types';\n\ntype FolderMap = {\n [key: string]: Partial<Folder> & {\n children: FolderNode[];\n };\n};\n\ntype FolderNode = Partial<Folder> & {\n children: FolderNode[];\n};\n\nconst setPathIdAndPath = async (folder: Pick<Folder, 'parent'>) => {\n const { max } = await strapi.db\n .queryBuilder(FOLDER_MODEL_UID)\n .max('pathId')\n .first()\n .execute<{ max: number }>();\n\n const pathId = max + 1;\n let parentPath = '/';\n if (folder.parent) {\n const parentFolder = await strapi.db\n .query(FOLDER_MODEL_UID)\n .findOne({ where: { id: folder.parent } });\n\n parentPath = parentFolder.path;\n }\n\n return Object.assign(folder, {\n pathId,\n path: strings.joinBy('/', parentPath, `${pathId}`),\n });\n};\n\nconst create = async (\n folderData: Pick<Folder, 'name' | 'parent'>,\n opts?: { user: { id: string | number } }\n) => {\n const folderService = getService('folder');\n\n const { user } = opts || {};\n\n let enrichedFolder = await folderService.setPathIdAndPath(folderData);\n if (user) {\n enrichedFolder = await setCreatorFields({ user })(enrichedFolder);\n }\n\n const folder = await strapi.db.query(FOLDER_MODEL_UID).create({ data: enrichedFolder });\n\n strapi.eventHub.emit('media-folder.create', { folder });\n\n return folder;\n};\n\n/**\n * Recursively delete folders and included files\n * @param ids ids of the folders to delete\n * @returns {Promise<Object[]>}\n */\nconst deleteByIds = async (ids = []) => {\n const folders = await strapi.db.query(FOLDER_MODEL_UID).findMany({ where: { id: { $in: ids } } });\n if (folders.length === 0) {\n return {\n folders: [],\n totalFolderNumber: 0,\n totalFileNumber: 0,\n };\n }\n\n const pathsToDelete = map('path', folders);\n\n // delete files\n const filesToDelete = await strapi.db.query(FILE_MODEL_UID).findMany({\n where: {\n $or: pathsToDelete.flatMap((path) => [\n { folderPath: { $eq: path } },\n { folderPath: { $startsWith: `${path}/` } },\n ]),\n },\n });\n\n await Promise.all(filesToDelete.map((file: File) => getService('upload').remove(file)));\n\n // delete folders and subfolders\n const { count: totalFolderNumber } = await strapi.db.query(FOLDER_MODEL_UID).deleteMany({\n where: {\n $or: pathsToDelete.flatMap((path) => [\n { path: { $eq: path } },\n { path: { $startsWith: `${path}/` } },\n ]),\n },\n });\n\n strapi.eventHub.emit('media-folder.delete', { folders });\n\n return {\n folders,\n totalFolderNumber,\n totalFileNumber: filesToDelete.length,\n };\n};\n\n/**\n * Update name and location of a folder and its belonging folders and files\n */\nconst update = async (\n id: number,\n {\n name,\n parent,\n }: {\n name: string;\n parent: number | null;\n },\n { user }: { user: { id: string | number } }\n) => {\n // only name is updated\n if (isUndefined(parent)) {\n const existingFolder = await strapi.db.query(FOLDER_MODEL_UID).findOne({ where: { id } });\n\n if (!existingFolder) {\n return undefined;\n }\n\n const newFolder = setCreatorFields({ user, isEdition: true })({ name, parent });\n\n if (isUndefined(parent)) {\n const folder = await strapi.db\n .query(FOLDER_MODEL_UID)\n .update({ where: { id }, data: newFolder });\n\n return folder;\n }\n // location is updated => using transaction\n } else {\n const trx = await strapi.db.transaction();\n try {\n // fetch existing folder\n const existingFolder = await strapi.db\n .queryBuilder(FOLDER_MODEL_UID)\n .select(['pathId', 'path'])\n .where({ id })\n .transacting(trx.get())\n .forUpdate()\n .first()\n .execute<Folder>();\n\n // update parent folder (delete + insert; upsert not possible)\n // @ts-expect-error - no dynamic types\n const { joinTable } = strapi.db.metadata.get(FOLDER_MODEL_UID).attributes.parent;\n await strapi.db\n .queryBuilder(joinTable.name)\n .transacting(trx.get())\n .delete()\n .where({ [joinTable.joinColumn.name]: id })\n .execute();\n\n if (parent !== null) {\n await strapi.db\n .queryBuilder(joinTable.name)\n .transacting(trx.get())\n .insert({ [joinTable.inverseJoinColumn.name]: parent, [joinTable.joinColumn.name]: id })\n .where({ [joinTable.joinColumn.name]: id })\n .execute();\n }\n\n // fetch destinationFolder path\n let destinationFolderPath = '/';\n if (parent !== null) {\n const destinationFolder = await strapi.db\n .queryBuilder(FOLDER_MODEL_UID)\n .select('path')\n .where({ id: parent })\n .transacting(trx.get())\n .first()\n .execute<Folder>();\n destinationFolderPath = destinationFolder.path;\n }\n\n const folderTable = strapi.getModel(FOLDER_MODEL_UID).collectionName;\n const fileTable = strapi.getModel(FILE_MODEL_UID).collectionName;\n const folderPathColumnName =\n // @ts-expect-error - no dynamic types\n strapi.db.metadata.get(FILE_MODEL_UID).attributes.folderPath.columnName;\n // @ts-expect-error - no dynamic types\n const pathColumnName = strapi.db.metadata.get(FOLDER_MODEL_UID).attributes.path.columnName;\n\n // update folders below\n await strapi.db\n .getConnection(folderTable)\n .transacting(trx.get())\n .where(pathColumnName, existingFolder.path)\n .orWhere(pathColumnName, 'like', `${existingFolder.path}/%`)\n .update(\n pathColumnName,\n strapi.db.connection.raw('REPLACE(??, ?, ?)', [\n pathColumnName,\n existingFolder.path,\n strings.joinBy('/', destinationFolderPath, `${existingFolder.pathId}`),\n ])\n );\n\n // update files below\n await strapi.db\n .getConnection(fileTable)\n .transacting(trx.get())\n .where(folderPathColumnName, existingFolder.path)\n .orWhere(folderPathColumnName, 'like', `${existingFolder.path}/%`)\n .update(\n folderPathColumnName,\n strapi.db.connection.raw('REPLACE(??, ?, ?)', [\n folderPathColumnName,\n existingFolder.path,\n strings.joinBy('/', destinationFolderPath, `${existingFolder.pathId}`),\n ])\n );\n\n await trx.commit();\n } catch (e) {\n await trx.rollback();\n throw e;\n }\n\n // update less critical information (name + updatedBy)\n const newFolder = setCreatorFields({ user, isEdition: true })({ name });\n\n const folder = await strapi.db\n .query(FOLDER_MODEL_UID)\n .update({ where: { id }, data: newFolder });\n\n strapi.eventHub.emit('media-folder.update', { folder });\n return folder;\n }\n};\n\n/**\n * Check if a folder exists in database\n * @param params query params to find the folder\n * @returns {Promise<boolean>}\n */\nconst exists = async (params = {}) => {\n const count = await strapi.db.query(FOLDER_MODEL_UID).count({ where: params });\n return count > 0;\n};\n\n/**\n * Returns the nested structure of folders\n * @returns {Promise<array>}\n */\nconst getStructure = async () => {\n // @ts-expect-error - no dynamic types\n const { joinTable } = strapi.db.metadata.get(FOLDER_MODEL_UID).attributes.parent;\n const qb = strapi.db.queryBuilder(FOLDER_MODEL_UID);\n const alias = qb.getAlias();\n const folders = (await qb\n .select(['id', 'name', `${alias}.${joinTable.inverseJoinColumn.name} as parent`])\n .join({\n alias,\n referencedTable: joinTable.name,\n referencedColumn: joinTable.joinColumn.name,\n rootColumn: joinTable.joinColumn.referencedColumn,\n rootTable: qb.alias,\n })\n .execute({ mapResults: false })) as Folder[];\n\n const folderMap: FolderMap = {\n null: { children: [] },\n };\n\n folders.forEach((f) => {\n folderMap[f.id] = { ...f, children: [] };\n });\n\n folders.forEach((f) => {\n const parentId = f.parent || 'null';\n\n if (!folderMap[parentId]) {\n folderMap[parentId] = { children: [] };\n }\n\n folderMap[parentId].children.push(folderMap[f.id]);\n folderMap[parentId].children = sortBy('name', folderMap[parentId].children);\n delete folderMap[f.id].parent;\n });\n\n return folderMap.null.children;\n};\n\nexport default {\n create,\n exists,\n deleteByIds,\n update,\n setPathIdAndPath,\n getStructure,\n};\n"],"names":["setPathIdAndPath","folder","max","strapi","db","queryBuilder","FOLDER_MODEL_UID","first","execute","pathId","parentPath","parent","parentFolder","query","findOne","where","id","path","Object","assign","strings","joinBy","create","folderData","opts","folderService","getService","user","enrichedFolder","setCreatorFields","data","eventHub","emit","deleteByIds","ids","folders","findMany","$in","length","totalFolderNumber","totalFileNumber","pathsToDelete","map","filesToDelete","FILE_MODEL_UID","$or","flatMap","folderPath","$eq","$startsWith","Promise","all","file","remove","count","deleteMany","update","name","isUndefined","existingFolder","undefined","newFolder","isEdition","trx","transaction","select","transacting","get","forUpdate","joinTable","metadata","attributes","delete","joinColumn","insert","inverseJoinColumn","destinationFolderPath","destinationFolder","folderTable","getModel","collectionName","fileTable","folderPathColumnName","columnName","pathColumnName","getConnection","orWhere","connection","raw","commit","e","rollback","exists","params","getStructure","qb","alias","getAlias","join","referencedTable","referencedColumn","rootColumn","rootTable","mapResults","folderMap","null","children","forEach","f","parentId","push","sortBy"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { sortBy, isUndefined, map } from 'lodash/fp';
|
|
2
2
|
import { strings, setCreatorFields } from '@strapi/utils';
|
|
3
3
|
import { FOLDER_MODEL_UID, FILE_MODEL_UID } from '../constants.mjs';
|
|
4
4
|
import { getService } from '../utils/index.mjs';
|