Migrated more stuff for MediaController

Signed-off-by: Bjarke Berg <mail@bergmania.dk>
This commit is contained in:
Bjarke Berg
2020-06-12 15:58:53 +02:00
parent a4a074e22c
commit 52bc003c8e
10 changed files with 1120 additions and 1103 deletions

View File

@@ -4,12 +4,9 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.ModelBinding;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Core;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
@@ -17,12 +14,9 @@ using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Dictionary;
using Umbraco.Core.Events;
using Umbraco.Core.Models.ContentEditing;
using Umbraco.Core.Models.Editors;
using Umbraco.Core.Models.Entities;
@@ -30,13 +24,18 @@ using Umbraco.Core.Models.Validation;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Strings;
using Umbraco.Web.ContentApps;
using Umbraco.Web.Editors.Filters;
using Umbraco.Web.WebApi.Filters;
using Constants = Umbraco.Core.Constants;
using Umbraco.Core.Mapping;
using Umbraco.Web.Routing;
using Umbraco.Core.Strings;
using Umbraco.Extensions;
using Umbraco.Web.BackOffice.Controllers;
using Umbraco.Web.BackOffice.Filters;
using Umbraco.Web.Common.Attributes;
using Umbraco.Web.Common.Exceptions;
using Umbraco.Web.Editors.Binders;
using Umbraco.Web.Security;
namespace Umbraco.Web.Editors
{
@@ -46,47 +45,55 @@ namespace Umbraco.Web.Editors
/// </remarks>
[PluginController("UmbracoApi")]
[UmbracoApplicationAuthorize(Constants.Applications.Media)]
[MediaControllerControllerConfiguration]
public class MediaController : ContentControllerBase
{
private readonly IContentSettings _contentSettings;
private readonly IIOHelper _ioHelper;
private readonly IMediaTypeService _mediaTypeService;
private readonly IMediaService _mediaService;
private readonly IEntityService _entityService;
private readonly IWebSecurity _webSecurity;
private readonly UmbracoMapper _umbracoMapper;
private readonly IDataTypeService _dataTypeService;
private readonly ILocalizedTextService _localizedTextService;
private readonly ISqlContext _sqlContext;
private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider;
private readonly IRelationService _relationService;
public MediaController(
ICultureDictionary cultureDictionary,
PropertyEditorCollection propertyEditors,
IGlobalSettings globalSettings,
IUmbracoContextAccessor umbracoContextAccessor,
ISqlContext sqlContext,
ServiceContext services,
AppCaches appCaches,
IProfilingLogger logger,
IRuntimeState runtimeState,
IMediaFileSystem mediaFileSystem,
ILogger logger,
IShortStringHelper shortStringHelper,
UmbracoMapper umbracoMapper,
IEventMessagesFactory eventMessages,
ILocalizedTextService localizedTextService,
IContentSettings contentSettings,
IIOHelper ioHelper,
IPublishedUrlProvider publishedUrlProvider)
: base(cultureDictionary, globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, shortStringHelper, umbracoMapper, publishedUrlProvider)
IMediaTypeService mediaTypeService,
IMediaService mediaService,
IEntityService entityService,
IWebSecurity webSecurity,
UmbracoMapper umbracoMapper,
IDataTypeService dataTypeService,
ISqlContext sqlContext,
IContentTypeBaseServiceProvider contentTypeBaseServiceProvider,
IRelationService relationService,
PropertyEditorCollection propertyEditors,
IMediaFileSystem mediaFileSystem)
: base(cultureDictionary, logger, shortStringHelper, eventMessages, localizedTextService)
{
_propertyEditors = propertyEditors ?? throw new ArgumentNullException(nameof(propertyEditors));
_contentSettings = contentSettings;
_ioHelper = ioHelper;
_mediaTypeService = mediaTypeService;
_mediaService = mediaService;
_entityService = entityService;
_webSecurity = webSecurity;
_umbracoMapper = umbracoMapper;
_dataTypeService = dataTypeService;
_localizedTextService = localizedTextService;
_sqlContext = sqlContext;
_contentTypeBaseServiceProvider = contentTypeBaseServiceProvider;
_relationService = relationService;
_propertyEditors = propertyEditors;
_mediaFileSystem = mediaFileSystem;
_contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings));
_ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper));
}
/// <summary>
/// Configures this controller with a custom action selector
/// </summary>
private class MediaControllerControllerConfigurationAttribute : Attribute, IControllerConfiguration
{
public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
{
controllerSettings.Services.Replace(typeof(IHttpActionSelector), new ParameterSwapControllerActionSelector(
new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetById", "id", typeof(int), typeof(Guid), typeof(Udi)),
new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetChildren", "id", typeof(int), typeof(Guid), typeof(Udi))));
}
}
/// <summary>
@@ -98,14 +105,14 @@ namespace Umbraco.Web.Editors
// [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
public MediaItemDisplay GetEmpty(string contentTypeAlias, int parentId)
{
var contentType = Services.MediaTypeService.Get(contentTypeAlias);
var contentType = _mediaTypeService.Get(contentTypeAlias);
if (contentType == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
var emptyContent = Services.MediaService.CreateMedia("", parentId, contentType.Alias, Security.GetUserId().ResultOr(Constants.Security.SuperUserId));
var mapped = Mapper.Map<MediaItemDisplay>(emptyContent);
var emptyContent = _mediaService.CreateMedia("", parentId, contentType.Alias, _webSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId));
var mapped = _umbracoMapper.Map<MediaItemDisplay>(emptyContent);
//remove the listview app if it exists
mapped.ContentApps = mapped.ContentApps.Where(x => x.Alias != "umbListView").ToList();
@@ -120,14 +127,14 @@ namespace Umbraco.Web.Editors
public MediaItemDisplay GetRecycleBin()
{
var apps = new List<ContentApp>();
apps.Add(ListViewContentAppFactory.CreateContentApp(Services.DataTypeService, _propertyEditors, "recycleBin", "media", Core.Constants.DataTypes.DefaultMediaListView));
apps.Add(ListViewContentAppFactory.CreateContentApp(_dataTypeService, _propertyEditors, "recycleBin", "media", Core.Constants.DataTypes.DefaultMediaListView));
apps[0].Active = true;
var display = new MediaItemDisplay
{
Id = Constants.System.RecycleBinMedia,
Alias = "recycleBin",
ParentId = -1,
Name = Services.TextService.Localize("general/recycleBin"),
Name = _localizedTextService.Localize("general/recycleBin"),
ContentTypeAlias = "recycleBin",
CreateDate = DateTime.Now,
IsContainer = true,
@@ -145,9 +152,10 @@ namespace Umbraco.Web.Editors
/// <returns></returns>
// [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
[EnsureUserPermissionForMedia("id")]
[DetermineAmbiguousActionByPassingParameters]
public MediaItemDisplay GetById(int id)
{
var foundContent = GetObjectFromRequest(() => Services.MediaService.GetById(id));
var foundContent = GetObjectFromRequest(() => _mediaService.GetById(id));
if (foundContent == null)
{
@@ -155,7 +163,7 @@ namespace Umbraco.Web.Editors
//HandleContentNotFound will throw an exception
return null;
}
return Mapper.Map<MediaItemDisplay>(foundContent);
return _umbracoMapper.Map<MediaItemDisplay>(foundContent);
}
/// <summary>
@@ -165,9 +173,10 @@ namespace Umbraco.Web.Editors
/// <returns></returns>
// [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
[EnsureUserPermissionForMedia("id")]
[DetermineAmbiguousActionByPassingParameters]
public MediaItemDisplay GetById(Guid id)
{
var foundContent = GetObjectFromRequest(() => Services.MediaService.GetById(id));
var foundContent = GetObjectFromRequest(() => _mediaService.GetById(id));
if (foundContent == null)
{
@@ -175,7 +184,7 @@ namespace Umbraco.Web.Editors
//HandleContentNotFound will throw an exception
return null;
}
return Mapper.Map<MediaItemDisplay>(foundContent);
return _umbracoMapper.Map<MediaItemDisplay>(foundContent);
}
/// <summary>
@@ -185,6 +194,7 @@ namespace Umbraco.Web.Editors
/// <returns></returns>
// [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
[EnsureUserPermissionForMedia("id")]
[DetermineAmbiguousActionByPassingParameters]
public MediaItemDisplay GetById(Udi id)
{
var guidUdi = id as GuidUdi;
@@ -201,10 +211,10 @@ namespace Umbraco.Web.Editors
/// <param name="ids"></param>
/// <returns></returns>
//[FilterAllowedOutgoingMedia(typeof(IEnumerable<MediaItemDisplay>))] // TODO introduce when moved to .NET Core
public IEnumerable<MediaItemDisplay> GetByIds([FromUri]int[] ids)
public IEnumerable<MediaItemDisplay> GetByIds([FromQuery]int[] ids)
{
var foundMedia = Services.MediaService.GetByIds(ids);
return foundMedia.Select(media => Mapper.Map<MediaItemDisplay>(media));
var foundMedia = _mediaService.GetByIds(ids);
return foundMedia.Select(media => _umbracoMapper.Map<MediaItemDisplay>(media));
}
/// <summary>
@@ -218,7 +228,7 @@ namespace Umbraco.Web.Editors
{
//Suggested convention for folder mediatypes - we can make this more or less complicated as long as we document it...
//if you create a media type, which has an alias that ends with ...Folder then its a folder: ex: "secureFolder", "bannerFolder", "Folder"
var folderTypes = Services.MediaTypeService
var folderTypes = _mediaTypeService
.GetAll()
.Where(x => x.Alias.EndsWith("Folder"))
.Select(x => x.Id)
@@ -230,14 +240,14 @@ namespace Umbraco.Web.Editors
}
long total;
var children = Services.MediaService.GetPagedChildren(id, pageNumber - 1, pageSize, out total,
var children = _mediaService.GetPagedChildren(id, pageNumber - 1, pageSize, out total,
//lookup these content types
SqlContext.Query<IMedia>().Where(x => folderTypes.Contains(x.ContentTypeId)),
_sqlContext.Query<IMedia>().Where(x => folderTypes.Contains(x.ContentTypeId)),
Ordering.By("Name", Direction.Ascending));
return new PagedResult<ContentItemBasic<ContentPropertyBasic>>(total, pageNumber, pageSize)
{
Items = children.Select(Mapper.Map<IMedia, ContentItemBasic<ContentPropertyBasic>>)
Items = children.Select(_umbracoMapper.Map<IMedia, ContentItemBasic<ContentPropertyBasic>>)
};
}
@@ -249,8 +259,8 @@ namespace Umbraco.Web.Editors
{
// TODO: Add permissions check!
return Services.MediaService.GetRootMedia()
.Select(Mapper.Map<IMedia, ContentItemBasic<ContentPropertyBasic>>);
return _mediaService.GetRootMedia()
.Select(_umbracoMapper.Map<IMedia, ContentItemBasic<ContentPropertyBasic>>);
}
#region GetChildren
@@ -262,13 +272,14 @@ namespace Umbraco.Web.Editors
protected int[] UserStartNodes
{
get { return _userStartNodes ?? (_userStartNodes = Security.CurrentUser.CalculateMediaStartNodeIds(Services.EntityService)); }
get { return _userStartNodes ?? (_userStartNodes = _webSecurity.CurrentUser.CalculateMediaStartNodeIds(_entityService)); }
}
/// <summary>
/// Returns the child media objects - using the entity INT id
/// </summary>
//[FilterAllowedOutgoingMedia(typeof(IEnumerable<ContentItemBasic<ContentPropertyBasic>>), "Items")] // TODO introduce when moved to .NET Core
[FilterAllowedOutgoingMedia(typeof(IEnumerable<ContentItemBasic<ContentPropertyBasic>>), "Items")] // TODO introduce when moved to .NET Core//[FilterAllowedOutgoingMedia(typeof(IEnumerable<ContentItemBasic<ContentPropertyBasic>>), "Items")]
[DetermineAmbiguousActionByPassingParameters]
public PagedResult<ContentItemBasic<ContentPropertyBasic>> GetChildren(int id,
int pageNumber = 0,
int pageSize = 0,
@@ -283,13 +294,13 @@ namespace Umbraco.Web.Editors
{
if (pageNumber > 0)
return new PagedResult<ContentItemBasic<ContentPropertyBasic>>(0, 0, 0);
var nodes = Services.MediaService.GetByIds(UserStartNodes).ToArray();
var nodes = _mediaService.GetByIds(UserStartNodes).ToArray();
if (nodes.Length == 0)
return new PagedResult<ContentItemBasic<ContentPropertyBasic>>(0, 0, 0);
if (pageSize < nodes.Length) pageSize = nodes.Length; // bah
var pr = new PagedResult<ContentItemBasic<ContentPropertyBasic>>(nodes.Length, pageNumber, pageSize)
{
Items = nodes.Select(Mapper.Map<IMedia, ContentItemBasic<ContentPropertyBasic>>)
Items = nodes.Select(_umbracoMapper.Map<IMedia, ContentItemBasic<ContentPropertyBasic>>)
};
return pr;
}
@@ -304,11 +315,11 @@ namespace Umbraco.Web.Editors
if (filter.IsNullOrWhiteSpace() == false)
{
//add the default text filter
queryFilter = SqlContext.Query<IMedia>()
queryFilter = _sqlContext.Query<IMedia>()
.Where(x => x.Name.Contains(filter));
}
children = Services.MediaService
children = _mediaService
.GetPagedChildren(
id, (pageNumber - 1), pageSize,
out totalChildren,
@@ -318,7 +329,7 @@ namespace Umbraco.Web.Editors
else
{
//better to not use this without paging where possible, currently only the sort dialog does
children = Services.MediaService.GetPagedChildren(id,0, int.MaxValue, out var total).ToList();
children = _mediaService.GetPagedChildren(id,0, int.MaxValue, out var total).ToList();
totalChildren = children.Count;
}
@@ -329,7 +340,7 @@ namespace Umbraco.Web.Editors
var pagedResult = new PagedResult<ContentItemBasic<ContentPropertyBasic>>(totalChildren, pageNumber, pageSize);
pagedResult.Items = children
.Select(Mapper.Map<IMedia, ContentItemBasic<ContentPropertyBasic>>);
.Select(_umbracoMapper.Map<IMedia, ContentItemBasic<ContentPropertyBasic>>);
return pagedResult;
}
@@ -345,7 +356,8 @@ namespace Umbraco.Web.Editors
/// <param name="orderBySystemField"></param>
/// <param name="filter"></param>
/// <returns></returns>
//[FilterAllowedOutgoingMedia(typeof(IEnumerable<ContentItemBasic<ContentPropertyBasic>>), "Items")] // TODO introduce when moved to .NET Core
[FilterAllowedOutgoingMedia(typeof(IEnumerable<ContentItemBasic<ContentPropertyBasic>>), "Items")]
[DetermineAmbiguousActionByPassingParameters]
public PagedResult<ContentItemBasic<ContentPropertyBasic>> GetChildren(Guid id,
int pageNumber = 0,
int pageSize = 0,
@@ -354,7 +366,7 @@ namespace Umbraco.Web.Editors
bool orderBySystemField = true,
string filter = "")
{
var entity = Services.EntityService.Get(id);
var entity = _entityService.Get(id);
if (entity != null)
{
return GetChildren(entity.Id, pageNumber, pageSize, orderBy, orderDirection, orderBySystemField, filter);
@@ -373,7 +385,8 @@ namespace Umbraco.Web.Editors
/// <param name="orderBySystemField"></param>
/// <param name="filter"></param>
/// <returns></returns>
//[FilterAllowedOutgoingMedia(typeof(IEnumerable<ContentItemBasic<ContentPropertyBasic>>), "Items")] // TODO introduce when moved to .NET Core
[FilterAllowedOutgoingMedia(typeof(IEnumerable<ContentItemBasic<ContentPropertyBasic>>), "Items")]
[DetermineAmbiguousActionByPassingParameters]
public PagedResult<ContentItemBasic<ContentPropertyBasic>> GetChildren(Udi id,
int pageNumber = 0,
int pageSize = 0,
@@ -385,7 +398,7 @@ namespace Umbraco.Web.Editors
var guidUdi = id as GuidUdi;
if (guidUdi != null)
{
var entity = Services.EntityService.Get(guidUdi.Guid);
var entity = _entityService.Get(guidUdi.Guid);
if (entity != null)
{
return GetChildren(entity.Id, pageNumber, pageSize, orderBy, orderDirection, orderBySystemField, filter);
@@ -406,7 +419,7 @@ namespace Umbraco.Web.Editors
[HttpPost]
public HttpResponseMessage DeleteById(int id)
{
var foundMedia = GetObjectFromRequest(() => Services.MediaService.GetById(id));
var foundMedia = GetObjectFromRequest(() => _mediaService.GetById(id));
if (foundMedia == null)
{
@@ -416,7 +429,7 @@ namespace Umbraco.Web.Editors
//if the current item is in the recycle bin
if (foundMedia.Trashed == false)
{
var moveResult = Services.MediaService.MoveToRecycleBin(foundMedia, Security.GetUserId().ResultOr(Constants.Security.SuperUserId));
var moveResult = _mediaService.MoveToRecycleBin(foundMedia, _webSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId));
if (moveResult == false)
{
//returning an object of INotificationModel will ensure that any pending
@@ -426,7 +439,7 @@ namespace Umbraco.Web.Editors
}
else
{
var deleteResult = Services.MediaService.Delete(foundMedia, Security.GetUserId().ResultOr(Constants.Security.SuperUserId));
var deleteResult = _mediaService.Delete(foundMedia, _webSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId));
if (deleteResult == false)
{
//returning an object of INotificationModel will ensure that any pending
@@ -450,11 +463,11 @@ namespace Umbraco.Web.Editors
var destinationParentID = move.ParentId;
var sourceParentID = toMove.ParentId;
var moveResult = Services.MediaService.Move(toMove, move.ParentId, Security.GetUserId().ResultOr(Constants.Security.SuperUserId));
var moveResult = _mediaService.Move(toMove, move.ParentId, _webSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId));
if (sourceParentID == destinationParentID)
{
return Request.CreateValidationErrorResponse(new SimpleNotificationModel(new BackOfficeNotification("",Services.TextService.Localize("media/moveToSameFolderFailed"),NotificationStyle.Error)));
return Request.CreateValidationErrorResponse(new SimpleNotificationModel(new BackOfficeNotification("",_localizedTextService.Localize("media/moveToSameFolderFailed"),NotificationStyle.Error)));
}
if (moveResult == false)
{
@@ -519,17 +532,17 @@ namespace Umbraco.Web.Editors
{
//ok, so the absolute mandatory data is invalid and it's new, we cannot actually continue!
// add the model state to the outgoing object and throw validation response
var forDisplay = Mapper.Map<MediaItemDisplay>(contentItem.PersistedContent);
var forDisplay = _umbracoMapper.Map<MediaItemDisplay>(contentItem.PersistedContent);
forDisplay.Errors = ModelState.ToErrorDictionary();
throw new HttpResponseException(Request.CreateValidationErrorResponse(forDisplay));
}
}
//save the item
var saveStatus = Services.MediaService.Save(contentItem.PersistedContent, Security.GetUserId().ResultOr(Constants.Security.SuperUserId));
var saveStatus = _mediaService.Save(contentItem.PersistedContent, _webSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId));
//return the updated model
var display = Mapper.Map<MediaItemDisplay>(contentItem.PersistedContent);
var display = _umbracoMapper.Map<MediaItemDisplay>(contentItem.PersistedContent);
//lastly, if it is not valid, add the model state to the outgoing object and throw a 403
HandleInvalidModelState(display);
@@ -542,8 +555,8 @@ namespace Umbraco.Web.Editors
if (saveStatus.Success)
{
display.AddSuccessNotification(
Services.TextService.Localize("speechBubbles/editMediaSaved"),
Services.TextService.Localize("speechBubbles/editMediaSavedText"));
_localizedTextService.Localize("speechBubbles/editMediaSaved"),
_localizedTextService.Localize("speechBubbles/editMediaSavedText"));
}
else
{
@@ -572,9 +585,9 @@ namespace Umbraco.Web.Editors
[HttpPost]
public HttpResponseMessage EmptyRecycleBin()
{
Services.MediaService.EmptyRecycleBin(Security.GetUserId().ResultOr(Constants.Security.SuperUserId));
_mediaService.EmptyRecycleBin(_webSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId));
return Request.CreateNotificationSuccessResponse(Services.TextService.Localize("defaultdialogs/recycleBinIsEmpty"));
return Request.CreateNotificationSuccessResponse(_localizedTextService.Localize("defaultdialogs/recycleBinIsEmpty"));
}
/// <summary>
@@ -596,7 +609,7 @@ namespace Umbraco.Web.Editors
return Request.CreateResponse(HttpStatusCode.OK);
}
var mediaService = Services.MediaService;
var mediaService = _mediaService;
var sortedMedia = new List<IMedia>();
try
{
@@ -621,12 +634,12 @@ namespace Umbraco.Web.Editors
{
var intParentId = GetParentIdAsInt(folder.ParentId, validatePermissions:true);
var mediaService = Services.MediaService;
var mediaService = _mediaService;
var f = mediaService.CreateMedia(folder.Name, intParentId, Constants.Conventions.MediaTypes.Folder);
mediaService.Save(f, Security.CurrentUser.Id);
mediaService.Save(f, _webSecurity.CurrentUser.Id);
return Mapper.Map<MediaItemDisplay>(f);
return _umbracoMapper.Map<MediaItemDisplay>(f);
}
/// <summary>
@@ -662,7 +675,7 @@ namespace Umbraco.Web.Editors
int parentId = GetParentIdAsInt(currentFolderId, validatePermissions: true);
var tempFiles = new PostedFiles();
var mediaService = Services.MediaService;
var mediaService = _mediaService;
//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"))
@@ -739,21 +752,21 @@ namespace Umbraco.Web.Editors
var mediaItemName = fileName.ToFriendlyName();
var f = mediaService.CreateMedia(mediaItemName, parentId, mediaType, Security.CurrentUser.Id);
var f = mediaService.CreateMedia(mediaItemName, parentId, mediaType, _webSecurity.CurrentUser.Id);
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(_mediaFileSystem, ShortStringHelper, Services.ContentTypeBaseServices, Constants.Conventions.Media.File,fileName, fs);
f.SetValue(_mediaFileSystem, ShortStringHelper, _contentTypeBaseServiceProvider, Constants.Conventions.Media.File,fileName, fs);
}
var saveResult = mediaService.Save(f, Security.CurrentUser.Id);
var saveResult = mediaService.Save(f, _webSecurity.CurrentUser.Id);
if (saveResult == false)
{
AddCancelMessage(tempFiles,
message: Services.TextService.Localize("speechBubbles/operationCancelledText") + " -- " + mediaItemName);
message: _localizedTextService.Localize("speechBubbles/operationCancelledText") + " -- " + mediaItemName);
}
else
{
@@ -768,8 +781,8 @@ namespace Umbraco.Web.Editors
else
{
tempFiles.Notifications.Add(new BackOfficeNotification(
Services.TextService.Localize("speechBubbles/operationFailedHeader"),
Services.TextService.Localize("media/disallowedFileType"),
_localizedTextService.Localize("speechBubbles/operationFailedHeader"),
_localizedTextService.Localize("media/disallowedFileType"),
NotificationStyle.Warning));
}
}
@@ -797,8 +810,8 @@ namespace Umbraco.Web.Editors
var total = long.MaxValue;
while (page * pageSize < total)
{
var children = Services.MediaService.GetPagedChildren(mediaId, page, pageSize, out total,
SqlContext.Query<IMedia>().Where(x => x.Name == nameToFind));
var children = _mediaService.GetPagedChildren(mediaId, page, pageSize, out total,
_sqlContext.Query<IMedia>().Where(x => x.Name == nameToFind));
foreach (var c in children)
return c; //return first one if any are found
}
@@ -814,7 +827,7 @@ namespace Umbraco.Web.Editors
/// and if that check fails an unauthorized exception will occur
/// </param>
/// <returns></returns>
private int GetParentIdAsInt(string parentId, bool validatePermissions)
private ActionResult<int> GetParentIdAsInt(string parentId, bool validatePermissions)
{
int intParentId;
@@ -831,37 +844,36 @@ namespace Umbraco.Web.Editors
Guid idGuid;
if (Guid.TryParse(parentId, out idGuid))
{
var entity = Services.EntityService.Get(idGuid);
var entity = _entityService.Get(idGuid);
if (entity != null)
{
intParentId = entity.Id;
}
else
{
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.NotFound, "The passed id doesn't exist"));
return NotFound("The passed id doesn't exist");
}
}
else
{
throw new HttpResponseException(
Request.CreateValidationErrorResponse("The request was not formatted correctly, the parentId is not an integer, Guid or UDI"));
throw HttpResponseException.CreateValidationErrorResponse("The request was not formatted correctly, the parentId is not an integer, Guid or UDI");
}
}
//ensure the user has access to this folder by parent id!
if (validatePermissions && CheckPermissions(
new Dictionary<string, object>(),
Security.CurrentUser,
Services.MediaService,
Services.EntityService,
new Dictionary<object, object>(),
_webSecurity.CurrentUser,
_mediaService,
_entityService,
intParentId) == false)
{
throw new HttpResponseException(Request.CreateResponse(
throw new HttpResponseException(
HttpStatusCode.Forbidden,
new SimpleNotificationModel(new BackOfficeNotification(
Services.TextService.Localize("speechBubbles/operationFailedHeader"),
Services.TextService.Localize("speechBubbles/invalidUserPermissionsText"),
NotificationStyle.Warning))));
_localizedTextService.Localize("speechBubbles/operationFailedHeader"),
_localizedTextService.Localize("speechBubbles/invalidUserPermissionsText"),
NotificationStyle.Warning)));
}
return intParentId;
@@ -879,7 +891,7 @@ namespace Umbraco.Web.Editors
throw new HttpResponseException(HttpStatusCode.NotFound);
}
var mediaService = Services.MediaService;
var mediaService = _mediaService;
var toMove = mediaService.GetById(model.Id);
if (toMove == null)
{
@@ -889,12 +901,12 @@ namespace Umbraco.Web.Editors
{
//cannot move if the content item is not allowed at the root unless there are
//none allowed at root (in which case all should be allowed at root)
var mediaTypeService = Services.MediaTypeService;
var mediaTypeService = _mediaTypeService;
if (toMove.ContentType.AllowedAsRoot == false && mediaTypeService.GetAll().Any(ct => ct.AllowedAsRoot))
{
var notificationModel = new SimpleNotificationModel();
notificationModel.AddErrorNotification(Services.TextService.Localize("moveOrCopy/notAllowedAtRoot"), "");
throw new HttpResponseException(Request.CreateValidationErrorResponse(notificationModel));
notificationModel.AddErrorNotification(_localizedTextService.Localize("moveOrCopy/notAllowedAtRoot"), "");
throw HttpResponseException.CreateValidationErrorResponse(notificationModel);
}
}
else
@@ -906,21 +918,21 @@ namespace Umbraco.Web.Editors
}
//check if the item is allowed under this one
var parentContentType = Services.MediaTypeService.Get(parent.ContentTypeId);
var parentContentType = _mediaTypeService.Get(parent.ContentTypeId);
if (parentContentType.AllowedContentTypes.Select(x => x.Id).ToArray()
.Any(x => x.Value == toMove.ContentType.Id) == false)
{
var notificationModel = new SimpleNotificationModel();
notificationModel.AddErrorNotification(Services.TextService.Localize("moveOrCopy/notAllowedByContentType"), "");
throw new HttpResponseException(Request.CreateValidationErrorResponse(notificationModel));
notificationModel.AddErrorNotification(_localizedTextService.Localize("moveOrCopy/notAllowedByContentType"), "");
throw HttpResponseException.CreateValidationErrorResponse(notificationModel);
}
// Check on paths
if ((string.Format(",{0},", parent.Path)).IndexOf(string.Format(",{0},", toMove.Id), StringComparison.Ordinal) > -1)
{
var notificationModel = new SimpleNotificationModel();
notificationModel.AddErrorNotification(Services.TextService.Localize("moveOrCopy/notAllowedByPath"), "");
throw new HttpResponseException(Request.CreateValidationErrorResponse(notificationModel));
notificationModel.AddErrorNotification(_localizedTextService.Localize("moveOrCopy/notAllowedByPath"), "");
throw HttpResponseException.CreateValidationErrorResponse(notificationModel);
}
}
@@ -938,7 +950,7 @@ namespace Umbraco.Web.Editors
/// <param name="nodeId">The content to lookup, if the contentItem is not specified</param>
/// <param name="media">Specifies the already resolved content item to check against, setting this ignores the nodeId</param>
/// <returns></returns>
internal static bool CheckPermissions(IDictionary<string, object> storage, IUser user, IMediaService mediaService, IEntityService entityService, int nodeId, IMedia media = null)
internal static bool CheckPermissions(IDictionary<object, object> storage, IUser user, IMediaService mediaService, IEntityService entityService, int nodeId, IMedia media = null)
{
if (storage == null) throw new ArgumentNullException("storage");
if (user == null) throw new ArgumentNullException("user");
@@ -977,7 +989,7 @@ namespace Umbraco.Web.Editors
var objectType = ObjectTypes.GetUmbracoObjectType(entityType);
var udiType = ObjectTypes.GetUdiType(objectType);
var relations = Services.RelationService.GetPagedParentEntitiesByChildId(id, pageNumber - 1, pageSize, out var totalRecords, objectType);
var relations = _relationService.GetPagedParentEntitiesByChildId(id, pageNumber - 1, pageSize, out var totalRecords, objectType);
return new PagedResult<EntityBasic>(totalRecords, pageNumber, pageSize)
{

View File

@@ -0,0 +1,476 @@
// using System;
// using System.Collections.Generic;
// using System.ComponentModel.DataAnnotations;
// using System.Linq;
// using System.Net;
// using System.Net.Http;
// using System.Net.Http.Formatting;
// using System.Net.Http.Headers;
// using System.Threading.Tasks;
// using System.Web.Http;
// using System.Web.Http.ModelBinding;
// using Microsoft.AspNetCore.Identity;
// using Microsoft.AspNetCore.Mvc;
// using Umbraco.Core;
// using Umbraco.Core.Cache;
// using Umbraco.Core.Configuration;
// using Umbraco.Core.Dictionary;
// using Umbraco.Core.Logging;
// using Umbraco.Core.Models;
// using Umbraco.Core.Models.ContentEditing;
// using Umbraco.Core.Models.Membership;
// using Umbraco.Core.Persistence;
// using Umbraco.Core.PropertyEditors;
// using Umbraco.Core.Security;
// using Umbraco.Core.Services;
// using Umbraco.Core.Services.Implement;
// using Umbraco.Core.Strings;
// using Umbraco.Web.ContentApps;
// using Umbraco.Web.Editors.Binders;
// using Umbraco.Web.Editors.Filters;
// using Umbraco.Web.Models.ContentEditing;
// using Umbraco.Web.Mvc;
// using Umbraco.Web.WebApi;
// using Umbraco.Web.WebApi.Filters;
// using Constants = Umbraco.Core.Constants;
// using Umbraco.Core.Mapping;
// using Umbraco.Extensions;
// using Umbraco.Web.BackOffice.Filters;
// using Umbraco.Web.Common.Attributes;
// using Umbraco.Web.Common.Exceptions;
// using Umbraco.Web.Routing;
//
// namespace Umbraco.Web.Editors
// {
// /// <remarks>
// /// This controller is decorated with the UmbracoApplicationAuthorizeAttribute which means that any user requesting
// /// access to ALL of the methods on this controller will need access to the member application.
// /// </remarks>
// [PluginController("UmbracoApi")]
// [UmbracoApplicationAuthorize(Constants.Applications.Members)]
// [OutgoingNoHyphenGuidFormat]
// public class MemberController : ContentControllerBase
// {
// public MemberController(
// IMemberPasswordConfiguration passwordConfig,
// ICultureDictionary cultureDictionary,
// PropertyEditorCollection propertyEditors,
// IGlobalSettings globalSettings,
// IUmbracoContextAccessor umbracoContextAccessor,
// ISqlContext sqlContext,
// ServiceContext services,
// AppCaches appCaches,
// IProfilingLogger logger,
// IRuntimeState runtimeState,
// IShortStringHelper shortStringHelper,
// UmbracoMapper umbracoMapper,
// IPublishedUrlProvider publishedUrlProvider)
// : base(cultureDictionary, globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, shortStringHelper, umbracoMapper, publishedUrlProvider)
// {
// _passwordConfig = passwordConfig ?? throw new ArgumentNullException(nameof(passwordConfig));
// _propertyEditors = propertyEditors ?? throw new ArgumentNullException(nameof(propertyEditors));
// _passwordSecurity = new LegacyPasswordSecurity(_passwordConfig);
// _passwordValidator = new ConfiguredPasswordValidator();
// }
//
// private readonly IMemberPasswordConfiguration _passwordConfig;
// private readonly PropertyEditorCollection _propertyEditors;
// private readonly LegacyPasswordSecurity _passwordSecurity;
// private readonly IPasswordValidator<> _passwordValidator;
//
// public PagedResult<MemberBasic> GetPagedResults(
// int pageNumber = 1,
// int pageSize = 100,
// string orderBy = "username",
// Direction orderDirection = Direction.Ascending,
// bool orderBySystemField = true,
// string filter = "",
// string memberTypeAlias = null)
// {
//
// if (pageNumber <= 0 || pageSize <= 0)
// {
// throw new NotSupportedException("Both pageNumber and pageSize must be greater than zero");
// }
//
// var members = Services.MemberService
// .GetAll((pageNumber - 1), pageSize, out var totalRecords, orderBy, orderDirection, orderBySystemField, memberTypeAlias, filter).ToArray();
// if (totalRecords == 0)
// {
// return new PagedResult<MemberBasic>(0, 0, 0);
// }
//
// var pagedResult = new PagedResult<MemberBasic>(totalRecords, pageNumber, pageSize)
// {
// Items = members
// .Select(x => Mapper.Map<MemberBasic>(x))
// };
// return pagedResult;
// }
//
// /// <summary>
// /// Returns a display node with a list view to render members
// /// </summary>
// /// <param name="listName"></param>
// /// <returns></returns>
// public MemberListDisplay GetListNodeDisplay(string listName)
// {
// var foundType = Services.MemberTypeService.Get(listName);
// var name = foundType != null ? foundType.Name : listName;
//
// var apps = new List<ContentApp>();
// apps.Add(ListViewContentAppFactory.CreateContentApp(Services.DataTypeService, _propertyEditors, listName, "member", Core.Constants.DataTypes.DefaultMembersListView));
// apps[0].Active = true;
//
// var display = new MemberListDisplay
// {
// ContentTypeAlias = listName,
// ContentTypeName = name,
// Id = listName,
// IsContainer = true,
// Name = listName == Constants.Conventions.MemberTypes.AllMembersListId ? "All Members" : name,
// Path = "-1," + listName,
// ParentId = -1,
// ContentApps = apps
// };
//
// return display;
// }
//
// /// <summary>
// /// Gets the content json for the member
// /// </summary>
// /// <param name="key"></param>
// /// <returns></returns>
// // [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
// public MemberDisplay GetByKey(Guid key)
// {
// var foundMember = Services.MemberService.GetByKey(key);
// if (foundMember == null)
// {
// HandleContentNotFound(key);
// }
// return Mapper.Map<MemberDisplay>(foundMember);
// }
//
// /// <summary>
// /// Gets an empty content item for the
// /// </summary>
// /// <param name="contentTypeAlias"></param>
// /// <returns></returns>
// // [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
// public MemberDisplay GetEmpty(string contentTypeAlias = null)
// {
// IMember emptyContent;
// if (contentTypeAlias == null)
// {
// throw new HttpResponseException(HttpStatusCode.NotFound);
// }
//
// var contentType = Services.MemberTypeService.Get(contentTypeAlias);
// if (contentType == null)
// {
// throw new HttpResponseException(HttpStatusCode.NotFound);
// }
//
// var passwordGenerator = new PasswordGenerator(_passwordConfig);
//
// emptyContent = new Member(contentType);
// emptyContent.AdditionalData["NewPassword"] = passwordGenerator.GeneratePassword();
// return Mapper.Map<MemberDisplay>(emptyContent);
// }
//
// /// <summary>
// /// Saves member
// /// </summary>
// /// <returns></returns>
// [FileUploadCleanupFilter]
// // [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
// [MemberSaveValidation]
// public async Task<MemberDisplay> PostSave(
// [ModelBinder(typeof(MemberBinder))]
// MemberSave contentItem)
// {
//
// //If we've reached here it means:
// // * Our model has been bound
// // * and validated
// // * any file attachments have been saved to their temporary location for us to use
// // * we have a reference to the DTO object and the persisted object
// // * Permissions are valid
//
// //map the properties to the persisted entity
// MapPropertyValues(contentItem);
//
// await ValidateMemberDataAsync(contentItem);
//
// //Unlike content/media - if there are errors for a member, we do NOT proceed to save them, we cannot so return the errors
// if (ModelState.IsValid == false)
// {
// var forDisplay = Mapper.Map<MemberDisplay>(contentItem.PersistedContent);
// forDisplay.Errors = ModelState.ToErrorDictionary();
// throw new HttpResponseException(Request.CreateValidationErrorResponse(forDisplay));
// }
//
// //We're gonna look up the current roles now because the below code can cause
// // events to be raised and developers could be manually adding roles to members in
// // their handlers. If we don't look this up now there's a chance we'll just end up
// // removing the roles they've assigned.
// var currRoles = Services.MemberService.GetAllRoles(contentItem.PersistedContent.Username);
// //find the ones to remove and remove them
// var rolesToRemove = currRoles.Except(contentItem.Groups).ToArray();
//
// //Depending on the action we need to first do a create or update using the membership provider
// // this ensures that passwords are formatted correctly and also performs the validation on the provider itself.
// switch (contentItem.Action)
// {
// case ContentSaveAction.Save:
// UpdateMemberData(contentItem);
// break;
// case ContentSaveAction.SaveNew:
// contentItem.PersistedContent = CreateMemberData(contentItem);
// break;
// default:
// //we don't support anything else for members
// throw new HttpResponseException(HttpStatusCode.NotFound);
// }
//
// //TODO: There's 3 things saved here and we should do this all in one transaction, which we can do here by wrapping in a scope
// // but it would be nicer to have this taken care of within the Save method itself
//
// //create/save the IMember
// Services.MemberService.Save(contentItem.PersistedContent);
//
// //Now let's do the role provider stuff - now that we've saved the content item (that is important since
// // if we are changing the username, it must be persisted before looking up the member roles).
// if (rolesToRemove.Any())
// {
// Services.MemberService.DissociateRoles(new[] { contentItem.PersistedContent.Username }, rolesToRemove);
// }
// //find the ones to add and add them
// var toAdd = contentItem.Groups.Except(currRoles).ToArray();
// if (toAdd.Any())
// {
// //add the ones submitted
// Services.MemberService.AssignRoles(new[] { contentItem.PersistedContent.Username }, toAdd);
// }
//
// //return the updated model
// var display = Mapper.Map<MemberDisplay>(contentItem.PersistedContent);
//
// //lastly, if it is not valid, add the model state to the outgoing object and throw a 403
// HandleInvalidModelState(display);
//
// var localizedTextService = Services.TextService;
// //put the correct messages in
// switch (contentItem.Action)
// {
// case ContentSaveAction.Save:
// case ContentSaveAction.SaveNew:
// display.AddSuccessNotification(localizedTextService.Localize("speechBubbles/editMemberSaved"), localizedTextService.Localize("speechBubbles/editMemberSaved"));
// break;
// }
//
// return display;
// }
//
// /// <summary>
// /// Maps the property values to the persisted entity
// /// </summary>
// /// <param name="contentItem"></param>
// private void MapPropertyValues(MemberSave contentItem)
// {
// UpdateName(contentItem);
//
// //map the custom properties - this will already be set for new entities in our member binder
// contentItem.PersistedContent.Email = contentItem.Email;
// contentItem.PersistedContent.Username = contentItem.Username;
//
// //use the base method to map the rest of the properties
// base.MapPropertyValuesForPersistence<IMember, MemberSave>(
// contentItem,
// contentItem.PropertyCollectionDto,
// (save, property) => property.GetValue(), //get prop val
// (save, property, v) => property.SetValue(v), //set prop val
// null); // member are all invariant
// }
//
// private IMember CreateMemberData(MemberSave contentItem)
// {
// var memberType = Services.MemberTypeService.Get(contentItem.ContentTypeAlias);
// if (memberType == null)
// throw new InvalidOperationException($"No member type found with alias {contentItem.ContentTypeAlias}");
// var member = new Member(contentItem.Name, contentItem.Email, contentItem.Username, memberType, true)
// {
// CreatorId = Security.CurrentUser.Id,
// RawPasswordValue = _passwordSecurity.HashPasswordForStorage(contentItem.Password.NewPassword),
// Comments = contentItem.Comments,
// IsApproved = contentItem.IsApproved
// };
//
// return member;
// }
//
// /// <summary>
// /// Update the member security data
// /// </summary>
// /// <param name="contentItem"></param>
// /// <returns>
// /// If the password has been reset then this method will return the reset/generated password, otherwise will return null.
// /// </returns>
// private void UpdateMemberData(MemberSave contentItem)
// {
// contentItem.PersistedContent.WriterId = Security.CurrentUser.Id;
//
// // If the user doesn't have access to sensitive values, then we need to check if any of the built in member property types
// // have been marked as sensitive. If that is the case we cannot change these persisted values no matter what value has been posted.
// // There's only 3 special ones we need to deal with that are part of the MemberSave instance: Comments, IsApproved, IsLockedOut
// // but we will take care of this in a generic way below so that it works for all props.
// if (!Security.CurrentUser.HasAccessToSensitiveData())
// {
// var memberType = Services.MemberTypeService.Get(contentItem.PersistedContent.ContentTypeId);
// var sensitiveProperties = memberType
// .PropertyTypes.Where(x => memberType.IsSensitiveProperty(x.Alias))
// .ToList();
//
// foreach (var sensitiveProperty in sensitiveProperties)
// {
// var destProp = contentItem.Properties.FirstOrDefault(x => x.Alias == sensitiveProperty.Alias);
// if (destProp != null)
// {
// //if found, change the value of the contentItem model to the persisted value so it remains unchanged
// var origValue = contentItem.PersistedContent.GetValue(sensitiveProperty.Alias);
// destProp.Value = origValue;
// }
// }
// }
//
// var isLockedOut = contentItem.IsLockedOut;
//
// //if they were locked but now they are trying to be unlocked
// if (contentItem.PersistedContent.IsLockedOut && isLockedOut == false)
// {
// contentItem.PersistedContent.IsLockedOut = false;
// contentItem.PersistedContent.FailedPasswordAttempts = 0;
// }
// else if (!contentItem.PersistedContent.IsLockedOut && isLockedOut)
// {
// //NOTE: This should not ever happen unless someone is mucking around with the request data.
// //An admin cannot simply lock a user, they get locked out by password attempts, but an admin can un-approve them
// ModelState.AddModelError("custom", "An admin cannot lock a user");
// }
//
// //no password changes then exit ?
// if (contentItem.Password == null)
// return;
//
// // set the password
// contentItem.PersistedContent.RawPasswordValue = _passwordSecurity.HashPasswordForStorage(contentItem.Password.NewPassword);
// }
//
// private static void UpdateName(MemberSave memberSave)
// {
// //Don't update the name if it is empty
// if (memberSave.Name.IsNullOrWhiteSpace() == false)
// {
// memberSave.PersistedContent.Name = memberSave.Name;
// }
// }
//
// // TODO: This logic should be pulled into the service layer
// private async Task<bool> ValidateMemberDataAsync(MemberSave contentItem)
// {
// if (contentItem.Name.IsNullOrWhiteSpace())
// {
// ModelState.AddPropertyError(
// new ValidationResult("Invalid user name", new[] { "value" }),
// string.Format("{0}login", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
// return false;
// }
//
// if (contentItem.Password != null && !contentItem.Password.NewPassword.IsNullOrWhiteSpace())
// {
// var validPassword = await _passwordValidator.ValidateAsync(_passwordConfig, contentItem.Password.NewPassword);
// if (!validPassword)
// {
// ModelState.AddPropertyError(
// new ValidationResult("Invalid password: " + string.Join(", ", validPassword.Result), new[] { "value" }),
// string.Format("{0}password", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
// return false;
// }
// }
//
// var byUsername = Services.MemberService.GetByUsername(contentItem.Username);
// if (byUsername != null && byUsername.Key != contentItem.Key)
// {
// ModelState.AddPropertyError(
// new ValidationResult("Username is already in use", new[] { "value" }),
// string.Format("{0}login", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
// return false;
// }
//
// var byEmail = Services.MemberService.GetByEmail(contentItem.Email);
// if (byEmail != null && byEmail.Key != contentItem.Key)
// {
// ModelState.AddPropertyError(
// new ValidationResult("Email address is already in use", new[] { "value" }),
// string.Format("{0}email", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
// return false;
// }
//
// return true;
// }
//
// /// <summary>
// /// Permanently deletes a member
// /// </summary>
// /// <param name="key"></param>
// /// <returns></returns>
// ///
// [HttpPost]
// public HttpResponseMessage DeleteByKey(Guid key)
// {
// var foundMember = Services.MemberService.GetByKey(key);
// if (foundMember == null)
// {
// return HandleContentNotFound(key, false);
// }
// Services.MemberService.Delete(foundMember);
//
// return Request.CreateResponse(HttpStatusCode.OK);
// }
//
// /// <summary>
// /// Exports member data based on their unique Id
// /// </summary>
// /// <param name="key">The unique <see cref="Guid">member identifier</see></param>
// /// <returns><see cref="HttpResponseMessage"/></returns>
// [HttpGet]
// public HttpResponseMessage ExportMemberData(Guid key)
// {
// var currentUser = Security.CurrentUser;
//
// var httpResponseMessage = Request.CreateResponse();
// if (currentUser.HasAccessToSensitiveData() == false)
// {
// httpResponseMessage.StatusCode = HttpStatusCode.Forbidden;
// return httpResponseMessage;
// }
//
// var member = ((MemberService)Services.MemberService).ExportMember(key);
//
// var fileName = $"{member.Name}_{member.Email}.txt";
//
// httpResponseMessage.Content = new ObjectContent<MemberExportModel>(member, new JsonMediaTypeFormatter { Indent = true });
// httpResponseMessage.Content.Headers.Add("x-filename", fileName);
// httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
// httpResponseMessage.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
// httpResponseMessage.Content.Headers.ContentDisposition.FileName = fileName;
// httpResponseMessage.StatusCode = HttpStatusCode.OK;
//
// return httpResponseMessage;
// }
// }
//
//
// }

View File

@@ -0,0 +1,180 @@
using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Web.Common.Exceptions;
using Umbraco.Web.Editors;
using Umbraco.Web.Security;
namespace Umbraco.Web.WebApi.Filters
{
/// <summary>
/// Auth filter to check if the current user has access to the content item
/// </summary>
/// <remarks>
/// Since media doesn't have permissions, this simply checks start node access
/// </remarks>
internal sealed class EnsureUserPermissionForMediaAttribute : TypeFilterAttribute
{
public EnsureUserPermissionForMediaAttribute(int nodeId)
: base(typeof(EnsureUserPermissionForMediaFilter))
{
Arguments = new object[]
{
nodeId
};
}
public EnsureUserPermissionForMediaAttribute(string paramName)
: base(typeof(EnsureUserPermissionForMediaFilter))
{
Arguments = new object[]
{
paramName
};
}
private sealed class EnsureUserPermissionForMediaFilter : IActionFilter
{
private readonly int? _nodeId;
private readonly string _paramName;
private readonly IWebSecurity _webSecurity;
private readonly IEntityService _entityService;
private readonly IMediaService _mediaService;
/// <summary>
/// This constructor will only be able to test the start node access
/// </summary>
public EnsureUserPermissionForMediaFilter(
IWebSecurity webSecurity,
IEntityService entityService,
IMediaService mediaService,
int nodeId)
:this(webSecurity, entityService, mediaService, nodeId, null)
{
_nodeId = nodeId;
}
public EnsureUserPermissionForMediaFilter(
IWebSecurity webSecurity,
IEntityService entityService,
IMediaService mediaService,
string paramName)
:this(webSecurity, entityService, mediaService,null, paramName)
{
if (paramName == null) throw new ArgumentNullException(nameof(paramName));
if (string.IsNullOrEmpty(paramName))
throw new ArgumentException("Value can't be empty.", nameof(paramName));
}
private EnsureUserPermissionForMediaFilter(
IWebSecurity webSecurity,
IEntityService entityService,
IMediaService mediaService,
int? nodeId, string paramName)
{
_webSecurity = webSecurity ?? throw new ArgumentNullException(nameof(webSecurity));
_entityService = entityService ?? throw new ArgumentNullException(nameof(entityService));
_mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService));
_paramName = paramName;
if (nodeId.HasValue)
{
_nodeId = nodeId.Value;
}
}
private int GetNodeIdFromParameter(object parameterValue)
{
if (parameterValue is int)
{
return (int) parameterValue;
}
var guidId = Guid.Empty;
if (parameterValue is Guid)
{
guidId = (Guid) parameterValue;
}
else if (parameterValue is GuidUdi)
{
guidId = ((GuidUdi) parameterValue).Guid;
}
if (guidId != Guid.Empty)
{
var found = _entityService.GetId(guidId, UmbracoObjectTypes.Media);
if (found)
return found.Result;
}
throw new InvalidOperationException("The id type: " + parameterValue.GetType() +
" is not a supported id");
}
public void OnActionExecuting(ActionExecutingContext context)
{
if (_webSecurity.CurrentUser == null)
{
throw new HttpResponseException(System.Net.HttpStatusCode.Unauthorized);
}
int nodeId;
if (_nodeId.HasValue == false)
{
var parts = _paramName.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
if (context.ActionArguments[parts[0]] == null)
{
throw new InvalidOperationException("No argument found for the current action with the name: " +
_paramName);
}
if (parts.Length == 1)
{
nodeId = GetNodeIdFromParameter(context.ActionArguments[parts[0]]);
}
else
{
//now we need to see if we can get the property of whatever object it is
var pType = context.ActionArguments[parts[0]].GetType();
var prop = pType.GetProperty(parts[1]);
if (prop == null)
{
throw new InvalidOperationException(
"No argument found for the current action with the name: " + _paramName);
}
nodeId = GetNodeIdFromParameter(prop.GetValue(context.ActionArguments[parts[0]]));
}
}
else
{
nodeId = _nodeId.Value;
}
if (MediaController.CheckPermissions(
context.HttpContext.Items,
_webSecurity.CurrentUser,
_mediaService,
_entityService,
nodeId))
{
}
else
{
throw new HttpResponseException(System.Net.HttpStatusCode.Unauthorized);
}
}
public void OnActionExecuted(ActionExecutedContext context)
{
}
}
}
}

View File

@@ -157,95 +157,14 @@ namespace Umbraco.Web.Editors.Binders
{
throw new ArgumentNullException(nameof(bindingContext));
}
var modelName = bindingContext.ModelName;
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
var model = await _modelBinderHelper.BindModelFromMultipartRequestAsync<ContentItemSave>(_jsonSerializer, _hostingEnvironment, bindingContext);
if (valueProviderResult == ValueProviderResult.None)
{
return;
}
bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
var value = valueProviderResult.FirstValue;
// Check if the argument value is null or empty
if (string.IsNullOrEmpty(value))
{
return;
}
var model = _jsonSerializer.Deserialize<ContentItemSave>(value);
if (model is null)
{
// Non-integer arguments result in model state errors
bindingContext.ModelState.TryAddModelError(
modelName, $"Cannot deserialize {modelName} as {nameof(ContentItemSave)}.");
return;
}
//Handle file uploads
foreach (var formFile in bindingContext.HttpContext.Request.Form.Files)
{
//The name that has been assigned in JS has 2 or more parts. The second part indicates the property id
// for which the file belongs, the remaining parts are just metadata that can be used by the property editor.
var parts = formFile.Name.Trim('\"').Split('_');
if (parts.Length < 2)
{
bindingContext.HttpContext.SetReasonPhrase( "The request was not formatted correctly the file name's must be underscore delimited");
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
var propAlias = parts[1];
//if there are 3 parts part 3 is always culture
string culture = null;
if (parts.Length > 2)
{
culture = parts[2];
//normalize to null if empty
if (culture.IsNullOrWhiteSpace())
{
culture = null;
}
}
//if there are 4 parts part 4 is always segment
string segment = null;
if (parts.Length > 3)
{
segment = parts[3];
//normalize to null if empty
if (segment.IsNullOrWhiteSpace())
{
segment = null;
}
}
// TODO: anything after 4 parts we can put in metadata
var fileName = formFile.FileName.Trim('\"');
var tempFileUploadFolder = _hostingEnvironment.MapPathContentRoot(Core.Constants.SystemDirectories.TempFileUploads);
Directory.CreateDirectory(tempFileUploadFolder);
var tempFilePath = Path.Combine(tempFileUploadFolder, Guid.NewGuid().ToString());
using (var stream = System.IO.File.Create(tempFilePath))
{
await formFile.CopyToAsync(stream);
}
model.UploadedFiles.Add(new ContentPropertyFile
{
TempFilePath = tempFilePath,
PropertyAlias = propAlias,
Culture = culture,
Segment = segment,
FileName = fileName
});
}
model.PersistedContent = ContentControllerBase.IsCreatingAction(model.Action) ? CreateNew(model) : GetExisting(model);
//create the dto from the persisted model
@@ -270,5 +189,7 @@ namespace Umbraco.Web.Editors.Binders
bindingContext.Result = ModelBindingResult.Success(model);
}
}
}

View File

@@ -1,11 +1,14 @@
using System;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Net.Http.Headers;
using Umbraco.Core;
using Umbraco.Core.Hosting;
using Umbraco.Core.Models.Editors;
using Umbraco.Core.Serialization;
using Umbraco.Extensions;
using Umbraco.Web.Common.Exceptions;
using Umbraco.Web.Models.ContentEditing;
@@ -17,73 +20,103 @@ namespace Umbraco.Web.Editors.Binders
/// </summary>
internal class ContentModelBinderHelper
{
// public TModelSave BindModelFromMultipartRequest<TModelSave>(ActionContext actionContext,
// ModelBindingContext bindingContext)
// where TModelSave : IHaveUploadedFiles
// {
// var result = actionContext.ReadAsMultipart(Constants.SystemDirectories.TempFileUploads);
//
// var model = actionContext.GetModelFromMultipartRequest<TModelSave>(result, "contentItem");
//
// //get the files
// foreach (var file in result.FileData)
// {
// //The name that has been assigned in JS has 2 or more parts. The second part indicates the property id
// // for which the file belongs, the remaining parts are just metadata that can be used by the property editor.
// var parts = file.Headers.ContentDisposition.Name.Trim('\"').Split('_');
// if (parts.Length < 2)
// {
// bindingContext.HttpContext.SetReasonPhrase(
// "The request was not formatted correctly the file name's must be underscore delimited");
// throw new HttpResponseException(HttpStatusCode.BadRequest);
// }
//
// var propAlias = parts[1];
//
// //if there are 3 parts part 3 is always culture
// string culture = null;
// if (parts.Length > 2)
// {
// culture = parts[2];
// //normalize to null if empty
// if (culture.IsNullOrWhiteSpace())
// {
// culture = null;
// }
// }
//
// //if there are 4 parts part 4 is always segment
// string segment = null;
// if (parts.Length > 3)
// {
// segment = parts[3];
// //normalize to null if empty
// if (segment.IsNullOrWhiteSpace())
// {
// segment = null;
// }
// }
//
// // TODO: anything after 4 parts we can put in metadata
//
// var fileName = file.Headers.ContentDisposition.FileName.Trim('\"');
//
// model.UploadedFiles.Add(new ContentPropertyFile
// {
// TempFilePath = file.LocalFileName,
// PropertyAlias = propAlias,
// Culture = culture,
// Segment = segment,
// FileName = fileName
// });
// }
//
// bindingContext.Model = model;
//
// return model;
// }
public async Task<T> BindModelFromMultipartRequestAsync<T>(
IJsonSerializer jsonSerializer,
IHostingEnvironment hostingEnvironment,
ModelBindingContext bindingContext)
where T: class, IHaveUploadedFiles
{
var modelName = bindingContext.ModelName;
/// <summary>
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
if (valueProviderResult == ValueProviderResult.None)
{
return null;
}
bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
var value = valueProviderResult.FirstValue;
// Check if the argument value is null or empty
if (string.IsNullOrEmpty(value))
{
return null;
}
var model = jsonSerializer.Deserialize<T>(value);
if (model is null)
{
// Non-integer arguments result in model state errors
bindingContext.ModelState.TryAddModelError(
modelName, $"Cannot deserialize {modelName} as {nameof(T)}.");
return null;
}
//Handle file uploads
foreach (var formFile in bindingContext.HttpContext.Request.Form.Files)
{
//The name that has been assigned in JS has 2 or more parts. The second part indicates the property id
// for which the file belongs, the remaining parts are just metadata that can be used by the property editor.
var parts = formFile.Name.Trim('\"').Split('_');
if (parts.Length < 2)
{
bindingContext.HttpContext.SetReasonPhrase( "The request was not formatted correctly the file name's must be underscore delimited");
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
var propAlias = parts[1];
//if there are 3 parts part 3 is always culture
string culture = null;
if (parts.Length > 2)
{
culture = parts[2];
//normalize to null if empty
if (culture.IsNullOrWhiteSpace())
{
culture = null;
}
}
//if there are 4 parts part 4 is always segment
string segment = null;
if (parts.Length > 3)
{
segment = parts[3];
//normalize to null if empty
if (segment.IsNullOrWhiteSpace())
{
segment = null;
}
}
// TODO: anything after 4 parts we can put in metadata
var fileName = formFile.FileName.Trim('\"');
var tempFileUploadFolder = hostingEnvironment.MapPathContentRoot(Core.Constants.SystemDirectories.TempFileUploads);
Directory.CreateDirectory(tempFileUploadFolder);
var tempFilePath = Path.Combine(tempFileUploadFolder, Guid.NewGuid().ToString());
using (var stream = System.IO.File.Create(tempFilePath))
{
await formFile.CopyToAsync(stream);
}
model.UploadedFiles.Add(new ContentPropertyFile
{
TempFilePath = tempFilePath,
PropertyAlias = propAlias,
Culture = culture,
Segment = segment,
FileName = fileName
});
}
return model;
}
/// <summary>
/// we will now assign all of the values in the 'save' model to the DTO object
/// </summary>
/// <param name="saveModel"></param>

View File

@@ -1,78 +1,82 @@
// using System;
// using System.Threading.Tasks;
// using Microsoft.AspNetCore.Mvc.ModelBinding;
// using Umbraco.Core.Mapping;
// using Umbraco.Core.Models;
// using Umbraco.Core.Services;
// using Umbraco.Web.Models.ContentEditing;
//
// namespace Umbraco.Web.Editors.Binders
// {
// /// <summary>
// /// The model binder for <see cref="T:Umbraco.Web.Models.ContentEditing.MediaItemSave" />
// /// </summary>
// internal class MediaItemBinder : IModelBinder
// {
// private readonly IMediaService _mediaService;
// private readonly UmbracoMapper _umbracoMapper;
// private readonly IMediaTypeService _mediaTypeService;
// private readonly ContentModelBinderHelper _modelBinderHelper;
//
//
// public MediaItemBinder(IMediaService mediaService, UmbracoMapper umbracoMapper, IMediaTypeService mediaTypeService)
// {
// _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService));
// _umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper));
// _mediaTypeService = mediaTypeService ?? throw new ArgumentNullException(nameof(mediaTypeService));
//
// _modelBinderHelper = new ContentModelBinderHelper();
// }
//
// /// <summary>
// /// Creates the model from the request and binds it to the context
// /// </summary>
// /// <param name="bindingContext"></param>
// /// <returns></returns>
// public Task BindModelAsync(ModelBindingContext bindingContext)
// {
// var actionContext = bindingContext.ActionContext;
// var model = _modelBinderHelper.BindModelFromMultipartRequest<MediaItemSave>(actionContext, bindingContext);
// if (model == null)
// {
// bindingContext.Result = ModelBindingResult.Failed();
// return Task.CompletedTask;
// }
//
// model.PersistedContent = ContentControllerBase.IsCreatingAction(model.Action) ? CreateNew(model) : GetExisting(model);
//
// //create the dto from the persisted model
// if (model.PersistedContent != null)
// {
// model.PropertyCollectionDto = _umbracoMapper.Map<IMedia, ContentPropertyCollectionDto>(model.PersistedContent);
// //now map all of the saved values to the dto
// _modelBinderHelper.MapPropertyValuesFromSaved(model, model.PropertyCollectionDto);
// }
//
// model.Name = model.Name.Trim();
//
// bindingContext.Result = ModelBindingResult.Success(model);
// return Task.CompletedTask;
// }
//
// private IMedia GetExisting(MediaItemSave model)
// {
// return _mediaService.GetById(Convert.ToInt32(model.Id));
// }
//
// private IMedia CreateNew(MediaItemSave model)
// {
// var mediaType = _mediaTypeService.Get(model.ContentTypeAlias);
// if (mediaType == null)
// {
// throw new InvalidOperationException("No media type found with alias " + model.ContentTypeAlias);
// }
// return new Core.Models.Media(model.Name, model.ParentId, mediaType);
// }
//
// }
// }
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Umbraco.Core.Hosting;
using Umbraco.Core.Mapping;
using Umbraco.Core.Models;
using Umbraco.Core.Serialization;
using Umbraco.Core.Services;
using Umbraco.Web.Models.ContentEditing;
namespace Umbraco.Web.Editors.Binders
{
/// <summary>
/// The model binder for <see cref="T:Umbraco.Web.Models.ContentEditing.MediaItemSave" />
/// </summary>
internal class MediaItemBinder : IModelBinder
{
private readonly IJsonSerializer _jsonSerializer;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IMediaService _mediaService;
private readonly UmbracoMapper _umbracoMapper;
private readonly IMediaTypeService _mediaTypeService;
private readonly ContentModelBinderHelper _modelBinderHelper;
public MediaItemBinder(IJsonSerializer jsonSerializer, IHostingEnvironment hostingEnvironment, IMediaService mediaService, UmbracoMapper umbracoMapper, IMediaTypeService mediaTypeService)
{
_jsonSerializer = jsonSerializer ?? throw new ArgumentNullException(nameof(jsonSerializer));
_hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment));
_mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService));
_umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper));
_mediaTypeService = mediaTypeService ?? throw new ArgumentNullException(nameof(mediaTypeService));
_modelBinderHelper = new ContentModelBinderHelper();
}
/// <summary>
/// Creates the model from the request and binds it to the context
/// </summary>
/// <param name="bindingContext"></param>
/// <returns></returns>
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
var model = await _modelBinderHelper.BindModelFromMultipartRequestAsync<MediaItemSave>(_jsonSerializer, _hostingEnvironment, bindingContext);
if (model == null)
{
return;
}
model.PersistedContent = ContentControllerBase.IsCreatingAction(model.Action) ? CreateNew(model) : GetExisting(model);
//create the dto from the persisted model
if (model.PersistedContent != null)
{
model.PropertyCollectionDto = _umbracoMapper.Map<IMedia, ContentPropertyCollectionDto>(model.PersistedContent);
//now map all of the saved values to the dto
_modelBinderHelper.MapPropertyValuesFromSaved(model, model.PropertyCollectionDto);
}
model.Name = model.Name.Trim();
bindingContext.Result = ModelBindingResult.Success(model);
}
private IMedia GetExisting(MediaItemSave model)
{
return _mediaService.GetById(Convert.ToInt32(model.Id));
}
private IMedia CreateNew(MediaItemSave model)
{
var mediaType = _mediaTypeService.Get(model.ContentTypeAlias);
if (mediaType == null)
{
throw new InvalidOperationException("No media type found with alias " + model.ContentTypeAlias);
}
return new Core.Models.Media(model.Name, model.ParentId, mediaType);
}
}
}

