Skip to content

Commit

Permalink
Ported over the fixes in #11858 "Check media Parent for permissions w…
Browse files Browse the repository at this point in the history
…hen setting correct MediaType" to target v8 (#12233)

* Ported over the fixes in the v9 PR #11858 "Check media Parent for permissions when setting correct MediaType" to v8

* reverted weird formatting in lang file

* Fixes

Co-authored-by: Elitsa Marinovska <[email protected]>
  • Loading branch information
OwainJ and elit0451 authored Apr 21, 2022
1 parent 400f323 commit 9daa15f
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 53 deletions.
3 changes: 3 additions & 0 deletions src/Umbraco.Web.UI/Umbraco/config/lang/en.xml
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@
<key alias="orClickHereToUpload">or click here to choose files</key>
<key alias="dragFilesHereToUpload">You can drag files here to upload</key>
<key alias="disallowedFileType">Cannot upload this file, it does not have an approved file type</key>
<key alias="disallowedMediaType">Cannot upload this file, the media type with alias '%0%' is not allowed here</key>
<key alias="invalidFileName">Cannot upload this file, it does not have a valid file name</key>
<key alias="maxFileSize">Max file size is</key>
<key alias="mediaRoot">Media root</key>
Expand Down Expand Up @@ -1448,6 +1449,8 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
<key alias="invalidUserPermissionsText">Insufficient user permissions, could not complete the operation</key>
<key alias="operationCancelledHeader">Cancelled</key>
<key alias="operationCancelledText">Operation was cancelled by a 3rd party add-in</key>
<key alias="folderUploadNotAllowed">This file is being uploaded as part of a folder, but creating a new folder is not allowed here</key>
<key alias="folderCreationNotAllowed">Creating a new folder is not allowed here</key>
<key alias="contentPublishedFailedByEvent">Publishing was cancelled by a 3rd party add-in</key>
<key alias="contentTypeDublicatePropertyType">Property type already exists</key>
<key alias="contentTypePropertyTypeCreated">Property type created</key>
Expand Down
6 changes: 5 additions & 1 deletion src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml
Original file line number Diff line number Diff line change
Expand Up @@ -331,8 +331,9 @@
<area alias="media">
<key alias="clickToUpload">Click to upload</key>
<key alias="orClickHereToUpload">or click here to choose files</key>
<key alias="dragFilesHereToUpload">You can drag files here to upload.</key>
<key alias="dragFilesHereToUpload">You can drag files here to upload.</key>
<key alias="disallowedFileType">Cannot upload this file, it does not have an approved file type</key>
<key alias="disallowedMediaType">Cannot upload this file, the media type with alias '%0%' is not allowed here</key>
<key alias="invalidFileName">Cannot upload this file, it does not have a valid file name</key>
<key alias="maxFileSize">Max file size is</key>
<key alias="mediaRoot">Media root</key>
Expand Down Expand Up @@ -1460,6 +1461,9 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
<key alias="invalidUserPermissionsText">Insufficient user permissions, could not complete the operation</key>
<key alias="operationCancelledHeader">Cancelled</key>
<key alias="operationCancelledText">Operation was cancelled by a 3rd party add-in</key>
<key alias="folderUploadNotAllowed">This file is being uploaded as part of a folder, but creating a new folder is not allowed here</key>
<key alias="folderCreationNotAllowed">Creating a new folder is not allowed here</key>
<key alias="contentPublishedFailedByEvent">Publishing was cancelled by a 3rd party add-in</key>
<key alias="contentTypeDublicatePropertyType">Property type already exists</key>
<key alias="contentTypePropertyTypeCreated">Property type created</key>
<key alias="contentTypePropertyTypeCreatedText"><![CDATA[Name: %0% <br /> DataType: %1%]]></key>
Expand Down
191 changes: 139 additions & 52 deletions src/Umbraco.Web/Editors/MediaController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,13 @@ public MediaItemDisplay PostAddFolder(PostedFolder folder)
{
var intParentId = GetParentIdAsInt(folder.ParentId, validatePermissions:true);

var isFolderAllowed = IsFolderCreationAllowedHere(intParentId);
if (isFolderAllowed == false)
{
throw new HttpResponseException(Request.CreateNotificationValidationErrorResponse(
Services.TextService.Localize("speechBubbles", "folderCreationNotAllowed")));
}

var mediaService = Services.MediaService;

var f = mediaService.CreateMedia(folder.Name, intParentId, Constants.Conventions.MediaTypes.Folder);
Expand Down Expand Up @@ -640,10 +647,16 @@ public async Task<HttpResponseMessage> PostAddFile()

var tempFiles = new PostedFiles();
var mediaService = Services.MediaService;
var localizedTextService = Services.TextService;

//in case we pass a path with a folder in it, we will create it and upload media to it.
if (result.FormData.ContainsKey("path"))
{
if (!IsFolderCreationAllowedHere(parentId))
{
AddCancelMessage(tempFiles, message: "speechBubbles/folderUploadNotAllowed");
return Request.CreateResponse(HttpStatusCode.OK, tempFiles);
}

var folders = result.FormData["path"].Split(Constants.CharArrays.ForwardSlash);

Expand All @@ -653,7 +666,7 @@ public async Task<HttpResponseMessage> PostAddFile()
IMedia folderMediaItem;

//if uploading directly to media root and not a subfolder
if (parentId == -1)
if (parentId == Constants.System.Root)
{
//look for matching folder
folderMediaItem =
Expand Down Expand Up @@ -691,88 +704,139 @@ public async Task<HttpResponseMessage> PostAddFile()
}
}

var mediaTypeAlias = string.Empty;
var allMediaTypes = Services.MediaTypeService.GetAll().ToList();
var allowedContentTypes = new HashSet<IMediaType>();

if (parentId != Constants.System.Root)
{
var mediaFolderItem = mediaService.GetById(parentId);
var mediaFolderType = allMediaTypes.FirstOrDefault(x => x.Alias == mediaFolderItem.ContentType.Alias);

if (mediaFolderType != null)
{
IMediaType mediaTypeItem = null;

foreach (ContentTypeSort allowedContentType in mediaFolderType.AllowedContentTypes)
{
IMediaType checkMediaTypeItem = allMediaTypes.FirstOrDefault(x => x.Id == allowedContentType.Id.Value);
allowedContentTypes.Add(checkMediaTypeItem);

var fileProperty = checkMediaTypeItem?.CompositionPropertyTypes.FirstOrDefault(x => x.Alias == Constants.Conventions.Media.File);
if (fileProperty != null)
{
mediaTypeItem = checkMediaTypeItem;
}
}

//Only set the permission-based mediaType if we only allow 1 specific file under this parent.
if (allowedContentTypes.Count == 1 && mediaTypeItem != null)
{
mediaTypeAlias = mediaTypeItem.Alias;
}
}
}
else
{
var typesAllowedAtRoot = allMediaTypes.Where(x => x.AllowedAsRoot).ToList();
allowedContentTypes.UnionWith(typesAllowedAtRoot);
}

//get the files
foreach (var file in result.FileData)
{
var fileName = file.Headers.ContentDisposition.FileName.Trim(Constants.CharArrays.DoubleQuote).TrimEnd();
var safeFileName = fileName.ToSafeFileName();
var ext = safeFileName.Substring(safeFileName.LastIndexOf('.') + 1).ToLower();

if (Current.Configs.Settings().Content.IsFileAllowedForUpload(ext))
if (!Current.Configs.Settings().Content.IsFileAllowedForUpload(ext))
{
tempFiles.Notifications.Add(new Notification(
localizedTextService.Localize("speechBubbles", "operationFailedHeader"),
localizedTextService.Localize("media", "disallowedFileType"),
NotificationStyle.Warning));
continue;
}

if (string.IsNullOrEmpty(mediaTypeAlias))
{
var mediaType = Constants.Conventions.MediaTypes.File;
mediaTypeAlias = Constants.Conventions.MediaTypes.File;

if (result.FormData["contentTypeAlias"] == Constants.Conventions.MediaTypes.AutoSelect)
{
var mediaTypes = Services.MediaTypeService.GetAll();
// Look up MediaTypes
foreach (var mediaTypeItem in mediaTypes)
foreach (var mediaTypeItem in allMediaTypes)
{
var fileProperty = mediaTypeItem.CompositionPropertyTypes.FirstOrDefault(x => x.Alias == "umbracoFile");
if (fileProperty != null) {
var dataTypeKey = fileProperty.DataTypeKey;
var dataType = Services.DataTypeService.GetDataType(dataTypeKey);

if (dataType != null && dataType.Configuration is IFileExtensionsConfig fileExtensionsConfig) {
var fileExtensions = fileExtensionsConfig.FileExtensions;
if (fileExtensions != null)
{
if (fileExtensions.Where(x => x.Value == ext).Count() != 0)
{
mediaType = mediaTypeItem.Alias;
break;
}
}
}
var fileProperty = mediaTypeItem.CompositionPropertyTypes.FirstOrDefault(x => x.Alias == Constants.Conventions.Media.File);
if (fileProperty == null)
{
continue;
}

var dataTypeKey = fileProperty.DataTypeKey;
var dataType = Services.DataTypeService.GetDataType(dataTypeKey);

if (dataType == null || dataType.Configuration is not IFileExtensionsConfig fileExtensionsConfig)
{
continue;
}

var fileExtensions = fileExtensionsConfig.FileExtensions;
if (fileExtensions == null || fileExtensions.All(x => x.Value != ext))
{
continue;
}

mediaTypeAlias = mediaTypeItem.Alias;
break;
}

// If media type is still File then let's check if it's an image.
if (mediaType == Constants.Conventions.MediaTypes.File && Current.Configs.Settings().Content.ImageFileTypes.Contains(ext))
if (mediaTypeAlias == Constants.Conventions.MediaTypes.File && Current.Configs.Settings().Content.ImageFileTypes.Contains(ext))
{
mediaType = Constants.Conventions.MediaTypes.Image;
mediaTypeAlias = Constants.Conventions.MediaTypes.Image;
}
}
else
{
mediaType = result.FormData["contentTypeAlias"];
mediaTypeAlias = result.FormData["contentTypeAlias"];
}
}

var mediaItemName = fileName.ToFriendlyName();
if (allowedContentTypes.Any(x => x.Alias == mediaTypeAlias) == false)
{
tempFiles.Notifications.Add(new Notification(
localizedTextService.Localize("speechBubbles", "operationFailedHeader"),
localizedTextService.Localize("media", "disallowedMediaType", new[] { mediaTypeAlias }),
NotificationStyle.Warning));
continue;
}

var f = mediaService.CreateMedia(mediaItemName, parentId, mediaType, Security.CurrentUser.Id);
var mediaItemName = fileName.ToFriendlyName();

var fileInfo = new FileInfo(file.LocalFileName);
var fs = fileInfo.OpenReadWithRetry();
if (fs == null) throw new InvalidOperationException("Could not acquire file stream");
using (fs)
{
f.SetValue(Services.ContentTypeBaseServices, Constants.Conventions.Media.File,fileName, fs);
}
var createdMediaItem = mediaService.CreateMedia(mediaItemName, parentId, mediaTypeAlias, Security.CurrentUser.Id);

var saveResult = mediaService.Save(f, Security.CurrentUser.Id);
if (saveResult == false)
{
AddCancelMessage(tempFiles,
message: Services.TextService.Localize("speechBubbles", "operationCancelledText") + " -- " + mediaItemName);
}
else
{
tempFiles.UploadedFiles.Add(new ContentPropertyFile
{
FileName = fileName,
PropertyAlias = Constants.Conventions.Media.File,
TempFilePath = file.LocalFileName
});
}
var fileInfo = new FileInfo(file.LocalFileName);
var fs = fileInfo.OpenReadWithRetry();
if (fs == null) throw new InvalidOperationException("Could not acquire file stream");
using (fs)
{
createdMediaItem.SetValue(Services.ContentTypeBaseServices, Constants.Conventions.Media.File, fileName, fs);
}

var saveResult = mediaService.Save(createdMediaItem, Security.CurrentUser.Id);
if (saveResult == false)
{
AddCancelMessage(tempFiles, message: "speechBubbles/operationCancelledText" + " -- " + mediaItemName);
}
else
{
tempFiles.Notifications.Add(new Notification(
Services.TextService.Localize("speechBubbles", "operationFailedHeader"),
Services.TextService.Localize("media", "disallowedFileType"),
NotificationStyle.Warning));
tempFiles.UploadedFiles.Add(new ContentPropertyFile
{
FileName = fileName,
PropertyAlias = Constants.Conventions.Media.File,
TempFilePath = file.LocalFileName
});
}
}

Expand All @@ -792,6 +856,29 @@ public async Task<HttpResponseMessage> PostAddFile()
return Request.CreateResponse(HttpStatusCode.OK, tempFiles);
}

private bool IsFolderCreationAllowedHere(int parentId)
{
var allMediaTypes = Services.MediaTypeService.GetAll().ToList();
var isFolderAllowed = false;
if (parentId == Constants.System.Root)
{
var typesAllowedAtRoot = allMediaTypes.Where(ct => ct.AllowedAsRoot).ToList();
isFolderAllowed = typesAllowedAtRoot.Any(x => x.Alias == Constants.Conventions.MediaTypes.Folder);
}
else
{
var parentMediaType = Services.MediaService.GetById(parentId);
var mediaFolderType = allMediaTypes.FirstOrDefault(x => x.Alias == parentMediaType.ContentType.Alias);
if (mediaFolderType != null)
{
isFolderAllowed =
mediaFolderType.AllowedContentTypes.Any(x => x.Alias == Constants.Conventions.MediaTypes.Folder);
}
}

return isFolderAllowed;
}

private IMedia FindInChildren(int mediaId, string nameToFind, string contentTypeAlias)
{
const int pageSize = 500;
Expand Down

0 comments on commit 9daa15f

Please sign in to comment.