This commit is contained in:
perploug
2013-10-27 15:22:04 +01:00
64 changed files with 1287 additions and 1865 deletions

View File

@@ -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)

View File

@@ -9,7 +9,11 @@
{
Value = value;
Id = id;
}
public PreValue(string value)
{
Value = value;
}
/// <summary>

View 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;
}
}
}

View File

@@ -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
}
}
}
}
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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()

View File

@@ -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>

View File

@@ -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>

View File

@@ -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" />