merged
This commit is contained in:
@@ -3,9 +3,11 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -34,8 +36,15 @@ namespace Umbraco.Core.Models
|
||||
public DataTypeDefinition(int parentId, Guid controlId)
|
||||
{
|
||||
_parentId = parentId;
|
||||
_propertyEditorAlias = LegacyPropertyEditorIdToAliasConverter.GetAliasFromLegacyId(controlId, true);
|
||||
|
||||
|
||||
_propertyEditorAlias = LegacyPropertyEditorIdToAliasConverter.GetAliasFromLegacyId(controlId, false);
|
||||
if (_propertyEditorAlias == null)
|
||||
{
|
||||
//convert to Label!
|
||||
LogHelper.Warn<DataTypeDefinition>("Could not find a GUID -> Alias mapping for the legacy property editor with id " + controlId + ". The DataType has been converted to a Label.");
|
||||
_propertyEditorAlias = Constants.PropertyEditors.NoEditAlias;
|
||||
}
|
||||
|
||||
_additionalData = new Dictionary<string, object>();
|
||||
}
|
||||
public DataTypeDefinition(int parentId, string propertyEditorAlias)
|
||||
|
||||
@@ -9,7 +9,11 @@
|
||||
{
|
||||
Value = value;
|
||||
Id = id;
|
||||
}
|
||||
|
||||
public PreValue(string value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
178
src/Umbraco.Core/Packaging/PackageBinaryInspector.cs
Normal file
178
src/Umbraco.Core/Packaging/PackageBinaryInspector.cs
Normal file
@@ -0,0 +1,178 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace Umbraco.Core.Packaging
|
||||
{
|
||||
internal class PackageBinaryInspector : MarshalByRefObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Entry point to call from your code
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="dllPath"></param>
|
||||
/// <param name="errorReport"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// Will perform the assembly scan in a separate app domain
|
||||
/// </remarks>
|
||||
public static IEnumerable<string> ScanAssembliesForTypeReference<T>(string dllPath, out string[] errorReport)
|
||||
{
|
||||
var appDomain = GetTempAppDomain();
|
||||
var type = typeof(PackageBinaryInspector);
|
||||
try
|
||||
{
|
||||
var value = (PackageBinaryInspector)appDomain.CreateInstanceAndUnwrap(
|
||||
type.Assembly.FullName,
|
||||
type.FullName);
|
||||
var result = value.PerformScan<T>(dllPath, out errorReport);
|
||||
return result;
|
||||
}
|
||||
finally
|
||||
{
|
||||
AppDomain.Unload(appDomain);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the assembly scanning
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="dllPath"></param>
|
||||
/// <param name="errorReport"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This method is executed in a separate app domain
|
||||
/// </remarks>
|
||||
internal IEnumerable<string> PerformScan<T>(string dllPath, out string[] errorReport)
|
||||
{
|
||||
if (Directory.Exists(dllPath) == false)
|
||||
{
|
||||
throw new DirectoryNotFoundException("Could not find directory " + dllPath);
|
||||
}
|
||||
|
||||
var files = Directory.GetFiles(dllPath, "*.dll");
|
||||
var dllsWithReference = new List<string>();
|
||||
var errors = new List<string>();
|
||||
var assembliesWithErrors = new List<string>();
|
||||
|
||||
//we need this handler to resolve assembly dependencies below
|
||||
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += (s, e) =>
|
||||
{
|
||||
var a = Assembly.ReflectionOnlyLoadFrom(GetAssemblyPath(Assembly.ReflectionOnlyLoad(e.Name)));
|
||||
if (a == null) throw new TypeLoadException("Could not load assembly " + e.Name);
|
||||
return a;
|
||||
};
|
||||
|
||||
//First load each dll file into the context
|
||||
foreach (var f in files) Assembly.ReflectionOnlyLoadFrom(f);
|
||||
|
||||
//Then load each referenced assembly into the context
|
||||
foreach (var f in files)
|
||||
{
|
||||
var reflectedAssembly = Assembly.ReflectionOnlyLoadFrom(f);
|
||||
foreach (var assemblyName in reflectedAssembly.GetReferencedAssemblies())
|
||||
{
|
||||
try
|
||||
{
|
||||
Assembly.ReflectionOnlyLoadFrom(GetAssemblyPath(Assembly.ReflectionOnlyLoad(assemblyName.FullName)));
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
//if an exception occurs it means that a referenced assembly could not be found
|
||||
errors.Add(
|
||||
string.Concat("This package references the assembly '",
|
||||
assemblyName.Name,
|
||||
"' which was not found, this package may have problems running"));
|
||||
assembliesWithErrors.Add(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var contractType = GetLoadFromContractType<T>();
|
||||
|
||||
//now that we have all referenced types into the context we can look up stuff
|
||||
foreach (var f in files.Except(assembliesWithErrors))
|
||||
{
|
||||
//now we need to see if they contain any type 'T'
|
||||
var reflectedAssembly = Assembly.ReflectionOnlyLoadFrom(f);
|
||||
|
||||
var found = reflectedAssembly.GetExportedTypes()
|
||||
.Where(contractType.IsAssignableFrom);
|
||||
|
||||
if (found.Any())
|
||||
{
|
||||
dllsWithReference.Add(reflectedAssembly.FullName);
|
||||
}
|
||||
}
|
||||
|
||||
errorReport = errors.ToArray();
|
||||
return dllsWithReference;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// In order to compare types, the types must be in the same context, this method will return the type that
|
||||
/// we are checking against but from the LoadFrom context.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
private static Type GetLoadFromContractType<T>()
|
||||
{
|
||||
var contractAssemblyLoadFrom = Assembly.ReflectionOnlyLoadFrom(
|
||||
GetAssemblyPath(Assembly.ReflectionOnlyLoad(typeof (T).Assembly.FullName)));
|
||||
|
||||
var contractType = contractAssemblyLoadFrom.GetExportedTypes()
|
||||
.FirstOrDefault(x => x.FullName == typeof(T).FullName && x.Assembly.FullName == typeof(T).Assembly.FullName);
|
||||
|
||||
if (contractType == null)
|
||||
{
|
||||
throw new InvalidOperationException("Could not find type " + typeof(T) + " in the LoadFrom assemblies");
|
||||
}
|
||||
return contractType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an app domain
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static AppDomain GetTempAppDomain()
|
||||
{
|
||||
//copy the current app domain setup but don't shadow copy files
|
||||
var appName = "TempDomain" + Guid.NewGuid();
|
||||
var domainSetup = new AppDomainSetup
|
||||
{
|
||||
ApplicationName = appName,
|
||||
ShadowCopyFiles = "false",
|
||||
ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
|
||||
ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,
|
||||
DynamicBase = AppDomain.CurrentDomain.SetupInformation.DynamicBase,
|
||||
LicenseFile = AppDomain.CurrentDomain.SetupInformation.LicenseFile,
|
||||
LoaderOptimization = AppDomain.CurrentDomain.SetupInformation.LoaderOptimization,
|
||||
PrivateBinPath = AppDomain.CurrentDomain.SetupInformation.PrivateBinPath,
|
||||
PrivateBinPathProbe = AppDomain.CurrentDomain.SetupInformation.PrivateBinPathProbe
|
||||
};
|
||||
|
||||
//create new domain with full trust
|
||||
return AppDomain.CreateDomain(
|
||||
appName,
|
||||
AppDomain.CurrentDomain.Evidence,
|
||||
domainSetup,
|
||||
new PermissionSet(PermissionState.Unrestricted));
|
||||
}
|
||||
|
||||
private static string GetAssemblyPath(Assembly a)
|
||||
{
|
||||
var codeBase = a.CodeBase;
|
||||
var uri = new Uri(codeBase);
|
||||
return uri.LocalPath;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,203 +1,203 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a pre-value editor
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A pre-value editor is made up of multiple pre-value fields, each field defines a key that the value is stored against.
|
||||
/// Each field can have any editor and the value from each field can store any data such as a simple string or a json structure.
|
||||
///
|
||||
/// The Json serialization attributes are required for manifest property editors to work.
|
||||
/// </remarks>
|
||||
public class PreValueEditor
|
||||
{
|
||||
public PreValueEditor()
|
||||
{
|
||||
var fields = new List<PreValueField>();
|
||||
|
||||
//the ctor checks if we have PreValueFieldAttributes applied and if so we construct our fields from them
|
||||
var props = TypeHelper.CachedDiscoverableProperties(GetType())
|
||||
.Where(x => x.Name != "Fields");
|
||||
foreach (var p in props)
|
||||
{
|
||||
var att = p.GetCustomAttributes(typeof (PreValueFieldAttribute), false).OfType<PreValueFieldAttribute>().SingleOrDefault();
|
||||
if (att != null)
|
||||
{
|
||||
if (att.PreValueFieldType != null)
|
||||
{
|
||||
//try to create it
|
||||
try
|
||||
{
|
||||
var instance = (PreValueField) Activator.CreateInstance(att.PreValueFieldType);
|
||||
//overwrite values if they are assigned
|
||||
if (!att.Key.IsNullOrWhiteSpace())
|
||||
{
|
||||
instance.Key = att.Key;
|
||||
}
|
||||
//if the key is still empty then assign it to be the property name
|
||||
if (instance.Key.IsNullOrWhiteSpace())
|
||||
{
|
||||
instance.Key = p.Name;
|
||||
}
|
||||
|
||||
if (!att.Name.IsNullOrWhiteSpace())
|
||||
instance.Name = att.Name;
|
||||
if (!att.View.IsNullOrWhiteSpace())
|
||||
instance.View = att.View;
|
||||
if (!att.Description.IsNullOrWhiteSpace())
|
||||
instance.Description = att.Description;
|
||||
if (att.HideLabel)
|
||||
instance.HideLabel = att.HideLabel;
|
||||
|
||||
//add the custom field
|
||||
fields.Add(instance);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WarnWithException<PreValueEditor>("Could not create an instance of " + att.PreValueFieldType, ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fields.Add(MapAttributeToField(att, p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Fields = fields;
|
||||
}
|
||||
|
||||
private static PreValueField MapAttributeToField(PreValueFieldAttribute att, PropertyInfo prop)
|
||||
{
|
||||
return new PreValueField
|
||||
{
|
||||
//set the key to the property name if it is empty
|
||||
Key = att.Key.IsNullOrWhiteSpace() ? prop.Name : att.Key,
|
||||
Name = att.Name,
|
||||
Description = att.Description,
|
||||
HideLabel = att.HideLabel,
|
||||
View = att.View
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A collection of pre-value fields to be edited
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If fields are specified then the master View and Validators will be ignored
|
||||
/// </remarks>
|
||||
[JsonProperty("fields")]
|
||||
public List<PreValueField> Fields { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// A method to format the posted values from the editor to the values to be persisted
|
||||
/// </summary>
|
||||
/// <param name="editorValue"></param>
|
||||
/// <param name="currentValue">
|
||||
/// The current value that has been persisted to the database for this pre-value editor. This value may be usesful for
|
||||
/// how the value then get's deserialized again to be re-persisted. In most cases it will probably not be used.
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// By default this will just return the Posted editorValue.
|
||||
///
|
||||
/// This can be overridden if perhaps you have a comma delimited string posted value but want to convert those to individual rows, or to convert
|
||||
/// a json structure to multiple rows.
|
||||
/// </remarks>
|
||||
public virtual IDictionary<string, string> ConvertEditorToDb(IDictionary<string, object> editorValue, PreValueCollection currentValue)
|
||||
{
|
||||
//convert to a string based value to be saved in the db
|
||||
return editorValue.ToDictionary(x => x.Key, x => x.Value == null ? null : x.Value.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This can be used to re-format the currently saved pre-values that will be passed to the editor,
|
||||
/// by default this returns the merged default and persisted pre-values.
|
||||
/// </summary>
|
||||
/// <param name="defaultPreVals">
|
||||
/// The default/static pre-vals for the property editor
|
||||
/// </param>
|
||||
/// <param name="persistedPreVals">
|
||||
/// The persisted pre-vals for the property editor
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This is generally not going to be used by anything unless a property editor wants to change the merging
|
||||
/// functionality or needs to convert some legacy persisted data, or convert the string values to strongly typed values in json (i.e. booleans)
|
||||
/// </remarks>
|
||||
public virtual IDictionary<string, object> ConvertDbToEditor(IDictionary<string, object> defaultPreVals, PreValueCollection persistedPreVals)
|
||||
{
|
||||
if (defaultPreVals == null)
|
||||
{
|
||||
defaultPreVals = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
if (persistedPreVals.IsDictionaryBased)
|
||||
{
|
||||
//we just need to merge the dictionaries now, the persisted will replace default.
|
||||
foreach (var item in persistedPreVals.PreValuesAsDictionary)
|
||||
{
|
||||
//The persisted dictionary contains values of type PreValue which contain the ID and the Value, we don't care
|
||||
// about the Id, just the value so ignore the id.
|
||||
defaultPreVals[item.Key] = item.Value.Value;
|
||||
}
|
||||
//now we're going to try to see if any of the values are JSON, if they are we'll convert them to real JSON objects
|
||||
// so they can be consumed as real json in angular!
|
||||
ConvertItemsToJsonIfDetected(defaultPreVals);
|
||||
|
||||
return defaultPreVals;
|
||||
}
|
||||
|
||||
//it's an array so need to format it
|
||||
var result = new Dictionary<string, object>();
|
||||
var asArray = persistedPreVals.PreValuesAsArray.ToArray();
|
||||
for (var i = 0; i < asArray.Length; i++)
|
||||
{
|
||||
//each item is of type PreValue but we don't want the ID, just the value so ignore the ID
|
||||
result.Add(i.ToInvariantString(), asArray[i].Value);
|
||||
}
|
||||
|
||||
//now we're going to try to see if any of the values are JSON, if they are we'll convert them to real JSON objects
|
||||
// so they can be consumed as real json in angular!
|
||||
ConvertItemsToJsonIfDetected(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void ConvertItemsToJsonIfDetected(IDictionary<string, object> result)
|
||||
{
|
||||
//now we're going to try to see if any of the values are JSON, if they are we'll convert them to real JSON objects
|
||||
// so they can be consumed as real json in angular!
|
||||
|
||||
var keys = result.Keys.ToArray();
|
||||
for (var i = 0; i < keys.Length; i++)
|
||||
{
|
||||
if (result[keys[i]] is string)
|
||||
{
|
||||
var asString = result[keys[i]].ToString();
|
||||
if (asString.DetectIsJson())
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = JsonConvert.DeserializeObject(asString);
|
||||
result[keys[i]] = json;
|
||||
}
|
||||
catch
|
||||
{
|
||||
//swallow this exception, we thought it was json but it really isn't so continue returning a string
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a pre-value editor
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A pre-value editor is made up of multiple pre-value fields, each field defines a key that the value is stored against.
|
||||
/// Each field can have any editor and the value from each field can store any data such as a simple string or a json structure.
|
||||
///
|
||||
/// The Json serialization attributes are required for manifest property editors to work.
|
||||
/// </remarks>
|
||||
public class PreValueEditor
|
||||
{
|
||||
public PreValueEditor()
|
||||
{
|
||||
var fields = new List<PreValueField>();
|
||||
|
||||
//the ctor checks if we have PreValueFieldAttributes applied and if so we construct our fields from them
|
||||
var props = TypeHelper.CachedDiscoverableProperties(GetType())
|
||||
.Where(x => x.Name != "Fields");
|
||||
foreach (var p in props)
|
||||
{
|
||||
var att = p.GetCustomAttributes(typeof (PreValueFieldAttribute), false).OfType<PreValueFieldAttribute>().SingleOrDefault();
|
||||
if (att != null)
|
||||
{
|
||||
if (att.PreValueFieldType != null)
|
||||
{
|
||||
//try to create it
|
||||
try
|
||||
{
|
||||
var instance = (PreValueField) Activator.CreateInstance(att.PreValueFieldType);
|
||||
//overwrite values if they are assigned
|
||||
if (!att.Key.IsNullOrWhiteSpace())
|
||||
{
|
||||
instance.Key = att.Key;
|
||||
}
|
||||
//if the key is still empty then assign it to be the property name
|
||||
if (instance.Key.IsNullOrWhiteSpace())
|
||||
{
|
||||
instance.Key = p.Name;
|
||||
}
|
||||
|
||||
if (!att.Name.IsNullOrWhiteSpace())
|
||||
instance.Name = att.Name;
|
||||
if (!att.View.IsNullOrWhiteSpace())
|
||||
instance.View = att.View;
|
||||
if (!att.Description.IsNullOrWhiteSpace())
|
||||
instance.Description = att.Description;
|
||||
if (att.HideLabel)
|
||||
instance.HideLabel = att.HideLabel;
|
||||
|
||||
//add the custom field
|
||||
fields.Add(instance);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WarnWithException<PreValueEditor>("Could not create an instance of " + att.PreValueFieldType, ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fields.Add(MapAttributeToField(att, p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Fields = fields;
|
||||
}
|
||||
|
||||
private static PreValueField MapAttributeToField(PreValueFieldAttribute att, PropertyInfo prop)
|
||||
{
|
||||
return new PreValueField
|
||||
{
|
||||
//set the key to the property name if it is empty
|
||||
Key = att.Key.IsNullOrWhiteSpace() ? prop.Name : att.Key,
|
||||
Name = att.Name,
|
||||
Description = att.Description,
|
||||
HideLabel = att.HideLabel,
|
||||
View = att.View
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A collection of pre-value fields to be edited
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If fields are specified then the master View and Validators will be ignored
|
||||
/// </remarks>
|
||||
[JsonProperty("fields")]
|
||||
public List<PreValueField> Fields { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// A method to format the posted values from the editor to the values to be persisted
|
||||
/// </summary>
|
||||
/// <param name="editorValue"></param>
|
||||
/// <param name="currentValue">
|
||||
/// The current value that has been persisted to the database for this pre-value editor. This value may be usesful for
|
||||
/// how the value then get's deserialized again to be re-persisted. In most cases it will probably not be used.
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// By default this will just return the Posted editorValue.
|
||||
///
|
||||
/// This can be overridden if perhaps you have a comma delimited string posted value but want to convert those to individual rows, or to convert
|
||||
/// a json structure to multiple rows.
|
||||
/// </remarks>
|
||||
public virtual IDictionary<string, PreValue> ConvertEditorToDb(IDictionary<string, object> editorValue, PreValueCollection currentValue)
|
||||
{
|
||||
//convert to a string based value to be saved in the db
|
||||
return editorValue.ToDictionary(x => x.Key, x => new PreValue(x.Value == null ? null : x.Value.ToString()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This can be used to re-format the currently saved pre-values that will be passed to the editor,
|
||||
/// by default this returns the merged default and persisted pre-values.
|
||||
/// </summary>
|
||||
/// <param name="defaultPreVals">
|
||||
/// The default/static pre-vals for the property editor
|
||||
/// </param>
|
||||
/// <param name="persistedPreVals">
|
||||
/// The persisted pre-vals for the property editor
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This is generally not going to be used by anything unless a property editor wants to change the merging
|
||||
/// functionality or needs to convert some legacy persisted data, or convert the string values to strongly typed values in json (i.e. booleans)
|
||||
/// </remarks>
|
||||
public virtual IDictionary<string, object> ConvertDbToEditor(IDictionary<string, object> defaultPreVals, PreValueCollection persistedPreVals)
|
||||
{
|
||||
if (defaultPreVals == null)
|
||||
{
|
||||
defaultPreVals = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
if (persistedPreVals.IsDictionaryBased)
|
||||
{
|
||||
//we just need to merge the dictionaries now, the persisted will replace default.
|
||||
foreach (var item in persistedPreVals.PreValuesAsDictionary)
|
||||
{
|
||||
//The persisted dictionary contains values of type PreValue which contain the ID and the Value, we don't care
|
||||
// about the Id, just the value so ignore the id.
|
||||
defaultPreVals[item.Key] = item.Value.Value;
|
||||
}
|
||||
//now we're going to try to see if any of the values are JSON, if they are we'll convert them to real JSON objects
|
||||
// so they can be consumed as real json in angular!
|
||||
ConvertItemsToJsonIfDetected(defaultPreVals);
|
||||
|
||||
return defaultPreVals;
|
||||
}
|
||||
|
||||
//it's an array so need to format it
|
||||
var result = new Dictionary<string, object>();
|
||||
var asArray = persistedPreVals.PreValuesAsArray.ToArray();
|
||||
for (var i = 0; i < asArray.Length; i++)
|
||||
{
|
||||
//each item is of type PreValue but we don't want the ID, just the value so ignore the ID
|
||||
result.Add(i.ToInvariantString(), asArray[i].Value);
|
||||
}
|
||||
|
||||
//now we're going to try to see if any of the values are JSON, if they are we'll convert them to real JSON objects
|
||||
// so they can be consumed as real json in angular!
|
||||
ConvertItemsToJsonIfDetected(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void ConvertItemsToJsonIfDetected(IDictionary<string, object> result)
|
||||
{
|
||||
//now we're going to try to see if any of the values are JSON, if they are we'll convert them to real JSON objects
|
||||
// so they can be consumed as real json in angular!
|
||||
|
||||
var keys = result.Keys.ToArray();
|
||||
for (var i = 0; i < keys.Length; i++)
|
||||
{
|
||||
if (result[keys[i]] is string)
|
||||
{
|
||||
var asString = result[keys[i]].ToString();
|
||||
if (asString.DetectIsJson())
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = JsonConvert.DeserializeObject(asString);
|
||||
result[keys[i]] = json;
|
||||
}
|
||||
catch
|
||||
{
|
||||
//swallow this exception, we thought it was json but it really isn't so continue returning a string
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Web;
|
||||
using System.Web.Security;
|
||||
using Newtonsoft.Json;
|
||||
@@ -11,6 +12,7 @@ namespace Umbraco.Core.Security
|
||||
/// <remarks>
|
||||
/// All values are lazy loaded for performance reasons as the constructor is called for every single request
|
||||
/// </remarks>
|
||||
[Serializable]
|
||||
public class UmbracoBackOfficeIdentity : FormsIdentity
|
||||
{
|
||||
public UmbracoBackOfficeIdentity(FormsAuthenticationTicket ticket)
|
||||
@@ -104,5 +106,6 @@ namespace Umbraco.Core.Security
|
||||
HttpContext.Current.Items[typeof (UmbracoBackOfficeIdentity)] = DeserializedData;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Runtime.Serialization;
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Security
|
||||
{
|
||||
@@ -6,6 +7,7 @@ namespace Umbraco.Core.Security
|
||||
/// Data structure used to store information in the authentication cookie
|
||||
/// </summary>
|
||||
[DataContract(Name = "userData", Namespace = "")]
|
||||
[Serializable]
|
||||
internal class UserData
|
||||
{
|
||||
public UserData()
|
||||
|
||||
@@ -217,6 +217,7 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the DataTypeDefinition to save PreValues for</param>
|
||||
/// <param name="values">List of string values to save</param>
|
||||
[Obsolete("This should no longer be used, use the alternative SavePreValues or SaveDataTypeAndPreValues methods instead. This will only insert pre-values without keys")]
|
||||
public void SavePreValues(int id, IEnumerable<string> values)
|
||||
{
|
||||
//TODO: Should we raise an event here since we are really saving values for the data type?
|
||||
@@ -255,9 +256,10 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="id"></param>
|
||||
/// <param name="values"></param>
|
||||
/// <remarks>
|
||||
/// We will actually just remove all pre-values and re-insert them in one transaction
|
||||
/// We need to actually look up each pre-value and maintain it's id if possible - this is because of silly property editors
|
||||
/// like 'dropdown list publishing keys'
|
||||
/// </remarks>
|
||||
internal void SavePreValues(int id, IDictionary<string, string> values)
|
||||
public void SavePreValues(int id, IDictionary<string, PreValue> values)
|
||||
{
|
||||
//TODO: Should we raise an event here since we are really saving values for the data type?
|
||||
|
||||
@@ -267,22 +269,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var transaction = uow.Database.GetTransaction())
|
||||
{
|
||||
uow.Database.Execute("DELETE FROM cmsDataTypePreValues WHERE datatypeNodeId = @DataTypeId", new { DataTypeId = id });
|
||||
|
||||
var sortOrder = 1;
|
||||
foreach (var value in values)
|
||||
{
|
||||
var dto = new DataTypePreValueDto
|
||||
{
|
||||
DataTypeNodeId = id,
|
||||
Value = value.Value,
|
||||
SortOrder = sortOrder,
|
||||
Alias = value.Key
|
||||
};
|
||||
uow.Database.Insert(dto);
|
||||
sortOrder++;
|
||||
}
|
||||
|
||||
AddOrUpdatePreValues(id, values, uow);
|
||||
transaction.Complete();
|
||||
}
|
||||
}
|
||||
@@ -295,7 +282,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="dataTypeDefinition"></param>
|
||||
/// <param name="values"></param>
|
||||
/// <param name="userId"></param>
|
||||
public void SaveDataTypeAndPreValues(IDataTypeDefinition dataTypeDefinition, IDictionary<string, string> values, int userId = 0)
|
||||
public void SaveDataTypeAndPreValues(IDataTypeDefinition dataTypeDefinition, IDictionary<string, PreValue> values, int userId = 0)
|
||||
{
|
||||
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinition), this))
|
||||
return;
|
||||
@@ -309,25 +296,7 @@ namespace Umbraco.Core.Services
|
||||
repository.AddOrUpdate(dataTypeDefinition);
|
||||
|
||||
//complete the transaction, but run the delegate before the db transaction is finalized
|
||||
uow.Commit(database =>
|
||||
{
|
||||
//Execute this before the transaction is completed!
|
||||
database.Execute("DELETE FROM cmsDataTypePreValues WHERE datatypeNodeId = @DataTypeId", new { DataTypeId = dataTypeDefinition.Id });
|
||||
|
||||
var sortOrder = 1;
|
||||
foreach (var value in values)
|
||||
{
|
||||
var dto = new DataTypePreValueDto
|
||||
{
|
||||
DataTypeNodeId = dataTypeDefinition.Id,
|
||||
Value = value.Value,
|
||||
SortOrder = sortOrder,
|
||||
Alias = value.Key
|
||||
};
|
||||
database.Insert(dto);
|
||||
sortOrder++;
|
||||
}
|
||||
});
|
||||
uow.Commit(database => AddOrUpdatePreValues(dataTypeDefinition.Id, values, uow));
|
||||
|
||||
Saved.RaiseEvent(new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinition, false), this);
|
||||
}
|
||||
@@ -336,6 +305,56 @@ namespace Umbraco.Core.Services
|
||||
Audit.Add(AuditTypes.Save, string.Format("Save DataTypeDefinition performed by user"), userId, dataTypeDefinition.Id);
|
||||
}
|
||||
|
||||
private void AddOrUpdatePreValues(int id, IDictionary<string, PreValue> preValueCollection, IDatabaseUnitOfWork uow)
|
||||
{
|
||||
//first just get all pre-values for this data type so we can compare them to see if we need to insert or update or replace
|
||||
var sql = new Sql().Select("*")
|
||||
.From<DataTypePreValueDto>()
|
||||
.Where<DataTypePreValueDto>(dto => dto.DataTypeNodeId == id)
|
||||
.OrderBy<DataTypePreValueDto>(dto => dto.SortOrder);
|
||||
var currentVals = uow.Database.Fetch<DataTypePreValueDto>(sql).ToArray();
|
||||
|
||||
//already existing, need to be updated
|
||||
var valueIds = preValueCollection.Where(x => x.Value.Id > 0).Select(x => x.Value.Id).ToArray();
|
||||
var existingByIds = currentVals.Where(x => valueIds.Contains(x.Id)).ToArray();
|
||||
|
||||
//These ones need to be removed from the db, they no longer exist in the new values
|
||||
var deleteById = currentVals.Where(x => valueIds.Contains(x.Id) == false);
|
||||
|
||||
foreach (var d in deleteById)
|
||||
{
|
||||
uow.Database.Execute(
|
||||
"DELETE FROM cmsDataTypePreValues WHERE datatypeNodeId = @DataTypeId AND id=@Id",
|
||||
new { DataTypeId = id, Id = d.Id });
|
||||
}
|
||||
|
||||
var sortOrder = 1;
|
||||
|
||||
foreach (var pre in preValueCollection)
|
||||
{
|
||||
var existing = existingByIds.FirstOrDefault(valueDto => valueDto.Id == pre.Value.Id);
|
||||
if (existing != null)
|
||||
{
|
||||
existing.Value = pre.Value.Value;
|
||||
existing.SortOrder = sortOrder;
|
||||
uow.Database.Update(existing);
|
||||
}
|
||||
else
|
||||
{
|
||||
var dto = new DataTypePreValueDto
|
||||
{
|
||||
DataTypeNodeId = id,
|
||||
Value = pre.Value.Value,
|
||||
SortOrder = sortOrder,
|
||||
Alias = pre.Key
|
||||
};
|
||||
uow.Database.Insert(dto);
|
||||
}
|
||||
|
||||
sortOrder++;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes an <see cref="IDataTypeDefinition"/>
|
||||
/// </summary>
|
||||
|
||||
@@ -10,8 +10,6 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
public interface IDataTypeService : IService
|
||||
{
|
||||
void SaveDataTypeAndPreValues(IDataTypeDefinition dataTypeDefinition, IDictionary<string, string> values, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="IDataTypeDefinition"/> by its Id
|
||||
/// </summary>
|
||||
@@ -107,8 +105,24 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the DataTypeDefinition to save PreValues for</param>
|
||||
/// <param name="values">List of string values to save</param>
|
||||
[Obsolete("This should no longer be used, use the alternative SavePreValues or SaveDataTypeAndPreValues methods instead. This will only insert pre-values without keys")]
|
||||
void SavePreValues(int id, IEnumerable<string> values);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a list of PreValues for a given DataTypeDefinition
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the DataTypeDefinition to save PreValues for</param>
|
||||
/// <param name="values">List of key/value pairs to save</param>
|
||||
void SavePreValues(int id, IDictionary<string, PreValue> values);
|
||||
|
||||
/// <summary>
|
||||
/// Saves the data type and it's prevalues
|
||||
/// </summary>
|
||||
/// <param name="dataTypeDefinition"></param>
|
||||
/// <param name="values"></param>
|
||||
/// <param name="userId"></param>
|
||||
void SaveDataTypeAndPreValues(IDataTypeDefinition dataTypeDefinition, IDictionary<string, PreValue> values, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a specific PreValue by its Id
|
||||
/// </summary>
|
||||
|
||||
@@ -326,6 +326,7 @@
|
||||
<Compile Include="Models\PublishedContent\PublishedContentModel.cs" />
|
||||
<Compile Include="Models\PublishedContent\PublishedContentModelFactoryResolver.cs" />
|
||||
<Compile Include="Models\TaggableObjectTypes.cs" />
|
||||
<Compile Include="Packaging\PackageBinaryInspector.cs" />
|
||||
<Compile Include="PropertyEditors\IValueEditor.cs" />
|
||||
<Compile Include="PropertyEditors\PropertyCacheValue.cs" />
|
||||
<Compile Include="PropertyEditors\PropertyValueCacheAttribute.cs" />
|
||||
@@ -1083,7 +1084,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Imaging\" />
|
||||
<Folder Include="Packaging\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||
|
||||
Reference in New Issue
Block a user