View File

@@ -1,144 +1,148 @@
// using System;
// using System.Collections.Generic;
// using Umbraco.Core;
// using Umbraco.Core.Models;
// using Umbraco.Core.Services;
// using Umbraco.Core.Strings;
// using Umbraco.Web.Models.ContentEditing;
// using System.Linq;
// using System.Threading.Tasks;
// using Microsoft.AspNetCore.Mvc.ModelBinding;
// using Umbraco.Core.Mapping;
//
// namespace Umbraco.Web.Editors.Binders
// {
// /// <summary>
// /// The model binder for <see cref="T:Umbraco.Web.Models.ContentEditing.MemberSave" />
// /// </summary>
// internal class MemberBinder : IModelBinder
// {
// private readonly ContentModelBinderHelper _modelBinderHelper;
// private readonly IShortStringHelper _shortStringHelper;
// private readonly UmbracoMapper _umbracoMapper;
// private readonly IMemberService _memberService;
// private readonly IMemberTypeService _memberTypeService;
//
// public MemberBinder(
// IShortStringHelper shortStringHelper,
// UmbracoMapper umbracoMapper,
// IMemberService memberService,
// IMemberTypeService memberTypeService)
// {
//
// _shortStringHelper = shortStringHelper ?? throw new ArgumentNullException(nameof(shortStringHelper));
// _umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper));
// _memberService = memberService ?? throw new ArgumentNullException(nameof(memberService));
// _memberTypeService = memberTypeService ?? throw new ArgumentNullException(nameof(memberTypeService));
// _modelBinderHelper = new ContentModelBinderHelper();
// }
//
// /// <summary>
// /// Creates the model from the request and binds it to the context
// /// </summary>
// /// <param name="actionContext"></param>
// /// <param name="bindingContext"></param>
// /// <returns></returns>
// public Task BindModelAsync(ModelBindingContext bindingContext)
// {
// var actionContext = bindingContext.ActionContext;
// var model = _modelBinderHelper.BindModelFromMultipartRequest<MemberSave>(actionContext, bindingContext);
// if (model == null)
// {
// bindingContext.Result = ModelBindingResult.Failed();
// return Task.CompletedTask;
// }
//
// model.PersistedContent = ContentControllerBase.IsCreatingAction(model.Action) ? CreateNew(model) : GetExisting(model);
//
// //create the dto from the persisted model
// if (model.PersistedContent != null)
// {
// model.PropertyCollectionDto = _umbracoMapper.Map<IMember, ContentPropertyCollectionDto>(model.PersistedContent);
// //now map all of the saved values to the dto
// _modelBinderHelper.MapPropertyValuesFromSaved(model, model.PropertyCollectionDto);
// }
//
// model.Name = model.Name.Trim();
//
// bindingContext.Result = ModelBindingResult.Success(model);
// return Task.CompletedTask;
// }
//
// /// <summary>
// /// Returns an IMember instance used to bind values to and save (depending on the membership scenario)
// /// </summary>
// /// <param name="model"></param>
// /// <returns></returns>
// private IMember GetExisting(MemberSave model)
// {
// return GetExisting(model.Key);
// }
//
// private IMember GetExisting(Guid key)
// {
// var member = _memberService.GetByKey(key);
// if (member == null)
// {
// throw new InvalidOperationException("Could not find member with key " + key);
// }
//
// return member;
// }
//
// /// <summary>
// /// Gets an instance of IMember used when creating a member
// /// </summary>
// /// <param name="model"></param>
// /// <returns></returns>
// /// <remarks>
// /// Depending on whether a custom membership provider is configured this will return different results.
// /// </remarks>
// private IMember CreateNew(MemberSave model)
// {
// var contentType = _memberTypeService.Get(model.ContentTypeAlias);
// if (contentType == null)
// {
// throw new InvalidOperationException("No member type found with alias " + model.ContentTypeAlias);
// }
//
// //remove all membership properties, these values are set with the membership provider.
// FilterMembershipProviderProperties(contentType);
//
// //return the new member with the details filled in
// return new Member(model.Name, model.Email, model.Username, model.Password.NewPassword, contentType);
// }
//
// /// <summary>
// /// This will remove all of the special membership provider properties which were required to display the property editors
// /// for editing - but the values have been mapped back to the MemberSave object directly - we don't want to keep these properties
// /// on the IMember because they will attempt to be persisted which we don't want since they might not even exist.
// /// </summary>
// /// <param name="contentType"></param>
// private void FilterMembershipProviderProperties(IContentTypeBase contentType)
// {
// var defaultProps = ConventionsHelper.GetStandardPropertyTypeStubs(_shortStringHelper);
// //remove all membership properties, these values are set with the membership provider.
// var exclude = defaultProps.Select(x => x.Value.Alias).ToArray();
// FilterContentTypeProperties(contentType, exclude);
// }
//
// private void FilterContentTypeProperties(IContentTypeBase contentType, IEnumerable<string> exclude)
// {
// //remove all properties based on the exclusion list
// foreach (var remove in exclude)
// {
// if (contentType.PropertyTypeExists(remove))
// {
// contentType.RemovePropertyType(remove);
// }
// }
// }
//
//
// }
// }
using System;
using System.Collections.Generic;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Core.Strings;
using Umbraco.Web.Models.ContentEditing;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Umbraco.Core.Hosting;
using Umbraco.Core.Mapping;
using Umbraco.Core.Serialization;
namespace Umbraco.Web.Editors.Binders
{
/// <summary>
/// The model binder for <see cref="T:Umbraco.Web.Models.ContentEditing.MemberSave" />
/// </summary>
internal class MemberBinder : IModelBinder
{
private readonly ContentModelBinderHelper _modelBinderHelper;
private readonly IJsonSerializer _jsonSerializer;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IShortStringHelper _shortStringHelper;
private readonly UmbracoMapper _umbracoMapper;
private readonly IMemberService _memberService;
private readonly IMemberTypeService _memberTypeService;
public MemberBinder(
IJsonSerializer jsonSerializer,
IHostingEnvironment hostingEnvironment,
IShortStringHelper shortStringHelper,
UmbracoMapper umbracoMapper,
IMemberService memberService,
IMemberTypeService memberTypeService)
{
_jsonSerializer = jsonSerializer ?? throw new ArgumentNullException(nameof(jsonSerializer));
_hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment));
_shortStringHelper = shortStringHelper ?? throw new ArgumentNullException(nameof(shortStringHelper));
_umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper));
_memberService = memberService ?? throw new ArgumentNullException(nameof(memberService));
_memberTypeService = memberTypeService ?? throw new ArgumentNullException(nameof(memberTypeService));
_modelBinderHelper = new ContentModelBinderHelper();
}
/// <summary>
/// Creates the model from the request and binds it to the context
/// </summary>
/// <param name="actionContext"></param>
/// <param name="bindingContext"></param>
/// <returns></returns>
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
var model = await _modelBinderHelper.BindModelFromMultipartRequestAsync<MemberSave>(_jsonSerializer, _hostingEnvironment, bindingContext);
if (model == null)
{
return;
}
model.PersistedContent = ContentControllerBase.IsCreatingAction(model.Action) ? CreateNew(model) : GetExisting(model);
//create the dto from the persisted model
if (model.PersistedContent != null)
{
model.PropertyCollectionDto = _umbracoMapper.Map<IMember, ContentPropertyCollectionDto>(model.PersistedContent);
//now map all of the saved values to the dto
_modelBinderHelper.MapPropertyValuesFromSaved(model, model.PropertyCollectionDto);
}
model.Name = model.Name.Trim();
bindingContext.Result = ModelBindingResult.Success(model);
}
/// <summary>
/// Returns an IMember instance used to bind values to and save (depending on the membership scenario)
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
private IMember GetExisting(MemberSave model)
{
return GetExisting(model.Key);
}
private IMember GetExisting(Guid key)
{
var member = _memberService.GetByKey(key);
if (member == null)
{
throw new InvalidOperationException("Could not find member with key " + key);
}
return member;
}
/// <summary>
/// Gets an instance of IMember used when creating a member
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
/// <remarks>
/// Depending on whether a custom membership provider is configured this will return different results.
/// </remarks>
private IMember CreateNew(MemberSave model)
{
var contentType = _memberTypeService.Get(model.ContentTypeAlias);
if (contentType == null)
{
throw new InvalidOperationException("No member type found with alias " + model.ContentTypeAlias);
}
//remove all membership properties, these values are set with the membership provider.
FilterMembershipProviderProperties(contentType);
//return the new member with the details filled in
return new Member(model.Name, model.Email, model.Username, model.Password.NewPassword, contentType);
}
/// <summary>
/// This will remove all of the special membership provider properties which were required to display the property editors
/// for editing - but the values have been mapped back to the MemberSave object directly - we don't want to keep these properties
/// on the IMember because they will attempt to be persisted which we don't want since they might not even exist.
/// </summary>
/// <param name="contentType"></param>
private void FilterMembershipProviderProperties(IContentTypeBase contentType)
{
var defaultProps = ConventionsHelper.GetStandardPropertyTypeStubs(_shortStringHelper);
//remove all membership properties, these values are set with the membership provider.
var exclude = defaultProps.Select(x => x.Value.Alias).ToArray();
FilterContentTypeProperties(contentType, exclude);
}
private void FilterContentTypeProperties(IContentTypeBase contentType, IEnumerable<string> exclude)
{
//remove all properties based on the exclusion list
foreach (var remove in exclude)
{
if (contentType.PropertyTypeExists(remove))
{
contentType.RemovePropertyType(remove);
}
}
}
}
}

