Commit ab01fd9f authored by Benni Mack's avatar Benni Mack
Browse files

[FEATURE] Create new filemount from folder

When setting up permissions and a good folder structure,
admins should be able to create new sys_filemounts from
the context menu of a folder, so they do not have to use
the list module (or the be_groups wizard) but can conventiently
use the file list module OR the file tree.

Resolves: #94374
Releases: master
Change-Id: Idb9781136eb24cb266eb61cd9f3138ab9b91650e
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/69516

Tested-by: core-ci's avatarcore-ci <typo3@b13.com>
Tested-by: Jochen's avatarJochen <rothjochen@gmail.com>
Tested-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Reviewed-by: Jochen's avatarJochen <rothjochen@gmail.com>
Reviewed-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
parent 3a93bc53
......@@ -69,6 +69,20 @@ class ContextMenuActions {
);
}
public static createFilemount(table: string, uid: string): void {
const parts: Array<string> = uid.split(':');
if (parts.length !== 2) {
return;
}
top.TYPO3.Backend.ContentContainer.setUrl(
top.TYPO3.settings.FormEngine.moduleUrl
+ '&edit[sys_filemounts][0]=new'
+ '&defVals[sys_filemounts][base]=' + encodeURIComponent(parts[0])
+ '&defVals[sys_filemounts][path]=' + encodeURIComponent(parts[1])
+ '&returnUrl=' + ContextMenuActions.getReturnUrl()
);
}
public static deleteFile(table: string, uid: string): void {
const $anchorElement = $(this);
const performDelete = () => {
......
......@@ -49,10 +49,10 @@ class UserFileMountService
$this->getBackendUserAuthentication()->getFileStorages()
);
// If working for sys_filemounts table
$storageUid = (int)$PA['row']['base'][0];
$storageUid = (int)($PA['row']['base'][0] ?? 0);
if (!$storageUid) {
// If working for sys_file_collection table
$storageUid = (int)$PA['row']['storage'][0];
$storageUid = (int)($PA['row']['storage'][0] ?? 0);
}
if ($storageUid > 0 && in_array($storageUid, $allowedStorageIds, true)) {
/** @var StorageRepository $storageRepository */
......
.. include:: ../../Includes.txt
================================================================
Feature: #94374 - Create new filemount via folders' context menu
================================================================
See :issue:`94374`
Description
===========
The :php:`sys_filemounts` records are an important feature, which
allows administrators to restrict their users to specific folders
in a file storage.
The workflow however was always to first create the folder in the
filelist module and afterwards switch to the list module to create
a new :php:`sys_filemounts` record for this folder. This furthermore
always required the administrator to select both, the storage and
the previously created folder, in the new record.
To ease the use for administrators, the context menu of folders is
extended with a new option "New Filemount". Using this option opens
the FormEngine with a new :php:`sys_filemounts` record, having the
correct storage and folder prefilled.
Impact
======
It's now possible to create new filemounts directly in the filelist
module, using the new "New Filemount" option in the folders' context
menu. This option also prefills the new record with the correct storage
and folder values.
.. index:: Backend, ext:filelist
......@@ -981,6 +981,9 @@ Do you want to refresh it now?</source>
<trans-unit id="cm.new" resname="cm.new">
<source>New</source>
</trans-unit>
<trans-unit id="cm.newFilemount" resname="cm.newFilemount">
<source>New Filemount</source>
</trans-unit>
<trans-unit id="cm.pasteinto" resname="cm.pasteinto">
<source>Paste into</source>
</trans-unit>
......
......@@ -60,6 +60,11 @@ class FileProvider extends AbstractProvider
'iconIdentifier' => 'actions-document-new',
'callbackAction' => 'createFile'
],
'newFileMount' => [
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.newFilemount',
'iconIdentifier' => 'mimetypes-x-sys_filemounts',
'callbackAction' => 'createFilemount'
],
'info' => [
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.info',
'iconIdentifier' => 'actions-document-info',
......@@ -154,6 +159,9 @@ class FileProvider extends AbstractProvider
case 'new':
$canRender = $this->canCreateNew();
break;
case 'newFileMount':
$canRender = $this->canCreateNewFilemount();
break;
case 'pasteInto':
$canRender = $this->canBePastedInto();
break;
......@@ -223,6 +231,16 @@ class FileProvider extends AbstractProvider
return $this->isFolder() && $this->record->checkActionPermission('write');
}
/**
* New filemounts can only be created for readable folders by admins
*
* @return bool
*/
protected function canCreateNewFilemount(): bool
{
return $this->isFolder() && $this->record->checkActionPermission('read') && $this->backendUser->isAdmin();
}
/**
* @return bool
*/
......
......@@ -10,4 +10,4 @@
*
* The TYPO3 project - inspiring people to share!
*/
var __importDefault=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};define(["require","exports","TYPO3/CMS/Backend/Enum/Severity","jquery","TYPO3/CMS/Core/Ajax/AjaxRequest","TYPO3/CMS/Backend/Modal","TYPO3/CMS/Backend/Hashing/Md5"],(function(t,e,n,o,a,r,i){"use strict";o=__importDefault(o);class s{static getReturnUrl(){return encodeURIComponent(top.list_frame.document.location.pathname+top.list_frame.document.location.search)}static renameFile(t,e){top.TYPO3.Backend.ContentContainer.setUrl(top.TYPO3.settings.FileRename.moduleUrl+"&target="+encodeURIComponent(e)+"&returnUrl="+s.getReturnUrl())}static editFile(t,e){top.TYPO3.Backend.ContentContainer.setUrl(top.TYPO3.settings.FileEdit.moduleUrl+"&target="+encodeURIComponent(e)+"&returnUrl="+s.getReturnUrl())}static editFileStorage(t,e){top.TYPO3.Backend.ContentContainer.setUrl(top.TYPO3.settings.FormEngine.moduleUrl+"&edit[sys_file_storage]["+parseInt(e,10)+"]=edit&returnUrl="+s.getReturnUrl())}static openInfoPopUp(t,e){"sys_file_storage"===t?top.TYPO3.InfoWindow.showItem(t,e):top.TYPO3.InfoWindow.showItem("_FILE",e)}static uploadFile(t,e){top.TYPO3.Backend.ContentContainer.setUrl(top.TYPO3.settings.FileUpload.moduleUrl+"&target="+encodeURIComponent(e)+"&returnUrl="+s.getReturnUrl())}static createFile(t,e){top.TYPO3.Backend.ContentContainer.setUrl(top.TYPO3.settings.FileCreate.moduleUrl+"&target="+encodeURIComponent(e)+"&returnUrl="+s.getReturnUrl())}static deleteFile(t,e){const a=o.default(this),i=()=>{top.TYPO3.Backend.ContentContainer.setUrl(top.TYPO3.settings.FileCommit.moduleUrl+"&data[delete][0][data]="+encodeURIComponent(e)+"&data[delete][0][redirect]="+s.getReturnUrl())};if(!a.data("title"))return void i();r.confirm(a.data("title"),a.data("message"),n.SeverityEnum.warning,[{text:o.default(this).data("button-close-text")||TYPO3.lang["button.cancel"]||"Cancel",active:!0,btnClass:"btn-default",name:"cancel"},{text:o.default(this).data("button-ok-text")||TYPO3.lang["button.delete"]||"Delete",btnClass:"btn-warning",name:"delete"}]).on("button.clicked",t=>{"delete"===t.target.name&&i(),r.dismiss()})}static copyFile(t,e){const n=i.hash(e).substring(0,10),o=TYPO3.settings.ajaxUrls.contextmenu_clipboard,r={CB:{el:{["_FILE%7C"+n]:e},setCopyMode:"1"}};new a(o).withQueryArguments(r).get().finally(()=>{top.TYPO3.Backend.ContentContainer.refresh(!0)})}static copyReleaseFile(t,e){const n=i.hash(e).substring(0,10),o=TYPO3.settings.ajaxUrls.contextmenu_clipboard,r={CB:{el:{["_FILE%7C"+n]:"0"},setCopyMode:"1"}};new a(o).withQueryArguments(r).get().finally(()=>{top.TYPO3.Backend.ContentContainer.refresh(!0)})}static cutFile(t,e){const n=i.hash(e).substring(0,10),o=TYPO3.settings.ajaxUrls.contextmenu_clipboard,r={CB:{el:{["_FILE%7C"+n]:e}}};new a(o).withQueryArguments(r).get().finally(()=>{top.TYPO3.Backend.ContentContainer.refresh(!0)})}static cutReleaseFile(t,e){const n=i.hash(e).substring(0,10),o=TYPO3.settings.ajaxUrls.contextmenu_clipboard,r={CB:{el:{["_FILE%7C"+n]:"0"}}};new a(o).withQueryArguments(r).get().finally(()=>{top.TYPO3.Backend.ContentContainer.refresh(!0)})}static pasteFileInto(t,e){const a=o.default(this),i=a.data("title"),l=()=>{top.TYPO3.Backend.ContentContainer.setUrl(top.TYPO3.settings.FileCommit.moduleUrl+"&CB[paste]=FILE|"+encodeURIComponent(e)+"&CB[pad]=normal&redirect="+s.getReturnUrl())};if(!i)return void l();r.confirm(i,a.data("message"),n.SeverityEnum.warning,[{text:o.default(this).data("button-close-text")||TYPO3.lang["button.cancel"]||"Cancel",active:!0,btnClass:"btn-default",name:"cancel"},{text:o.default(this).data("button-ok-text")||TYPO3.lang["button.ok"]||"OK",btnClass:"btn-warning",name:"ok"}]).on("button.clicked",t=>{"ok"===t.target.name&&l(),r.dismiss()})}static dropInto(t,e,n){const a=o.default(this).data("drop-target");top.TYPO3.Backend.ContentContainer.setUrl(top.TYPO3.settings.FileCommit.moduleUrl+"&file["+n+"][0][data]="+encodeURIComponent(e)+"&file["+n+"][0][target]="+encodeURIComponent(a)+"&redirect="+s.getReturnUrl())}static dropMoveInto(t,e){s.dropInto.bind(o.default(this))(t,e,"move")}static dropCopyInto(t,e){s.dropInto.bind(o.default(this))(t,e,"copy")}}return s}));
\ No newline at end of file
var __importDefault=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};define(["require","exports","TYPO3/CMS/Backend/Enum/Severity","jquery","TYPO3/CMS/Core/Ajax/AjaxRequest","TYPO3/CMS/Backend/Modal","TYPO3/CMS/Backend/Hashing/Md5"],(function(t,e,n,o,a,r,s){"use strict";o=__importDefault(o);class i{static getReturnUrl(){return encodeURIComponent(top.list_frame.document.location.pathname+top.list_frame.document.location.search)}static renameFile(t,e){top.TYPO3.Backend.ContentContainer.setUrl(top.TYPO3.settings.FileRename.moduleUrl+"&target="+encodeURIComponent(e)+"&returnUrl="+i.getReturnUrl())}static editFile(t,e){top.TYPO3.Backend.ContentContainer.setUrl(top.TYPO3.settings.FileEdit.moduleUrl+"&target="+encodeURIComponent(e)+"&returnUrl="+i.getReturnUrl())}static editFileStorage(t,e){top.TYPO3.Backend.ContentContainer.setUrl(top.TYPO3.settings.FormEngine.moduleUrl+"&edit[sys_file_storage]["+parseInt(e,10)+"]=edit&returnUrl="+i.getReturnUrl())}static openInfoPopUp(t,e){"sys_file_storage"===t?top.TYPO3.InfoWindow.showItem(t,e):top.TYPO3.InfoWindow.showItem("_FILE",e)}static uploadFile(t,e){top.TYPO3.Backend.ContentContainer.setUrl(top.TYPO3.settings.FileUpload.moduleUrl+"&target="+encodeURIComponent(e)+"&returnUrl="+i.getReturnUrl())}static createFile(t,e){top.TYPO3.Backend.ContentContainer.setUrl(top.TYPO3.settings.FileCreate.moduleUrl+"&target="+encodeURIComponent(e)+"&returnUrl="+i.getReturnUrl())}static createFilemount(t,e){const n=e.split(":");2===n.length&&top.TYPO3.Backend.ContentContainer.setUrl(top.TYPO3.settings.FormEngine.moduleUrl+"&edit[sys_filemounts][0]=new&defVals[sys_filemounts][base]="+encodeURIComponent(n[0])+"&defVals[sys_filemounts][path]="+encodeURIComponent(n[1])+"&returnUrl="+i.getReturnUrl())}static deleteFile(t,e){const a=o.default(this),s=()=>{top.TYPO3.Backend.ContentContainer.setUrl(top.TYPO3.settings.FileCommit.moduleUrl+"&data[delete][0][data]="+encodeURIComponent(e)+"&data[delete][0][redirect]="+i.getReturnUrl())};if(!a.data("title"))return void s();r.confirm(a.data("title"),a.data("message"),n.SeverityEnum.warning,[{text:o.default(this).data("button-close-text")||TYPO3.lang["button.cancel"]||"Cancel",active:!0,btnClass:"btn-default",name:"cancel"},{text:o.default(this).data("button-ok-text")||TYPO3.lang["button.delete"]||"Delete",btnClass:"btn-warning",name:"delete"}]).on("button.clicked",t=>{"delete"===t.target.name&&s(),r.dismiss()})}static copyFile(t,e){const n=s.hash(e).substring(0,10),o=TYPO3.settings.ajaxUrls.contextmenu_clipboard,r={CB:{el:{["_FILE%7C"+n]:e},setCopyMode:"1"}};new a(o).withQueryArguments(r).get().finally(()=>{top.TYPO3.Backend.ContentContainer.refresh(!0)})}static copyReleaseFile(t,e){const n=s.hash(e).substring(0,10),o=TYPO3.settings.ajaxUrls.contextmenu_clipboard,r={CB:{el:{["_FILE%7C"+n]:"0"},setCopyMode:"1"}};new a(o).withQueryArguments(r).get().finally(()=>{top.TYPO3.Backend.ContentContainer.refresh(!0)})}static cutFile(t,e){const n=s.hash(e).substring(0,10),o=TYPO3.settings.ajaxUrls.contextmenu_clipboard,r={CB:{el:{["_FILE%7C"+n]:e}}};new a(o).withQueryArguments(r).get().finally(()=>{top.TYPO3.Backend.ContentContainer.refresh(!0)})}static cutReleaseFile(t,e){const n=s.hash(e).substring(0,10),o=TYPO3.settings.ajaxUrls.contextmenu_clipboard,r={CB:{el:{["_FILE%7C"+n]:"0"}}};new a(o).withQueryArguments(r).get().finally(()=>{top.TYPO3.Backend.ContentContainer.refresh(!0)})}static pasteFileInto(t,e){const a=o.default(this),s=a.data("title"),l=()=>{top.TYPO3.Backend.ContentContainer.setUrl(top.TYPO3.settings.FileCommit.moduleUrl+"&CB[paste]=FILE|"+encodeURIComponent(e)+"&CB[pad]=normal&redirect="+i.getReturnUrl())};if(!s)return void l();r.confirm(s,a.data("message"),n.SeverityEnum.warning,[{text:o.default(this).data("button-close-text")||TYPO3.lang["button.cancel"]||"Cancel",active:!0,btnClass:"btn-default",name:"cancel"},{text:o.default(this).data("button-ok-text")||TYPO3.lang["button.ok"]||"OK",btnClass:"btn-warning",name:"ok"}]).on("button.clicked",t=>{"ok"===t.target.name&&l(),r.dismiss()})}static dropInto(t,e,n){const a=o.default(this).data("drop-target");top.TYPO3.Backend.ContentContainer.setUrl(top.TYPO3.settings.FileCommit.moduleUrl+"&file["+n+"][0][data]="+encodeURIComponent(e)+"&file["+n+"][0][target]="+encodeURIComponent(a)+"&redirect="+i.getReturnUrl())}static dropMoveInto(t,e){i.dropInto.bind(o.default(this))(t,e,"move")}static dropCopyInto(t,e){i.dropInto.bind(o.default(this))(t,e,"copy")}}return i}));
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment