+
+
+ Hide this property value from content editors that don't have access to view sensitive information
+
+
diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
index b17ee5c61e..d4cd37e938 100644
--- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
+++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
@@ -332,8 +332,8 @@
umbraco.providers
-
- ..\packages\Umbraco.ModelsBuilder.3.0.8\lib\Umbraco.ModelsBuilder.dll
+
+ ..\packages\Umbraco.ModelsBuilder.3.0.10\lib\Umbraco.ModelsBuilder.dll
@@ -1028,8 +1028,10 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\"
/
http://localhost:7900
7790
+ http://localhost:7800
+ 7800
/
- http://localhost:7790
+ http://localhost:7800
False
False
diff --git a/src/Umbraco.Web.UI/config/BackOfficeTours/getting-started.json b/src/Umbraco.Web.UI/config/BackOfficeTours/getting-started.json
index 36350b5d18..f2bf531ab4 100644
--- a/src/Umbraco.Web.UI/config/BackOfficeTours/getting-started.json
+++ b/src/Umbraco.Web.UI/config/BackOfficeTours/getting-started.json
@@ -5,6 +5,15 @@
"group": "Getting Started",
"groupOrder": 100,
"allowDisable": true,
+ "requiredSections": [
+ "content",
+ "media",
+ "settings",
+ "developer",
+ "users",
+ "member",
+ "forms"
+ ],
"steps": [
{
"title": "Welcome to Umbraco - The Friendly CMS",
@@ -25,7 +34,6 @@
"content": "Each area in Umbraco is called a Section. Right now you are in the Content section, when you want to go to another section simply click on the appropriate icon in the main menu and you'll be there in no time.",
"backdropOpacity": 0.6
},
-
{
"element": "#tree",
"elementPreventClick": true,
@@ -88,6 +96,15 @@
"alias": "umbIntroCreateDocType",
"group": "Getting Started",
"groupOrder": 100,
+ "requiredSections": [
+ "content",
+ "media",
+ "settings",
+ "developer",
+ "users",
+ "member",
+ "forms"
+ ],
"steps": [
{
"title": "Create your first Document Type",
@@ -203,6 +220,15 @@
"alias": "umbIntroCreateContent",
"group": "Getting Started",
"groupOrder": 100,
+ "requiredSections": [
+ "content",
+ "media",
+ "settings",
+ "developer",
+ "users",
+ "member",
+ "forms"
+ ],
"steps": [
{
"title": "Creating your first content node",
@@ -253,6 +279,15 @@
"alias": "umbIntroRenderInTemplate",
"group": "Getting Started",
"groupOrder": 100,
+ "requiredSections": [
+ "content",
+ "media",
+ "settings",
+ "developer",
+ "users",
+ "member",
+ "forms"
+ ],
"steps": [
{
"title": "Render your content in a template",
@@ -299,6 +334,15 @@
"alias": "umbIntroViewHomePage",
"group": "Getting Started",
"groupOrder": 100,
+ "requiredSections": [
+ "content",
+ "media",
+ "settings",
+ "developer",
+ "users",
+ "member",
+ "forms"
+ ],
"steps": [
{
"title": "View your Umbraco site",
@@ -339,6 +383,15 @@
"alias": "umbIntroMediaSection",
"group": "Getting Started",
"groupOrder": 100,
+ "requiredSections": [
+ "content",
+ "media",
+ "settings",
+ "developer",
+ "users",
+ "member",
+ "forms"
+ ],
"steps": [
{
"title": "How to use the media library",
diff --git a/src/Umbraco.Web.UI/packages.config b/src/Umbraco.Web.UI/packages.config
index c72ff9aa8c..8a4b77ca3a 100644
--- a/src/Umbraco.Web.UI/packages.config
+++ b/src/Umbraco.Web.UI/packages.config
@@ -36,5 +36,5 @@
-
+
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI/umbraco/Views/Default.cshtml b/src/Umbraco.Web.UI/umbraco/Views/Default.cshtml
index 388ffcf6ba..d0b0118870 100644
--- a/src/Umbraco.Web.UI/umbraco/Views/Default.cshtml
+++ b/src/Umbraco.Web.UI/umbraco/Views/Default.cshtml
@@ -43,6 +43,7 @@
+
Umbraco
diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml
index 1bd8673b43..64eef18fd1 100644
--- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml
+++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml
@@ -221,6 +221,7 @@
Add another text box
Remove this text box
Content root
+ This value is hidden. If you need access to view this value please contact your website administrator.
Create a new Content Template from '%0%'
@@ -510,6 +511,7 @@
There is a configuration error with the data type used for this property, please check the data type
+ Options
About
Action
Actions
@@ -1609,7 +1611,12 @@ To manage your website, simply open the Umbraco back office and start adding con
using this editor will get updated with the new settings
Member can edit
+ Allow this property value to be edited by the member on their profile page
+ Is sensitive data
+ Hide this property value from content editors that don't have access to view sensitive information
Show on member profile
+ Allow this property value to be displayed on the member profile page
+
tab has no sort order
diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml
index b9375420bd..d2b6ca6f82 100644
--- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml
+++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml
@@ -227,6 +227,7 @@
Add another text box
Remove this text box
Content root
+ This value is hidden. If you need access to view this value please contact your website administrator.
Create a new Content Template from '%0%'
@@ -516,6 +517,7 @@
There is a configuration error with the data type used for this property, please check the data type
+ Options
About
Action
Actions
@@ -1613,7 +1615,12 @@ To manage your website, simply open the Umbraco back office and start adding con
using this editor will get updated with the new settings
Member can edit
+ Allow this property value to be edited by the member on their profile page
+ Is sensitive data
+ Hide this property value from content editors that don't have access to view sensitive information
Show on member profile
+ Allow this property value to be displayed on the member profile page
+
tab has no sort order
diff --git a/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs b/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs
index 2d61b254a0..6d3ce6bb57 100644
--- a/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs
+++ b/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs
@@ -1,6 +1,6 @@
using System;
using System.Linq;
-using System.Web.Script.Serialization;
+using System.Web;
using Newtonsoft.Json;
using Umbraco.Core;
using Umbraco.Core.Cache;
@@ -83,36 +83,28 @@ namespace Umbraco.Web.Cache
public override void Refresh(string jsonPayload)
{
- ClearCache(DeserializeFromJsonPayload(jsonPayload));
+ ClearCache();
base.Refresh(jsonPayload);
}
public override void Refresh(int id)
{
- ClearCache(FromMemberGroup(ApplicationContext.Current.Services.MemberGroupService.GetById(id)));
+ ClearCache();
base.Refresh(id);
}
public override void Remove(int id)
{
- ClearCache(FromMemberGroup(ApplicationContext.Current.Services.MemberGroupService.GetById(id)));
+ ClearCache();
base.Remove(id);
}
- private void ClearCache(params JsonPayload[] payloads)
+ private void ClearCache()
{
- if (payloads == null) return;
-
- var memberGroupCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache();
- payloads.ForEach(payload =>
- {
- if (payload != null && memberGroupCache)
- {
- memberGroupCache.Result.ClearCacheByKeySearch(string.Format("{0}.{1}", typeof(IMemberGroup).FullName, payload.Name));
- memberGroupCache.Result.ClearCacheItem(RepositoryBase.GetCacheIdKey(payload.Id));
- }
- });
-
+ // Since we cache by group name, it could be problematic when renaming to
+ // previously existing names - see http://issues.umbraco.org/issue/U4-10846.
+ // To work around this, just clear all the cache items
+ ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.ClearCache();
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs
index a61ca7e249..be78638a9e 100644
--- a/src/Umbraco.Web/Editors/ContentController.cs
+++ b/src/Umbraco.Web/Editors/ContentController.cs
@@ -80,7 +80,7 @@ namespace Umbraco.Web.Editors
public IEnumerable GetByIds([FromUri]int[] ids)
{
var foundContent = Services.ContentService.GetByIds(ids);
- return foundContent.Select(Mapper.Map);
+ return foundContent.Select(content => AutoMapperExtensions.MapWithUmbracoContext(content, UmbracoContext));
}
///
@@ -219,7 +219,7 @@ namespace Umbraco.Web.Editors
Path = "-1," + Constants.System.RecycleBinContent
};
- TabsAndPropertiesResolver.AddListView(display, "content", Services.DataTypeService, Services.TextService);
+ TabsAndPropertiesResolver.AddListView(display, "content", Services.DataTypeService, Services.TextService);
return display;
}
@@ -232,7 +232,7 @@ namespace Umbraco.Web.Editors
HandleContentNotFound(id);
}
- var content = Mapper.Map(foundContent);
+ var content = AutoMapperExtensions.MapWithUmbracoContext(foundContent, UmbracoContext);
SetupBlueprint(content, foundContent);
@@ -270,7 +270,7 @@ namespace Umbraco.Web.Editors
HandleContentNotFound(id);
}
- var content = Mapper.Map(foundContent);
+ var content = AutoMapperExtensions.MapWithUmbracoContext(foundContent, UmbracoContext);
return content;
}
@@ -283,7 +283,7 @@ namespace Umbraco.Web.Editors
HandleContentNotFound(id);
}
- var content = Mapper.Map(foundContent);
+ var content = AutoMapperExtensions.MapWithUmbracoContext(foundContent, UmbracoContext);
return content;
}
@@ -306,7 +306,7 @@ namespace Umbraco.Web.Editors
}
var emptyContent = Services.ContentService.CreateContent("", parentId, contentType.Alias, UmbracoUser.Id);
- var mapped = Mapper.Map(emptyContent);
+ var mapped = AutoMapperExtensions.MapWithUmbracoContext(emptyContent, UmbracoContext);
//remove this tab if it exists: umbContainerView
var containerTab = mapped.Tabs.FirstOrDefault(x => x.Alias == Constants.Conventions.PropertyGroups.ListViewGroupName);
@@ -563,7 +563,7 @@ namespace Umbraco.Web.Editors
{
//ok, so the absolute mandatory data is invalid and it's new, we cannot actually continue!
// add the modelstate to the outgoing object and throw a validation message
- var forDisplay = Mapper.Map(contentItem.PersistedContent);
+ var forDisplay = AutoMapperExtensions.MapWithUmbracoContext(contentItem.PersistedContent, UmbracoContext);
forDisplay.Errors = ModelState.ToErrorDictionary();
throw new HttpResponseException(Request.CreateValidationErrorResponse(forDisplay));
@@ -605,7 +605,7 @@ namespace Umbraco.Web.Editors
}
//return the updated model
- var display = Mapper.Map(contentItem.PersistedContent);
+ var display = AutoMapperExtensions.MapWithUmbracoContext(contentItem.PersistedContent, UmbracoContext);
//lasty, if it is not valid, add the modelstate to the outgoing object and throw a 403
HandleInvalidModelState(display);
@@ -858,7 +858,7 @@ namespace Umbraco.Web.Editors
var unpublishResult = Services.ContentService.WithResult().UnPublish(foundContent, Security.CurrentUser.Id);
- var content = Mapper.Map(foundContent);
+ var content = AutoMapperExtensions.MapWithUmbracoContext(foundContent, UmbracoContext);
if (unpublishResult == false)
{
@@ -1092,4 +1092,4 @@ namespace Umbraco.Web.Editors
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Umbraco.Web/Editors/MediaController.cs b/src/Umbraco.Web/Editors/MediaController.cs
index 72af1c4c70..e22c83cbeb 100644
--- a/src/Umbraco.Web/Editors/MediaController.cs
+++ b/src/Umbraco.Web/Editors/MediaController.cs
@@ -89,7 +89,7 @@ namespace Umbraco.Web.Editors
}
var emptyContent = Services.MediaService.CreateMedia("", parentId, contentType.Alias, UmbracoUser.Id);
- var mapped = Mapper.Map(emptyContent);
+ var mapped = AutoMapperExtensions.MapWithUmbracoContext(emptyContent, UmbracoContext);
//remove this tab if it exists: umbContainerView
var containerTab = mapped.Tabs.FirstOrDefault(x => x.Alias == Constants.Conventions.PropertyGroups.ListViewGroupName);
@@ -115,7 +115,7 @@ namespace Umbraco.Web.Editors
Path = "-1," + Constants.System.RecycleBinMedia
};
- TabsAndPropertiesResolver.AddListView(display, "media", Services.DataTypeService, Services.TextService);
+ TabsAndPropertiesResolver.AddListView(display, "media", Services.DataTypeService, Services.TextService);
return display;
}
@@ -137,7 +137,7 @@ namespace Umbraco.Web.Editors
//HandleContentNotFound will throw an exception
return null;
}
- return Mapper.Map(foundContent);
+ return AutoMapperExtensions.MapWithUmbracoContext(foundContent, UmbracoContext);
}
///
@@ -157,7 +157,7 @@ namespace Umbraco.Web.Editors
//HandleContentNotFound will throw an exception
return null;
}
- return Mapper.Map(foundContent);
+ return AutoMapperExtensions.MapWithUmbracoContext(foundContent, UmbracoContext);
}
///
@@ -186,7 +186,7 @@ namespace Umbraco.Web.Editors
public IEnumerable GetByIds([FromUri]int[] ids)
{
var foundMedia = Services.MediaService.GetByIds(ids);
- return foundMedia.Select(Mapper.Map);
+ return foundMedia.Select(media => AutoMapperExtensions.MapWithUmbracoContext(media, UmbracoContext));
}
///
@@ -488,7 +488,7 @@ namespace Umbraco.Web.Editors
{
//ok, so the absolute mandatory data is invalid and it's new, we cannot actually continue!
// add the modelstate to the outgoing object and throw validation response
- var forDisplay = Mapper.Map(contentItem.PersistedContent);
+ var forDisplay = AutoMapperExtensions.MapWithUmbracoContext(contentItem.PersistedContent, UmbracoContext);
forDisplay.Errors = ModelState.ToErrorDictionary();
throw new HttpResponseException(Request.CreateValidationErrorResponse(forDisplay));
}
@@ -498,7 +498,7 @@ namespace Umbraco.Web.Editors
var saveStatus = Services.MediaService.WithResult().Save(contentItem.PersistedContent, (int)Security.CurrentUser.Id);
//return the updated model
- var display = Mapper.Map(contentItem.PersistedContent);
+ var display = AutoMapperExtensions.MapWithUmbracoContext(contentItem.PersistedContent, UmbracoContext);
//lasty, if it is not valid, add the modelstate to the outgoing object and throw a 403
HandleInvalidModelState(display);
@@ -607,7 +607,7 @@ namespace Umbraco.Web.Editors
var f = mediaService.CreateMedia(folder.Name, intParentId, Constants.Conventions.MediaTypes.Folder);
mediaService.Save(f, Security.CurrentUser.Id);
- return Mapper.Map(f);
+ return AutoMapperExtensions.MapWithUmbracoContext(f, UmbracoContext);
}
///
diff --git a/src/Umbraco.Web/Editors/MemberController.cs b/src/Umbraco.Web/Editors/MemberController.cs
index 5aad40aa70..2440ad0691 100644
--- a/src/Umbraco.Web/Editors/MemberController.cs
+++ b/src/Umbraco.Web/Editors/MemberController.cs
@@ -154,7 +154,7 @@ namespace Umbraco.Web.Editors
ParentId = -1
};
- TabsAndPropertiesResolver.AddListView(display, "member", Services.DataTypeService, Services.TextService);
+ TabsAndPropertiesResolver.AddListView(display, "member", Services.DataTypeService, Services.TextService);
return display;
}
@@ -178,7 +178,7 @@ namespace Umbraco.Web.Editors
{
HandleContentNotFound(key);
}
- return Mapper.Map(foundMember);
+ return AutoMapperExtensions.MapWithUmbracoContext(foundMember, UmbracoContext);
case MembershipScenario.CustomProviderWithUmbracoLink:
//TODO: Support editing custom properties for members with a custom membership provider here.
@@ -238,7 +238,7 @@ namespace Umbraco.Web.Editors
emptyContent = new Member(contentType);
emptyContent.AdditionalData["NewPassword"] = Membership.GeneratePassword(provider.MinRequiredPasswordLength, provider.MinRequiredNonAlphanumericCharacters);
- return Mapper.Map(emptyContent);
+ return AutoMapperExtensions.MapWithUmbracoContext(emptyContent, UmbracoContext);
case MembershipScenario.CustomProviderWithUmbracoLink:
//TODO: Support editing custom properties for members with a custom membership provider here.
@@ -247,7 +247,7 @@ namespace Umbraco.Web.Editors
//we need to return a scaffold of a 'simple' member - basically just what a membership provider can edit
emptyContent = MemberService.CreateGenericMembershipProviderMember("", "", "", "");
emptyContent.AdditionalData["NewPassword"] = Membership.GeneratePassword(Membership.MinRequiredPasswordLength, Membership.MinRequiredNonAlphanumericCharacters);
- return Mapper.Map(emptyContent);
+ return AutoMapperExtensions.MapWithUmbracoContext(emptyContent, UmbracoContext);
}
}
@@ -287,7 +287,7 @@ namespace Umbraco.Web.Editors
//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(contentItem.PersistedContent);
+ var forDisplay = AutoMapperExtensions.MapWithUmbracoContext(contentItem.PersistedContent, UmbracoContext);
forDisplay.Errors = ModelState.ToErrorDictionary();
throw new HttpResponseException(Request.CreateValidationErrorResponse(forDisplay));
}
@@ -329,7 +329,7 @@ namespace Umbraco.Web.Editors
//If we've had problems creating/updating the user with the provider then return the error
if (ModelState.IsValid == false)
{
- var forDisplay = Mapper.Map(contentItem.PersistedContent);
+ var forDisplay = AutoMapperExtensions.MapWithUmbracoContext(contentItem.PersistedContent, UmbracoContext);
forDisplay.Errors = ModelState.ToErrorDictionary();
throw new HttpResponseException(Request.CreateValidationErrorResponse(forDisplay));
}
@@ -367,7 +367,7 @@ namespace Umbraco.Web.Editors
contentItem.PersistedContent.AdditionalData["GeneratedPassword"] = generatedPassword;
//return the updated model
- var display = Mapper.Map(contentItem.PersistedContent);
+ var display = AutoMapperExtensions.MapWithUmbracoContext(contentItem.PersistedContent, UmbracoContext);
//lasty, if it is not valid, add the modelstate to the outgoing object and throw a 403
HandleInvalidModelState(display);
diff --git a/src/Umbraco.Web/Editors/MemberTypeController.cs b/src/Umbraco.Web/Editors/MemberTypeController.cs
index 1d8766f253..45486125e7 100644
--- a/src/Umbraco.Web/Editors/MemberTypeController.cs
+++ b/src/Umbraco.Web/Editors/MemberTypeController.cs
@@ -131,9 +131,43 @@ namespace Umbraco.Web.Editors
public MemberTypeDisplay PostSave(MemberTypeSave contentTypeSave)
{
+ //get the persisted member type
+ var ctId = Convert.ToInt32(contentTypeSave.Id);
+ var ct = ctId > 0 ? Services.MemberTypeService.Get(ctId) : null;
+
+ if (UmbracoContext.Security.CurrentUser.HasAccessToSensitiveData() == false)
+ {
+ //We need to validate if any properties on the contentTypeSave have had their IsSensitiveValue changed,
+ //and if so, we need to check if the current user has access to sensitive values. If not, we have to return an error
+ var props = contentTypeSave.Groups.SelectMany(x => x.Properties);
+ if (ct != null)
+ {
+ foreach (var prop in props)
+ {
+ var foundOnContentType = ct.PropertyTypes.FirstOrDefault(x => x.Id == prop.Id);
+ if (foundOnContentType == null)
+ throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.NotFound, "No property type with id " + prop.Id + " found on the content type"));
+ if (ct.IsSensitiveProperty(foundOnContentType.Alias) && prop.IsSensitiveData == false)
+ {
+ //if these don't match, then we cannot continue, this user is not allowed to change this value
+ throw new HttpResponseException(HttpStatusCode.Forbidden);
+ }
+ }
+ }
+ else
+ {
+ //if it is new, then we can just verify if any property has sensitive data turned on which is not allowed
+ if (props.Any(prop => prop.IsSensitiveData))
+ {
+ throw new HttpResponseException(HttpStatusCode.Forbidden);
+ }
+ }
+ }
+
+
var savedCt = PerformPostSave(
contentTypeSave: contentTypeSave,
- getContentType: i => Services.MemberTypeService.Get(i),
+ getContentType: i => ct,
saveContentType: type => Services.MemberTypeService.Save(type));
var display = Mapper.Map(savedCt);
@@ -145,4 +179,4 @@ namespace Umbraco.Web.Editors
return display;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Umbraco.Web/Editors/TourController.cs b/src/Umbraco.Web/Editors/TourController.cs
index 152879bf5a..da16659cfe 100644
--- a/src/Umbraco.Web/Editors/TourController.cs
+++ b/src/Umbraco.Web/Editors/TourController.cs
@@ -7,8 +7,6 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Web.Models;
using Umbraco.Web.Mvc;
-using Umbraco.Web.WebApi.Filters;
-using Constants = Umbraco.Core.Constants;
namespace Umbraco.Web.Editors
{
@@ -23,7 +21,7 @@ namespace Umbraco.Web.Editors
return result;
var filters = TourFilterResolver.Current.Filters.ToList();
-
+
//get all filters that will be applied to all tour aliases
var aliasOnlyFilters = filters.Where(x => x.PluginName == null && x.TourFileName == null).ToList();
@@ -64,8 +62,28 @@ namespace Umbraco.Web.Editors
}
}
}
+ //Get all allowed sections for the current user
+ var allowedSections = UmbracoContext.Current.Security.CurrentUser.AllowedSections.ToList();
- return result.OrderBy(x => x.FileName, StringComparer.InvariantCultureIgnoreCase);
+ var toursToBeRemoved = new List();
+
+ //Checking to see if the user has access to the required tour sections, else we remove the tour
+ foreach (var backOfficeTourFile in result)
+ {
+ foreach (var tour in backOfficeTourFile.Tours)
+ {
+ foreach (var toursRequiredSection in tour.RequiredSections)
+ {
+ if (allowedSections.Contains(toursRequiredSection) == false)
+ {
+ toursToBeRemoved.Add(backOfficeTourFile);
+ break;
+ }
+ }
+ }
+ }
+
+ return result.Except(toursToBeRemoved).OrderBy(x => x.FileName, StringComparer.InvariantCultureIgnoreCase);
}
private void TryParseTourFile(string tourFile,
@@ -79,7 +97,7 @@ namespace Umbraco.Web.Editors
//get the filters specific to this file
var fileFilters = filters.Where(x => x.TourFileName != null && x.TourFileName.IsMatch(fileName)).ToList();
-
+
//If there is any filter applied to match the file only (no tour alias) then ignore the file entirely
var isFileFiltered = fileFilters.Any(x => x.TourAlias == null);
if (isFileFiltered) return;
@@ -117,4 +135,4 @@ namespace Umbraco.Web.Editors
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Umbraco.Web/Models/BackOfficeTour.cs b/src/Umbraco.Web/Models/BackOfficeTour.cs
index a973a92429..78a4cd1897 100644
--- a/src/Umbraco.Web/Models/BackOfficeTour.cs
+++ b/src/Umbraco.Web/Models/BackOfficeTour.cs
@@ -1,4 +1,5 @@
-using System.Runtime.Serialization;
+using System.Collections.Generic;
+using System.Runtime.Serialization;
namespace Umbraco.Web.Models
{
@@ -18,6 +19,8 @@ namespace Umbraco.Web.Models
public int GroupOrder { get; set; }
[DataMember(Name = "allowDisable")]
public bool AllowDisable { get; set; }
+ [DataMember(Name = "requiredSections")]
+ public List RequiredSections { get; set; }
[DataMember(Name = "steps")]
public BackOfficeTourStep[] Steps { get; set; }
}
diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDisplay.cs
index 343b018000..8a09c62333 100644
--- a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDisplay.cs
+++ b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDisplay.cs
@@ -34,6 +34,9 @@ namespace Umbraco.Web.Models.ContentEditing
public bool HideLabel { get; set; }
[DataMember(Name = "validation")]
- public PropertyTypeValidation Validation { get; set; }
+ public PropertyTypeValidation Validation { get; set; }
+
+ [DataMember(Name = "readonly")]
+ public bool Readonly { get; set; }
}
-}
\ No newline at end of file
+}
diff --git a/src/Umbraco.Web/Models/ContentEditing/MemberPropertyTypeBasic.cs b/src/Umbraco.Web/Models/ContentEditing/MemberPropertyTypeBasic.cs
index dfe98461dd..a1f5af645b 100644
--- a/src/Umbraco.Web/Models/ContentEditing/MemberPropertyTypeBasic.cs
+++ b/src/Umbraco.Web/Models/ContentEditing/MemberPropertyTypeBasic.cs
@@ -13,5 +13,8 @@ namespace Umbraco.Web.Models.ContentEditing
[DataMember(Name = "memberCanEdit")]
public bool MemberCanEditProperty { get; set; }
+
+ [DataMember(Name = "isSensitiveData")]
+ public bool IsSensitiveData { get; set; }
}
-}
\ No newline at end of file
+}
diff --git a/src/Umbraco.Web/Models/ContentEditing/MemberPropertyTypeDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/MemberPropertyTypeDisplay.cs
index 8f7d4be310..bdbf19e68e 100644
--- a/src/Umbraco.Web/Models/ContentEditing/MemberPropertyTypeDisplay.cs
+++ b/src/Umbraco.Web/Models/ContentEditing/MemberPropertyTypeDisplay.cs
@@ -10,5 +10,8 @@ namespace Umbraco.Web.Models.ContentEditing
[DataMember(Name = "memberCanEdit")]
public bool MemberCanEditProperty { get; set; }
+
+ [DataMember(Name = "isSensitiveData")]
+ public bool IsSensitiveData { get; set; }
}
-}
\ No newline at end of file
+}
diff --git a/src/Umbraco.Web/Models/Mapping/AutoMapperExtensions.cs b/src/Umbraco.Web/Models/Mapping/AutoMapperExtensions.cs
new file mode 100644
index 0000000000..e5850b2689
--- /dev/null
+++ b/src/Umbraco.Web/Models/Mapping/AutoMapperExtensions.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using AutoMapper;
+using Umbraco.Core.Models;
+using Umbraco.Web.Models.ContentEditing;
+
+namespace Umbraco.Web.Models.Mapping
+{
+ internal static class AutoMapperExtensions
+ {
+ ///
+ /// This maps an object and passes in the current so the mapping logic can use it
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static TOut MapWithUmbracoContext(TIn obj, UmbracoContext umbCtx)
+ {
+ return Mapper.Map(obj, opt => opt.Items["UmbracoContext"] = umbCtx);
+ }
+
+ ///
+ /// Returns an from the mapping options
+ ///
+ ///
+ ///
+ ///
+ /// If an UmbracoContext is not found in the mapping options, it will try to retrieve it from the singleton
+ ///
+ public static UmbracoContext GetUmbracoContext(this ResolutionContext res)
+ {
+ //get the context from the mapping options set during a mapping operation
+ object umbCtx;
+ if (res.Options.Items.TryGetValue("UmbracoContext", out umbCtx))
+ {
+ var umbracoContext = umbCtx as UmbracoContext;
+ if (umbracoContext != null) return umbracoContext;
+ }
+
+ //return the singleton (this could be null)
+ return UmbracoContext.Current;
+ }
+ }
+}
diff --git a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs
index 2fa919716c..c54574a08a 100644
--- a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs
+++ b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs
@@ -35,19 +35,15 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(display => display.ContentTypeAlias, expression => expression.MapFrom(content => content.ContentType.Alias))
.ForMember(display => display.ContentTypeName, expression => expression.MapFrom(content => content.ContentType.Name))
.ForMember(display => display.IsContainer, expression => expression.MapFrom(content => content.ContentType.IsContainer))
- .ForMember(display => display.IsChildOfListView, expression => expression.Ignore())
+ .ForMember(display => display.IsChildOfListView, expression => expression.ResolveUsing(new ChildOfListViewResolver(applicationContext.Services.ContentService, applicationContext.Services.ContentTypeService)))
.ForMember(display => display.Trashed, expression => expression.MapFrom(content => content.Trashed))
.ForMember(display => display.PublishDate, expression => expression.MapFrom(content => GetPublishedDate(content)))
- .ForMember(display => display.TemplateAlias, expression => expression.MapFrom(content => content.Template.Alias))
+ .ForMember(display => display.TemplateAlias, expression => expression.ResolveUsing())
.ForMember(display => display.HasPublishedVersion, expression => expression.MapFrom(content => content.HasPublishedVersion))
- .ForMember(display => display.Urls,
- expression => expression.MapFrom(content =>
- UmbracoContext.Current == null
- ? new[] { "Cannot generate urls without a current Umbraco Context" }
- : content.GetContentUrls(UmbracoContext.Current)))
+ .ForMember(display => display.Urls, expression => expression.ResolveUsing())
.ForMember(display => display.Properties, expression => expression.Ignore())
.ForMember(display => display.AllowPreview, expression => expression.Ignore())
- .ForMember(display => display.TreeNodeUrl, expression => expression.Ignore())
+ .ForMember(display => display.TreeNodeUrl, opt => opt.ResolveUsing(new ContentTreeNodeUrlResolver()))
.ForMember(display => display.Notifications, expression => expression.Ignore())
.ForMember(display => display.Errors, expression => expression.Ignore())
.ForMember(display => display.Alias, expression => expression.Ignore())
@@ -56,11 +52,16 @@ namespace Umbraco.Web.Models.Mapping
expression.MapFrom(content => content.ContentType.AllowedTemplates
.Where(t => t.Alias.IsNullOrWhiteSpace() == false && t.Name.IsNullOrWhiteSpace() == false)
.ToDictionary(t => t.Alias, t => t.Name)))
- .ForMember(display => display.Tabs, expression => expression.ResolveUsing(new TabsAndPropertiesResolver(applicationContext.Services.TextService)))
+ .ForMember(display => display.Tabs, expression => expression.ResolveUsing(new TabsAndPropertiesResolver(applicationContext.Services.TextService)))
.ForMember(display => display.AllowedActions, expression => expression.ResolveUsing(
new ActionButtonsResolver(new Lazy(() => applicationContext.Services.UserService), new Lazy(() => applicationContext.Services.ContentService))))
- .AfterMap((content, display) => AfterMap(content, display, applicationContext.Services.DataTypeService, applicationContext.Services.TextService,
- applicationContext.Services.ContentTypeService));
+ .AfterMap((content, display) =>
+ {
+ if (content.ContentType.IsContainer)
+ {
+ TabsAndPropertiesResolver.AddListView(display, "content", applicationContext.Services.DataTypeService, applicationContext.Services.TextService);
+ }
+ });
//FROM IContent TO ContentItemBasic
config.CreateMap>()
@@ -88,42 +89,58 @@ namespace Umbraco.Web.Models.Mapping
var date = ((Content)content).PublishedDate;
return date == default(DateTime) ? (DateTime?)null : date;
}
-
- ///
- /// Maps the generic tab with custom properties for content
- ///
- ///
- ///
- ///
- ///
- ///
- private static void AfterMap(IContent content, ContentItemDisplay display, IDataTypeService dataTypeService,
- ILocalizedTextService localizedText, IContentTypeService contentTypeService)
+
+ internal class ContentUrlResolver : IValueResolver
{
- // map the IsChildOfListView (this is actually if it is a descendant of a list view!)
- var parent = content.Parent();
- display.IsChildOfListView = parent != null && (parent.ContentType.IsContainer || contentTypeService.HasContainerInPath(parent.Path));
-
- //map the tree node url
- if (HttpContext.Current != null)
+ public ResolutionResult Resolve(ResolutionResult source)
{
- var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
- var url = urlHelper.GetUmbracoApiService(controller => controller.GetTreeNode(display.Id.ToString(), null));
- display.TreeNodeUrl = url;
+ var content = (IContent)source.Value;
+
+ var umbCtx = source.Context.GetUmbracoContext();
+
+ var urls = umbCtx == null
+ ? new[] {"Cannot generate urls without a current Umbraco Context"}
+ : content.GetContentUrls(umbCtx);
+
+ return source.New(urls, typeof(string[]));
+ }
+ }
+
+ internal class DefaultTemplateResolver : ValueResolver
+ {
+ protected override string ResolveCore(IContent source)
+ {
+ if (source == null || source.Template == null) return null;
+
+ var alias = source.Template.Alias;
+
+ //set default template if template isn't set
+ if (string.IsNullOrEmpty(alias))
+ alias = source.ContentType.DefaultTemplate == null
+ ? string.Empty
+ : source.ContentType.DefaultTemplate.Alias;
+
+ return alias;
+ }
+ }
+
+ private class ChildOfListViewResolver : ValueResolver
+ {
+ private readonly IContentService _contentService;
+ private readonly IContentTypeService _contentTypeService;
+
+ public ChildOfListViewResolver(IContentService contentService, IContentTypeService contentTypeService)
+ {
+ _contentService = contentService;
+ _contentTypeService = contentTypeService;
}
- //set default template if template isn't set
- if (string.IsNullOrEmpty(display.TemplateAlias))
- display.TemplateAlias = content.ContentType.DefaultTemplate == null
- ? string.Empty
- : content.ContentType.DefaultTemplate.Alias;
-
- if (content.ContentType.IsContainer)
+ protected override bool ResolveCore(IContent source)
{
- TabsAndPropertiesResolver.AddListView(display, "content", dataTypeService, localizedText);
+ // map the IsChildOfListView (this is actually if it is a descendant of a list view!)
+ var parent = _contentService.GetParent(source);
+ return parent != null && (parent.ContentType.IsContainer || _contentTypeService.HasContainerInPath(parent.Path));
}
-
- TabsAndPropertiesResolver.MapGenericProperties(content, display, localizedText);
}
///
@@ -134,9 +151,7 @@ namespace Umbraco.Web.Models.Mapping
{
protected override ContentTypeBasic ResolveCore(IContent source)
{
- //TODO: This would be much nicer with the IUmbracoContextAccessor so we don't use singletons
- //If this is a web request and there's a user signed in and the
- // user has access to the settings section, we will
+ //TODO: We can resolve the UmbracoContext from the IValueResolver options!
if (HttpContext.Current != null && UmbracoContext.Current != null && UmbracoContext.Current.Security.CurrentUser != null
&& UmbracoContext.Current.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings)))
{
@@ -194,4 +209,4 @@ namespace Umbraco.Web.Models.Mapping
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Umbraco.Web/Models/Mapping/ContentPropertyBasicConverter.cs b/src/Umbraco.Web/Models/Mapping/ContentPropertyBasicConverter.cs
index f61d9adf77..e7104f2939 100644
--- a/src/Umbraco.Web/Models/Mapping/ContentPropertyBasicConverter.cs
+++ b/src/Umbraco.Web/Models/Mapping/ContentPropertyBasicConverter.cs
@@ -16,9 +16,9 @@ namespace Umbraco.Web.Models.Mapping
internal class ContentPropertyBasicConverter : TypeConverter
where T : ContentPropertyBasic, new()
{
- protected Lazy DataTypeService { get; private set; }
+ protected IDataTypeService DataTypeService { get; private set; }
- public ContentPropertyBasicConverter(Lazy dataTypeService)
+ public ContentPropertyBasicConverter(IDataTypeService dataTypeService)
{
DataTypeService = dataTypeService;
}
@@ -42,7 +42,7 @@ namespace Umbraco.Web.Models.Mapping
var result = new T
{
Id = property.Id,
- Value = editor.ValueEditor.ConvertDbToEditor(property, property.PropertyType, DataTypeService.Value),
+ Value = editor.ValueEditor.ConvertDbToEditor(property, property.PropertyType, DataTypeService),
Alias = property.Alias,
PropertyEditor = editor,
Editor = editor.Alias
@@ -51,4 +51,4 @@ namespace Umbraco.Web.Models.Mapping
return result;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayConverter.cs b/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayConverter.cs
index 20ff209371..8267e46e25 100644
--- a/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayConverter.cs
+++ b/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayConverter.cs
@@ -13,17 +13,19 @@ namespace Umbraco.Web.Models.Mapping
///
internal class ContentPropertyDisplayConverter : ContentPropertyBasicConverter
{
- public ContentPropertyDisplayConverter(Lazy dataTypeService)
+ private readonly ILocalizedTextService _textService;
+
+ public ContentPropertyDisplayConverter(IDataTypeService dataTypeService, ILocalizedTextService textService)
: base(dataTypeService)
{
-
+ _textService = textService;
}
protected override ContentPropertyDisplay ConvertCore(Property originalProp)
{
var display = base.ConvertCore(originalProp);
- var dataTypeService = DataTypeService.Value;
+ var dataTypeService = DataTypeService;
var preVals = dataTypeService.GetPreValuesCollectionByDataTypeId(originalProp.PropertyType.DataTypeDefinitionId);
//configure the editor for display with the pre-values
@@ -54,7 +56,11 @@ namespace Umbraco.Web.Models.Mapping
display.View = valEditor.View;
}
+ //Translate
+ display.Label = _textService.UmbracoDictionaryTranslate(display.Label);
+ display.Description = _textService.UmbracoDictionaryTranslate(display.Description);
+
return display;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoConverter.cs b/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoConverter.cs
index 3a6e199f96..f3f9fbe9d5 100644
--- a/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoConverter.cs
+++ b/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoConverter.cs
@@ -12,7 +12,7 @@ namespace Umbraco.Web.Models.Mapping
///
internal class ContentPropertyDtoConverter : ContentPropertyBasicConverter
{
- public ContentPropertyDtoConverter(Lazy dataTypeService)
+ public ContentPropertyDtoConverter(IDataTypeService dataTypeService)
: base(dataTypeService)
{
}
@@ -21,7 +21,7 @@ namespace Umbraco.Web.Models.Mapping
{
var propertyDto = base.ConvertCore(originalProperty);
- var dataTypeService = DataTypeService.Value;
+ var dataTypeService = DataTypeService;
propertyDto.IsRequired = originalProperty.PropertyType.Mandatory;
propertyDto.ValidationRegExp = originalProperty.PropertyType.ValidationRegExp;
@@ -35,4 +35,4 @@ namespace Umbraco.Web.Models.Mapping
return propertyDto;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Umbraco.Web/Models/Mapping/ContentPropertyModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentPropertyModelMapper.cs
index ba51eb1790..5e29bcf125 100644
--- a/src/Umbraco.Web/Models/Mapping/ContentPropertyModelMapper.cs
+++ b/src/Umbraco.Web/Models/Mapping/ContentPropertyModelMapper.cs
@@ -16,8 +16,6 @@ namespace Umbraco.Web.Models.Mapping
{
public override void ConfigureMappings(IConfiguration config, ApplicationContext applicationContext)
{
- var lazyDataTypeService = new Lazy(() => applicationContext.Services.DataTypeService);
-
//FROM Property TO ContentPropertyBasic
config.CreateMap>()
.ForMember(tab => tab.Label, expression => expression.MapFrom(@group => @group.Name))
@@ -27,15 +25,15 @@ namespace Umbraco.Web.Models.Mapping
//FROM Property TO ContentPropertyBasic
config.CreateMap()
- .ConvertUsing(new ContentPropertyBasicConverter(lazyDataTypeService));
+ .ConvertUsing(new ContentPropertyBasicConverter(applicationContext.Services.DataTypeService));
//FROM Property TO ContentPropertyDto
config.CreateMap()
- .ConvertUsing(new ContentPropertyDtoConverter(lazyDataTypeService));
+ .ConvertUsing(new ContentPropertyDtoConverter(applicationContext.Services.DataTypeService));
//FROM Property TO ContentPropertyDisplay
config.CreateMap()
- .ConvertUsing(new ContentPropertyDisplayConverter(lazyDataTypeService));
+ .ConvertUsing(new ContentPropertyDisplayConverter(applicationContext.Services.DataTypeService, applicationContext.Services.TextService));
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Umbraco.Web/Models/Mapping/ContentTreeNodeUrlResolver.cs b/src/Umbraco.Web/Models/Mapping/ContentTreeNodeUrlResolver.cs
new file mode 100644
index 0000000000..63d5b9b7e3
--- /dev/null
+++ b/src/Umbraco.Web/Models/Mapping/ContentTreeNodeUrlResolver.cs
@@ -0,0 +1,34 @@
+using System.Web.Mvc;
+using AutoMapper;
+using Umbraco.Core.Models;
+using Umbraco.Web.Trees;
+
+namespace Umbraco.Web.Models.Mapping
+{
+ ///
+ /// Gets the tree node url for the content or media
+ ///
+ internal class ContentTreeNodeUrlResolver : IValueResolver
+ where TSource : IContentBase
+ where TController : ContentTreeControllerBase
+ {
+
+ public ResolutionResult Resolve(ResolutionResult source)
+ {
+ return source.New(ResolveCore(source, (TSource)source.Value), typeof(string));
+ }
+
+ private string ResolveCore(ResolutionResult res, TSource source)
+ {
+ var umbCtx = res.Context.GetUmbracoContext();
+ //map the tree node url
+ if (umbCtx != null)
+ {
+ var urlHelper = new UrlHelper(umbCtx.HttpContext.Request.RequestContext);
+ var url = urlHelper.GetUmbracoApiService(controller => controller.GetTreeNode(source.Key.ToString("N"), null));
+ return url;
+ }
+ return null;
+ }
+ }
+}
diff --git a/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs
index 3daf22f172..7ab2e63dbc 100644
--- a/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs
+++ b/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs
@@ -88,7 +88,7 @@ namespace Umbraco.Web.Models.Mapping
{
ContentTypeModelMapperExtensions.AfterMapContentTypeSaveToEntity(source, dest, applicationContext);
- //map the MemberCanEditProperty,MemberCanViewProperty
+ //map the MemberCanEditProperty,MemberCanViewProperty,IsSensitiveData
foreach (var propertyType in source.Groups.SelectMany(x => x.Properties))
{
var localCopy = propertyType;
@@ -97,6 +97,7 @@ namespace Umbraco.Web.Models.Mapping
{
dest.SetMemberCanEditProperty(localCopy.Alias, localCopy.MemberCanEditProperty);
dest.SetMemberCanViewProperty(localCopy.Alias, localCopy.MemberCanViewProperty);
+ dest.SetIsSensitiveProperty(localCopy.Alias, localCopy.IsSensitiveData);
}
}
});
@@ -108,7 +109,7 @@ namespace Umbraco.Web.Models.Mapping
.MapBaseContentTypeEntityToDisplay(applicationContext, _propertyEditorResolver)
.AfterMap((memberType, display) =>
{
- //map the MemberCanEditProperty,MemberCanViewProperty
+ //map the MemberCanEditProperty,MemberCanViewProperty,IsSensitiveData
foreach (var propertyType in memberType.PropertyTypes)
{
var localCopy = propertyType;
@@ -117,6 +118,7 @@ namespace Umbraco.Web.Models.Mapping
{
displayProp.MemberCanEditProperty = memberType.MemberCanEditProperty(localCopy.Alias);
displayProp.MemberCanViewProperty = memberType.MemberCanViewProperty(localCopy.Alias);
+ displayProp.IsSensitiveData = memberType.IsSensitiveProperty(localCopy.Alias);
}
}
});
@@ -284,4 +286,4 @@ namespace Umbraco.Web.Models.Mapping
}
-}
\ No newline at end of file
+}
diff --git a/src/Umbraco.Web/Models/Mapping/DataTypeModelMapper.cs b/src/Umbraco.Web/Models/Mapping/DataTypeModelMapper.cs
index 32d25028e4..60d9eb7d3b 100644
--- a/src/Umbraco.Web/Models/Mapping/DataTypeModelMapper.cs
+++ b/src/Umbraco.Web/Models/Mapping/DataTypeModelMapper.cs
@@ -19,9 +19,7 @@ namespace Umbraco.Web.Models.Mapping
{
public override void ConfigureMappings(IConfiguration config, ApplicationContext applicationContext)
{
- var lazyDataTypeService = new Lazy(() => applicationContext.Services.DataTypeService);
-
- config.CreateMap();
+ config.CreateMap();
//just maps the standard properties, does not map the value!
config.CreateMap()
@@ -67,7 +65,7 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(x => x.Udi, expression => expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.DataType, content.Key)))
.ForMember(display => display.AvailableEditors, expression => expression.ResolveUsing(new AvailablePropertyEditorsResolver(UmbracoConfig.For.UmbracoSettings().Content)))
.ForMember(display => display.PreValues, expression => expression.ResolveUsing(
- new PreValueDisplayResolver(lazyDataTypeService)))
+ new PreValueDisplayResolver(applicationContext.Services.DataTypeService)))
.ForMember(display => display.SelectedEditor, expression => expression.MapFrom(
definition => definition.PropertyEditorAlias.IsNullOrWhiteSpace() ? null : definition.PropertyEditorAlias))
.ForMember(x => x.HasPrevalues, expression => expression.Ignore())
@@ -90,7 +88,7 @@ namespace Umbraco.Web.Models.Mapping
config.CreateMap>()
.ConvertUsing(definition =>
{
- var resolver = new PreValueDisplayResolver(lazyDataTypeService);
+ var resolver = new PreValueDisplayResolver(applicationContext.Services.DataTypeService);
return resolver.Convert(definition);
});
@@ -124,4 +122,4 @@ namespace Umbraco.Web.Models.Mapping
});
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs b/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs
index 157205eb51..5c10692c4b 100644
--- a/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs
+++ b/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs
@@ -29,11 +29,11 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(display => display.Owner, expression => expression.ResolveUsing(new OwnerResolver()))
.ForMember(display => display.Icon, expression => expression.MapFrom(content => content.ContentType.Icon))
.ForMember(display => display.ContentTypeAlias, expression => expression.MapFrom(content => content.ContentType.Alias))
- .ForMember(display => display.IsChildOfListView, expression => expression.Ignore())
+ .ForMember(display => display.IsChildOfListView, expression => expression.ResolveUsing(new ChildOfListViewResolver(applicationContext.Services.MediaService, applicationContext.Services.ContentTypeService)))
.ForMember(display => display.Trashed, expression => expression.MapFrom(content => content.Trashed))
.ForMember(display => display.ContentTypeName, expression => expression.MapFrom(content => content.ContentType.Name))
.ForMember(display => display.Properties, expression => expression.Ignore())
- .ForMember(display => display.TreeNodeUrl, expression => expression.Ignore())
+ .ForMember(display => display.TreeNodeUrl, opt => opt.ResolveUsing(new ContentTreeNodeUrlResolver()))
.ForMember(display => display.Notifications, expression => expression.Ignore())
.ForMember(display => display.Errors, expression => expression.Ignore())
.ForMember(display => display.Published, expression => expression.Ignore())
@@ -41,11 +41,17 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(display => display.Alias, expression => expression.Ignore())
.ForMember(display => display.IsContainer, expression => expression.Ignore())
.ForMember(display => display.HasPublishedVersion, expression => expression.Ignore())
- .ForMember(display => display.Tabs, expression => expression.ResolveUsing(new TabsAndPropertiesResolver(applicationContext.Services.TextService)))
- .ForMember(display => display.ContentType, expression => expression.ResolveUsing())
- .ForMember(display => display.MediaLink, expression => expression.ResolveUsing(
+ .ForMember(display => display.Tabs, expression => expression.ResolveUsing(new TabsAndPropertiesResolver(applicationContext.Services.TextService)))
+ .ForMember(display => display.ContentType, expression => expression.ResolveUsing())
+ .ForMember(display => display.MediaLink, expression => expression.ResolveUsing(
content => string.Join(",", content.GetUrls(UmbracoConfig.For.UmbracoSettings().Content, applicationContext.ProfilingLogger.Logger))))
- .AfterMap((media, display) => AfterMap(media, display, applicationContext.Services.DataTypeService, applicationContext.Services.TextService, applicationContext.Services.ContentTypeService, applicationContext.ProfilingLogger.Logger));
+ .AfterMap((media, display) =>
+ {
+ if (media.ContentType.IsContainer)
+ {
+ TabsAndPropertiesResolver.AddListView(display, "media", applicationContext.Services.DataTypeService, applicationContext.Services.TextService);
+ }
+ });
//FROM IMedia TO ContentItemBasic
config.CreateMap>()
@@ -68,31 +74,28 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(dto => dto.Icon, expression => expression.Ignore())
.ForMember(dto => dto.Alias, expression => expression.Ignore())
.ForMember(dto => dto.HasPublishedVersion, expression => expression.Ignore());
- }
+ }
- private static void AfterMap(IMedia media, MediaItemDisplay display, IDataTypeService dataTypeService, ILocalizedTextService localizedText, IContentTypeService contentTypeService, ILogger logger)
+ private class ChildOfListViewResolver : ValueResolver
{
- // Adapted from ContentModelMapper
- //map the IsChildOfListView (this is actually if it is a descendant of a list view!)
- var parent = media.Parent();
- display.IsChildOfListView = parent != null && (parent.ContentType.IsContainer || contentTypeService.HasContainerInPath(parent.Path));
+ private readonly IMediaService _mediaService;
+ private readonly IContentTypeService _contentTypeService;
- //map the tree node url
- if (HttpContext.Current != null)
+ public ChildOfListViewResolver(IMediaService mediaService, IContentTypeService contentTypeService)
{
- var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
- var url = urlHelper.GetUmbracoApiService(controller => controller.GetTreeNode(display.Id.ToString(), null));
- display.TreeNodeUrl = url;
+ _mediaService = mediaService;
+ _contentTypeService = contentTypeService;
}
- if (media.ContentType.IsContainer)
+ protected override bool ResolveCore(IMedia source)
{
- TabsAndPropertiesResolver.AddListView(display, "media", dataTypeService, localizedText);
+ // map the IsChildOfListView (this is actually if it is a descendant of a list view!)
+ var parent = _mediaService.GetParent(source);
+ return parent != null && (parent.ContentType.IsContainer || _contentTypeService.HasContainerInPath(parent.Path));
}
-
- TabsAndPropertiesResolver.MapGenericProperties(media, display, localizedText);
}
+
///
/// Resolves a from the item and checks if the current user
/// has access to see this data
@@ -101,9 +104,7 @@ namespace Umbraco.Web.Models.Mapping
{
protected override ContentTypeBasic ResolveCore(IMedia source)
{
- //TODO: This would be much nicer with the IUmbracoContextAccessor so we don't use singletons
- //If this is a web request and there's a user signed in and the
- // user has access to the settings section, we will
+ //TODO: We can resolve the UmbracoContext from the IValueResolver options!
if (HttpContext.Current != null && UmbracoContext.Current != null &&
UmbracoContext.Current.Security.CurrentUser != null
&& UmbracoContext.Current.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants
diff --git a/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs b/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs
index e3c82cf782..21cf4d1ec1 100644
--- a/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs
+++ b/src/Umbraco.Web/Models/Mapping/MemberModelMapper.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Web;
-using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using AutoMapper;
@@ -14,7 +13,6 @@ using Umbraco.Web.Models.ContentEditing;
using System.Linq;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Security;
-using Umbraco.Web.Trees;
using UserProfile = Umbraco.Web.Models.ContentEditing.UserProfile;
namespace Umbraco.Web.Models.Mapping
@@ -27,12 +25,7 @@ namespace Umbraco.Web.Models.Mapping
public override void ConfigureMappings(IConfiguration config, ApplicationContext applicationContext)
{
//FROM MembershipUser TO MediaItemDisplay - used when using a non-umbraco membership provider
- config.CreateMap()
- .ConvertUsing(user =>
- {
- var member = Mapper.Map(user);
- return Mapper.Map(member);
- });
+ config.CreateMap().ConvertUsing();
//FROM MembershipUser TO IMember - used when using a non-umbraco membership provider
config.CreateMap()
@@ -56,9 +49,9 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(member => member.SortOrder, expression => expression.Ignore())
.ForMember(member => member.AdditionalData, expression => expression.Ignore())
.ForMember(member => member.FailedPasswordAttempts, expression => expression.Ignore())
- .ForMember(member => member.DeletedDate, expression => expression.Ignore())
- //TODO: Support these eventually
- .ForMember(member => member.PasswordQuestion, expression => expression.Ignore())
+ .ForMember(member => member.DeletedDate, expression => expression.Ignore())
+ //TODO: Support these eventually
+ .ForMember(member => member.PasswordQuestion, expression => expression.Ignore())
.ForMember(member => member.RawPasswordAnswerValue, expression => expression.Ignore());
//FROM IMember TO MediaItemDisplay
@@ -69,10 +62,10 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(display => display.ContentTypeAlias, expression => expression.MapFrom(content => content.ContentType.Alias))
.ForMember(display => display.ContentTypeName, expression => expression.MapFrom(content => content.ContentType.Name))
.ForMember(display => display.Properties, expression => expression.Ignore())
- .ForMember(display => display.Tabs, expression => expression.ResolveUsing(new MemberTabsAndPropertiesResolver(applicationContext.Services.TextService)))
+ .ForMember(display => display.Tabs, expression => expression.ResolveUsing(new MemberTabsAndPropertiesResolver(applicationContext.Services.TextService, applicationContext.Services.MemberService, applicationContext.Services.UserService)))
.ForMember(display => display.MemberProviderFieldMapping, expression => expression.ResolveUsing(new MemberProviderFieldMappingResolver()))
.ForMember(display => display.MembershipScenario,
- expression => expression.ResolveUsing(new MembershipScenarioMappingResolver(new Lazy(() => applicationContext.Services.MemberTypeService))))
+ expression => expression.ResolveUsing(new MembershipScenarioMappingResolver(applicationContext.Services.MemberTypeService)))
.ForMember(display => display.Notifications, expression => expression.Ignore())
.ForMember(display => display.Errors, expression => expression.Ignore())
.ForMember(display => display.Published, expression => expression.Ignore())
@@ -81,9 +74,9 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(display => display.IsChildOfListView, expression => expression.Ignore())
.ForMember(display => display.Trashed, expression => expression.Ignore())
.ForMember(display => display.IsContainer, expression => expression.Ignore())
- .ForMember(display => display.TreeNodeUrl, expression => expression.Ignore())
- .ForMember(display => display.HasPublishedVersion, expression => expression.Ignore())
- .AfterMap((member, display) => MapGenericCustomProperties(applicationContext.Services.MemberService, applicationContext.Services.UserService, member, display, applicationContext.Services.TextService));
+ .ForMember(display => display.TreeNodeUrl, opt => opt.ResolveUsing(new MemberTreeNodeUrlResolver()))
+ .ForMember(display => display.HasPublishedVersion, expression => expression.Ignore());
+ //.AfterMap((member, display) => MapGenericCustomProperties(applicationContext.Services.MemberService, applicationContext.Services.UserService, member, display, applicationContext.Services.TextService));
//FROM IMember TO MemberBasic
config.CreateMap()
@@ -100,14 +93,14 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(dto => dto.HasPublishedVersion, expression => expression.Ignore());
//FROM MembershipUser TO MemberBasic
- config.CreateMap()
+ config.CreateMap()
//we're giving this entity an ID of 0 - we cannot really map it but it needs an id so the system knows it's not a new entity
.ForMember(member => member.Id, expression => expression.MapFrom(user => int.MaxValue))
.ForMember(display => display.Udi, expression => expression.Ignore())
.ForMember(member => member.CreateDate, expression => expression.MapFrom(user => user.CreationDate))
.ForMember(member => member.UpdateDate, expression => expression.MapFrom(user => user.LastActivityDate))
.ForMember(member => member.Key, expression => expression.MapFrom(user => user.ProviderUserKey.TryConvertTo().Result.ToString("N")))
- .ForMember(member => member.Owner, expression => expression.UseValue(new UserProfile {Name = "Admin", UserId = 0}))
+ .ForMember(member => member.Owner, expression => expression.UseValue(new UserProfile { Name = "Admin", UserId = 0 }))
.ForMember(member => member.Icon, expression => expression.UseValue("icon-user"))
.ForMember(member => member.Name, expression => expression.MapFrom(user => user.UserName))
.ForMember(member => member.Email, expression => expression.MapFrom(content => content.Email))
@@ -137,119 +130,11 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(dto => dto.Properties, expression => expression.ResolveUsing(new MemberDtoPropertiesValueResolver()));
}
- ///
- /// Maps the generic tab with custom properties for content
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- /// If this is a new entity and there is an approved field then we'll set it to true by default.
- ///
- private static void MapGenericCustomProperties(IMemberService memberService, IUserService userService, IMember member, MemberDisplay display, ILocalizedTextService localizedText)
- {
- var membersProvider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
-
- //map the tree node url
- if (HttpContext.Current != null)
- {
- var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
- var url = urlHelper.GetUmbracoApiService(controller => controller.GetTreeNode(display.Key.ToString("N"), null));
- display.TreeNodeUrl = url;
- }
-
- var genericProperties = new List
- {
- new ContentPropertyDisplay
- {
- Alias = string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
- Label = localizedText.Localize("content/membertype"),
- Value = localizedText.UmbracoDictionaryTranslate(display.ContentTypeName),
- View = PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View
- },
- GetLoginProperty(memberService, member, display, localizedText),
- new ContentPropertyDisplay
- {
- Alias = string.Format("{0}email", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
- Label = localizedText.Localize("general/email"),
- Value = display.Email,
- View = "email",
- Validation = {Mandatory = true}
- },
- new ContentPropertyDisplay
- {
- Alias = string.Format("{0}password", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
- Label = localizedText.Localize("password"),
- //NOTE: The value here is a json value - but the only property we care about is the generatedPassword one if it exists, the newPassword exists
- // only when creating a new member and we want to have a generated password pre-filled.
- Value = new Dictionary
- {
- {"generatedPassword", member.GetAdditionalDataValueIgnoreCase("GeneratedPassword", null)},
- {"newPassword", member.GetAdditionalDataValueIgnoreCase("NewPassword", null)},
- },
- //TODO: Hard coding this because the changepassword doesn't necessarily need to be a resolvable (real) property editor
- View = "changepassword",
- //initialize the dictionary with the configuration from the default membership provider
- Config = new Dictionary(membersProvider.GetConfiguration(userService))
- {
- //the password change toggle will only be displayed if there is already a password assigned.
- {"hasPassword", member.RawPasswordValue.IsNullOrWhiteSpace() == false}
- }
- },
- new ContentPropertyDisplay
- {
- Alias = string.Format("{0}membergroup", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
- Label = localizedText.Localize("content/membergroup"),
- Value = GetMemberGroupValue(display.Username),
- View = "membergroups",
- Config = new Dictionary {{"IsRequired", true}}
- }
- };
-
- TabsAndPropertiesResolver.MapGenericProperties(member, display, localizedText, genericProperties, properties =>
- {
- if (HttpContext.Current != null && UmbracoContext.Current != null && UmbracoContext.Current.Security.CurrentUser != null
- && UmbracoContext.Current.Security.CurrentUser.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings)))
- {
- var memberTypeLink = string.Format("#/member/memberTypes/edit/{0}", member.ContentTypeId);
-
- //Replace the doctype property
- var docTypeProperty = properties.First(x => x.Alias == string.Format("{0}doctype", Constants.PropertyEditors.InternalGenericPropertiesPrefix));
- docTypeProperty.Value = new List