View File

@@ -1,470 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.ModelBinding;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Dictionary;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.ContentEditing;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Implement;
using Umbraco.Core.Strings;
using Umbraco.Web.ContentApps;
using Umbraco.Web.Editors.Binders;
using Umbraco.Web.Editors.Filters;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi;
using Umbraco.Web.WebApi.Filters;
using Constants = Umbraco.Core.Constants;
using Umbraco.Core.Mapping;
using Umbraco.Web.Routing;
namespace Umbraco.Web.Editors
{
/// <remarks>
/// This controller is decorated with the UmbracoApplicationAuthorizeAttribute which means that any user requesting
/// access to ALL of the methods on this controller will need access to the member application.
/// </remarks>
[PluginController("UmbracoApi")]
[UmbracoApplicationAuthorize(Constants.Applications.Members)]
[OutgoingNoHyphenGuidFormat]
public class MemberController : ContentControllerBase
{
public MemberController(
IMemberPasswordConfiguration passwordConfig,
ICultureDictionary cultureDictionary,
PropertyEditorCollection propertyEditors,
IGlobalSettings globalSettings,
IUmbracoContextAccessor umbracoContextAccessor,
ISqlContext sqlContext,
ServiceContext services,
AppCaches appCaches,
IProfilingLogger logger,
IRuntimeState runtimeState,
IShortStringHelper shortStringHelper,
UmbracoMapper umbracoMapper,
IPublishedUrlProvider publishedUrlProvider)
: base(cultureDictionary, globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, shortStringHelper, umbracoMapper, publishedUrlProvider)
{
_passwordConfig = passwordConfig ?? throw new ArgumentNullException(nameof(passwordConfig));
_propertyEditors = propertyEditors ?? throw new ArgumentNullException(nameof(propertyEditors));
_passwordSecurity = new LegacyPasswordSecurity(_passwordConfig);
_passwordValidator = new ConfiguredPasswordValidator();
}
private readonly IMemberPasswordConfiguration _passwordConfig;
private readonly PropertyEditorCollection _propertyEditors;
private readonly LegacyPasswordSecurity _passwordSecurity;
private readonly IPasswordValidator _passwordValidator;
public PagedResult<MemberBasic> GetPagedResults(
int pageNumber = 1,
int pageSize = 100,
string orderBy = "username",
Direction orderDirection = Direction.Ascending,
bool orderBySystemField = true,
string filter = "",
string memberTypeAlias = null)
{
if (pageNumber <= 0 || pageSize <= 0)
{
throw new NotSupportedException("Both pageNumber and pageSize must be greater than zero");
}
var members = Services.MemberService
.GetAll((pageNumber - 1), pageSize, out var totalRecords, orderBy, orderDirection, orderBySystemField, memberTypeAlias, filter).ToArray();
if (totalRecords == 0)
{
return new PagedResult<MemberBasic>(0, 0, 0);
}
var pagedResult = new PagedResult<MemberBasic>(totalRecords, pageNumber, pageSize)
{
Items = members
.Select(x => Mapper.Map<MemberBasic>(x))
};
return pagedResult;
}
/// <summary>
/// Returns a display node with a list view to render members
/// </summary>
/// <param name="listName"></param>
/// <returns></returns>
public MemberListDisplay GetListNodeDisplay(string listName)
{
var foundType = Services.MemberTypeService.Get(listName);
var name = foundType != null ? foundType.Name : listName;
var apps = new List<ContentApp>();
apps.Add(ListViewContentAppFactory.CreateContentApp(Services.DataTypeService, _propertyEditors, listName, "member", Core.Constants.DataTypes.DefaultMembersListView));
apps[0].Active = true;
var display = new MemberListDisplay
{
ContentTypeAlias = listName,
ContentTypeName = name,
Id = listName,
IsContainer = true,
Name = listName == Constants.Conventions.MemberTypes.AllMembersListId ? "All Members" : name,
Path = "-1," + listName,
ParentId = -1,
ContentApps = apps
};
return display;
}
/// <summary>
/// Gets the content json for the member
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
// [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
public MemberDisplay GetByKey(Guid key)
{
var foundMember = Services.MemberService.GetByKey(key);
if (foundMember == null)
{
HandleContentNotFound(key);
}
return Mapper.Map<MemberDisplay>(foundMember);
}
/// <summary>
/// Gets an empty content item for the
/// </summary>
/// <param name="contentTypeAlias"></param>
/// <returns></returns>
// [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
public MemberDisplay GetEmpty(string contentTypeAlias = null)
{
IMember emptyContent;
if (contentTypeAlias == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
var contentType = Services.MemberTypeService.Get(contentTypeAlias);
if (contentType == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
var passwordGenerator = new PasswordGenerator(_passwordConfig);
emptyContent = new Member(contentType);
emptyContent.AdditionalData["NewPassword"] = passwordGenerator.GeneratePassword();
return Mapper.Map<MemberDisplay>(emptyContent);
}
/// <summary>
/// Saves member
/// </summary>
/// <returns></returns>
[FileUploadCleanupFilter]
// [OutgoingEditorModelEvent] // TODO introduce when moved to .NET Core
[MemberSaveValidation]
public async Task<MemberDisplay> PostSave(
[ModelBinder(typeof(MemberBinder))]
MemberSave contentItem)
{
//If we've reached here it means:
// * Our model has been bound
// * and validated
// * any file attachments have been saved to their temporary location for us to use
// * we have a reference to the DTO object and the persisted object
// * Permissions are valid
//map the properties to the persisted entity
MapPropertyValues(contentItem);
await ValidateMemberDataAsync(contentItem);
//Unlike content/media - if there are errors for a member, we do NOT proceed to save them, we cannot so return the errors
if (ModelState.IsValid == false)
{
var forDisplay = Mapper.Map<MemberDisplay>(contentItem.PersistedContent);
forDisplay.Errors = ModelState.ToErrorDictionary();
throw new HttpResponseException(Request.CreateValidationErrorResponse(forDisplay));
}
//We're gonna look up the current roles now because the below code can cause
// events to be raised and developers could be manually adding roles to members in
// their handlers. If we don't look this up now there's a chance we'll just end up
// removing the roles they've assigned.
var currRoles = Services.MemberService.GetAllRoles(contentItem.PersistedContent.Username);
//find the ones to remove and remove them
var rolesToRemove = currRoles.Except(contentItem.Groups).ToArray();
//Depending on the action we need to first do a create or update using the membership provider
// this ensures that passwords are formatted correctly and also performs the validation on the provider itself.
switch (contentItem.Action)
{
case ContentSaveAction.Save:
UpdateMemberData(contentItem);
break;
case ContentSaveAction.SaveNew:
contentItem.PersistedContent = CreateMemberData(contentItem);
break;
default:
//we don't support anything else for members
throw new HttpResponseException(HttpStatusCode.NotFound);
}
//TODO: There's 3 things saved here and we should do this all in one transaction, which we can do here by wrapping in a scope
// but it would be nicer to have this taken care of within the Save method itself
//create/save the IMember
Services.MemberService.Save(contentItem.PersistedContent);
//Now let's do the role provider stuff - now that we've saved the content item (that is important since
// if we are changing the username, it must be persisted before looking up the member roles).
if (rolesToRemove.Any())
{
Services.MemberService.DissociateRoles(new[] { contentItem.PersistedContent.Username }, rolesToRemove);
}
//find the ones to add and add them
var toAdd = contentItem.Groups.Except(currRoles).ToArray();
if (toAdd.Any())
{
//add the ones submitted
Services.MemberService.AssignRoles(new[] { contentItem.PersistedContent.Username }, toAdd);
}
//return the updated model
var display = Mapper.Map<MemberDisplay>(contentItem.PersistedContent);
//lastly, if it is not valid, add the model state to the outgoing object and throw a 403
HandleInvalidModelState(display);
var localizedTextService = Services.TextService;
//put the correct messages in
switch (contentItem.Action)
{
case ContentSaveAction.Save:
case ContentSaveAction.SaveNew:
display.AddSuccessNotification(localizedTextService.Localize("speechBubbles/editMemberSaved"), localizedTextService.Localize("speechBubbles/editMemberSaved"));
break;
}
return display;
}
/// <summary>
/// Maps the property values to the persisted entity
/// </summary>
/// <param name="contentItem"></param>
private void MapPropertyValues(MemberSave contentItem)
{
UpdateName(contentItem);
//map the custom properties - this will already be set for new entities in our member binder
contentItem.PersistedContent.Email = contentItem.Email;
contentItem.PersistedContent.Username = contentItem.Username;
//use the base method to map the rest of the properties
base.MapPropertyValuesForPersistence<IMember, MemberSave>(
contentItem,
contentItem.PropertyCollectionDto,
(save, property) => property.GetValue(), //get prop val
(save, property, v) => property.SetValue(v), //set prop val
null); // member are all invariant
}
private IMember CreateMemberData(MemberSave contentItem)
{
var memberType = Services.MemberTypeService.Get(contentItem.ContentTypeAlias);
if (memberType == null)
throw new InvalidOperationException($"No member type found with alias {contentItem.ContentTypeAlias}");
var member = new Member(contentItem.Name, contentItem.Email, contentItem.Username, memberType, true)
{
CreatorId = Security.CurrentUser.Id,
RawPasswordValue = _passwordSecurity.HashPasswordForStorage(contentItem.Password.NewPassword),
Comments = contentItem.Comments,
IsApproved = contentItem.IsApproved
};
return member;
}
/// <summary>
/// Update the member security data
/// </summary>
/// <param name="contentItem"></param>
/// <returns>
/// If the password has been reset then this method will return the reset/generated password, otherwise will return null.
/// </returns>
private void UpdateMemberData(MemberSave contentItem)
{
contentItem.PersistedContent.WriterId = Security.CurrentUser.Id;
// If the user doesn't have access to sensitive values, then we need to check if any of the built in member property types
// have been marked as sensitive. If that is the case we cannot change these persisted values no matter what value has been posted.
// There's only 3 special ones we need to deal with that are part of the MemberSave instance: Comments, IsApproved, IsLockedOut
// but we will take care of this in a generic way below so that it works for all props.
if (!Security.CurrentUser.HasAccessToSensitiveData())
{
var memberType = Services.MemberTypeService.Get(contentItem.PersistedContent.ContentTypeId);
var sensitiveProperties = memberType
.PropertyTypes.Where(x => memberType.IsSensitiveProperty(x.Alias))
.ToList();
foreach (var sensitiveProperty in sensitiveProperties)
{
var destProp = contentItem.Properties.FirstOrDefault(x => x.Alias == sensitiveProperty.Alias);
if (destProp != null)
{
//if found, change the value of the contentItem model to the persisted value so it remains unchanged
var origValue = contentItem.PersistedContent.GetValue(sensitiveProperty.Alias);
destProp.Value = origValue;
}
}
}
var isLockedOut = contentItem.IsLockedOut;
//if they were locked but now they are trying to be unlocked
if (contentItem.PersistedContent.IsLockedOut && isLockedOut == false)
{
contentItem.PersistedContent.IsLockedOut = false;
contentItem.PersistedContent.FailedPasswordAttempts = 0;
}
else if (!contentItem.PersistedContent.IsLockedOut && isLockedOut)
{
//NOTE: This should not ever happen unless someone is mucking around with the request data.
//An admin cannot simply lock a user, they get locked out by password attempts, but an admin can un-approve them
ModelState.AddModelError("custom", "An admin cannot lock a user");
}
//no password changes then exit ?
if (contentItem.Password == null)
return;
// set the password
contentItem.PersistedContent.RawPasswordValue = _passwordSecurity.HashPasswordForStorage(contentItem.Password.NewPassword);
}
private static void UpdateName(MemberSave memberSave)
{
//Don't update the name if it is empty
if (memberSave.Name.IsNullOrWhiteSpace() == false)
{
memberSave.PersistedContent.Name = memberSave.Name;
}
}
// TODO: This logic should be pulled into the service layer
private async Task<bool> ValidateMemberDataAsync(MemberSave contentItem)
{
if (contentItem.Name.IsNullOrWhiteSpace())
{
ModelState.AddPropertyError(
new ValidationResult("Invalid user name", new[] { "value" }),
string.Format("{0}login", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
return false;
}
if (contentItem.Password != null && !contentItem.Password.NewPassword.IsNullOrWhiteSpace())
{
var validPassword = await _passwordValidator.ValidateAsync(_passwordConfig, contentItem.Password.NewPassword);
if (!validPassword)
{
ModelState.AddPropertyError(
new ValidationResult("Invalid password: " + string.Join(", ", validPassword.Result), new[] { "value" }),
string.Format("{0}password", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
return false;
}
}
var byUsername = Services.MemberService.GetByUsername(contentItem.Username);
if (byUsername != null && byUsername.Key != contentItem.Key)
{
ModelState.AddPropertyError(
new ValidationResult("Username is already in use", new[] { "value" }),
string.Format("{0}login", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
return false;
}
var byEmail = Services.MemberService.GetByEmail(contentItem.Email);
if (byEmail != null && byEmail.Key != contentItem.Key)
{
ModelState.AddPropertyError(
new ValidationResult("Email address is already in use", new[] { "value" }),
string.Format("{0}email", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
return false;
}
return true;
}
/// <summary>
/// Permanently deletes a member
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
///
[HttpPost]
public HttpResponseMessage DeleteByKey(Guid key)
{
var foundMember = Services.MemberService.GetByKey(key);
if (foundMember == null)
{
return HandleContentNotFound(key, false);
}
Services.MemberService.Delete(foundMember);
return Request.CreateResponse(HttpStatusCode.OK);
}
/// <summary>
/// Exports member data based on their unique Id
/// </summary>
/// <param name="key">The unique <see cref="Guid">member identifier</see></param>
/// <returns><see cref="HttpResponseMessage"/></returns>
[HttpGet]
public HttpResponseMessage ExportMemberData(Guid key)
{
var currentUser = Security.CurrentUser;
var httpResponseMessage = Request.CreateResponse();
if (currentUser.HasAccessToSensitiveData() == false)
{
httpResponseMessage.StatusCode = HttpStatusCode.Forbidden;
return httpResponseMessage;
}
var member = ((MemberService)Services.MemberService).ExportMember(key);
var fileName = $"{member.Name}_{member.Email}.txt";
httpResponseMessage.Content = new ObjectContent<MemberExportModel>(member, new JsonMediaTypeFormatter { Indent = true });
httpResponseMessage.Content.Headers.Add("x-filename", fileName);
httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
httpResponseMessage.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
httpResponseMessage.Content.Headers.ContentDisposition.FileName = fileName;
httpResponseMessage.StatusCode = HttpStatusCode.OK;
return httpResponseMessage;
}
}
}

View File

@@ -308,7 +308,6 @@
<Compile Include="Mvc\UmbracoViewPage.cs" />
<Compile Include="Editors\MemberTypeController.cs" />
<Compile Include="Editors\EntityController.cs" />
<Compile Include="Editors\MemberController.cs" />
<Compile Include="Editors\CurrentUserController.cs" />
<Compile Include="ImageCropperTemplateExtensions.cs" />
<Compile Include="Mvc\UmbracoVirtualNodeRouteHandler.cs" />
@@ -367,11 +366,9 @@
<Compile Include="CdfLogger.cs" />
<Compile Include="Controllers\UmbLoginController.cs" />
<Compile Include="UrlHelperExtensions.cs" />
<Compile Include="Editors\MediaController.cs" />
<Compile Include="UrlHelperRenderExtensions.cs" />
<Compile Include="WebApi\IsBackOfficeAttribute.cs" />
<Compile Include="Editors\Filters\ContentModelValidator.cs" />
<Compile Include="WebApi\Filters\EnsureUserPermissionForMediaAttribute.cs" />
<Compile Include="WebApi\Filters\FileUploadCleanupFilterAttribute.cs" />
<Compile Include="WebApi\Filters\OutgoingDateTimeFormatAttribute.cs" />
<Compile Include="WebApi\Filters\UmbracoApplicationAuthorizeAttribute.cs" />
@@ -456,8 +453,5 @@
<Link>Mvc\web.config</Link>
</None>
</ItemGroup>
<ItemGroup>
<Folder Include="Editors\Binders" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -1,137 +0,0 @@
using System;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Web.Composing;
using Umbraco.Web.Editors;
namespace Umbraco.Web.WebApi.Filters
{
/// <summary>
/// Auth filter to check if the current user has access to the content item
/// </summary>
/// <remarks>
/// Since media doesn't have permissions, this simply checks start node access
/// </remarks>
internal sealed class EnsureUserPermissionForMediaAttribute : ActionFilterAttribute
{
private readonly int? _nodeId;
private readonly string _paramName;
public enum DictionarySource
{
ActionArguments,
RequestForm,
RequestQueryString
}
/// <summary>
/// This constructor will only be able to test the start node access
/// </summary>
public EnsureUserPermissionForMediaAttribute(int nodeId)
{
_nodeId = nodeId;
}
public EnsureUserPermissionForMediaAttribute(string paramName)
{
if (paramName == null) throw new ArgumentNullException(nameof(paramName));
if (string.IsNullOrEmpty(paramName)) throw new ArgumentException("Value can't be empty.", nameof(paramName));
_paramName = paramName;
}
// TODO: v8 guess this is not used anymore, source is ignored?!
public EnsureUserPermissionForMediaAttribute(string paramName, DictionarySource source)
{
if (paramName == null) throw new ArgumentNullException(nameof(paramName));
if (string.IsNullOrEmpty(paramName)) throw new ArgumentException("Value can't be empty.", nameof(paramName));
_paramName = paramName;
}
public override bool AllowMultiple => true;
private int GetNodeIdFromParameter(object parameterValue)
{
if (parameterValue is int)
{
return (int) parameterValue;
}
var guidId = Guid.Empty;
if (parameterValue is Guid)
{
guidId = (Guid)parameterValue;
}
else if (parameterValue is GuidUdi)
{
guidId = ((GuidUdi) parameterValue).Guid;
}
if (guidId != Guid.Empty)
{
var found = Current.Services.EntityService.GetId(guidId, UmbracoObjectTypes.Media);
if (found)
return found.Result;
}
throw new InvalidOperationException("The id type: " + parameterValue.GetType() + " is not a supported id");
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (Current.UmbracoContext.Security.CurrentUser == null)
{
throw new HttpResponseException(System.Net.HttpStatusCode.Unauthorized);
}
int nodeId;
if (_nodeId.HasValue == false)
{
var parts = _paramName.Split(new [] { '.' }, StringSplitOptions.RemoveEmptyEntries);
if (actionContext.ActionArguments[parts[0]] == null)
{
throw new InvalidOperationException("No argument found for the current action with the name: " + _paramName);
}
if (parts.Length == 1)
{
nodeId = GetNodeIdFromParameter(actionContext.ActionArguments[parts[0]]);
}
else
{
//now we need to see if we can get the property of whatever object it is
var pType = actionContext.ActionArguments[parts[0]].GetType();
var prop = pType.GetProperty(parts[1]);
if (prop == null)
{
throw new InvalidOperationException("No argument found for the current action with the name: " + _paramName);
}
nodeId = GetNodeIdFromParameter(prop.GetValue(actionContext.ActionArguments[parts[0]]));
}
}
else
{
nodeId = _nodeId.Value;
}
if (MediaController.CheckPermissions(
actionContext.Request.Properties,
Current.UmbracoContext.Security.CurrentUser,
Current.Services.MediaService,
Current.Services.EntityService,
nodeId))
{
base.OnActionExecuting(actionContext);
}
else
{
throw new HttpResponseException(System.Net.HttpStatusCode.Unauthorized);
}
}
}
}