Moved Models from Umbraco.Core to Umbraco.Infrastructure

This commit is contained in:
Bjarke Berg
2019-12-10 08:37:19 +01:00
parent becce7800b
commit 67536a49a7
43 changed files with 238 additions and 218 deletions

View File

@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
namespace Umbraco.Core.Models
{
/// <summary>
/// Provides extension methods for the <see cref="IContentBase"/> class, to manage tags.
/// </summary>
public static class ContentTagsExtensions
{
/// <summary>
/// Assign tags.
/// </summary>
/// <param name="content">The content item.</param>
/// <param name="propertyTypeAlias">The property alias.</param>
/// <param name="tags">The tags.</param>
/// <param name="merge">A value indicating whether to merge the tags with existing tags instead of replacing them.</param>
/// <param name="culture">A culture, for multi-lingual properties.</param>
public static void AssignTags(this IContentBase content, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, string propertyTypeAlias, IEnumerable<string> tags, bool merge = false, string culture = null)
{
content.GetTagProperty(propertyTypeAlias).AssignTags(propertyEditors, dataTypeService, tags, merge, culture);
}
/// <summary>
/// Remove tags.
/// </summary>
/// <param name="content">The content item.</param>
/// <param name="propertyTypeAlias">The property alias.</param>
/// <param name="tags">The tags.</param>
/// <param name="culture">A culture, for multi-lingual properties.</param>
public static void RemoveTags(this IContentBase content, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, string propertyTypeAlias, IEnumerable<string> tags, string culture = null)
{
content.GetTagProperty(propertyTypeAlias).RemoveTags(propertyEditors, dataTypeService, tags, culture);
}
// gets and validates the property
private static IProperty GetTagProperty(this IContentBase content, string propertyTypeAlias)
{
if (content == null) throw new ArgumentNullException(nameof(content));
var property = content.Properties[propertyTypeAlias];
if (property != null) return property;
throw new IndexOutOfRangeException($"Could not find a property with alias \"{propertyTypeAlias}\".");
}
}
}

View File

@@ -1,26 +0,0 @@
namespace Umbraco.Core.Models.Identity
{
internal class UserLoginInfoWrapper : IUserLoginInfo
{
private readonly IUserLoginInfo _info;
public static IUserLoginInfo Wrap(IUserLoginInfo info) => new UserLoginInfoWrapper(info);
private UserLoginInfoWrapper(IUserLoginInfo info)
{
_info = info;
}
public string LoginProvider
{
get => _info.LoginProvider;
set => _info.LoginProvider = value;
}
public string ProviderKey
{
get => _info.ProviderKey;
set => _info.ProviderKey = value;
}
}
}

View File

@@ -0,0 +1,230 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Composing;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
namespace Umbraco.Core.Models
{
/// <summary>
/// Provides extension methods for the <see cref="Property"/> class to manage tags.
/// </summary>
public static class PropertyTagsExtensions
{
// gets the tag configuration for a property
// from the datatype configuration, and the editor tag configuration attribute
internal static TagConfiguration GetTagConfiguration(this IProperty property, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService)
{
if (property == null) throw new ArgumentNullException(nameof(property));
var editor = propertyEditors[property.PropertyType.PropertyEditorAlias];
var tagAttribute = editor.GetTagAttribute();
if (tagAttribute == null) return null;
var configurationObject = dataTypeService.GetDataType(property.PropertyType.DataTypeId).Configuration;
var configuration = ConfigurationEditor.ConfigurationAs<TagConfiguration>(configurationObject);
if (configuration.Delimiter == default)
configuration.Delimiter = tagAttribute.Delimiter;
return configuration;
}
/// <summary>
/// Assign tags.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="tags">The tags.</param>
/// <param name="merge">A value indicating whether to merge the tags with existing tags instead of replacing them.</param>
/// <param name="culture">A culture, for multi-lingual properties.</param>
public static void AssignTags(this IProperty property, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, IEnumerable<string> tags, bool merge = false, string culture = null)
{
if (property == null) throw new ArgumentNullException(nameof(property));
var configuration = property.GetTagConfiguration(propertyEditors, dataTypeService);
if (configuration == null)
throw new NotSupportedException($"Property with alias \"{property.Alias}\" does not support tags.");
property.AssignTags(tags, merge, configuration.StorageType, configuration.Delimiter, culture);
}
// assumes that parameters are consistent with the datatype configuration
private static void AssignTags(this IProperty property, IEnumerable<string> tags, bool merge, TagsStorageType storageType, char delimiter, string culture)
{
// set the property value
var trimmedTags = tags.Select(x => x.Trim()).ToArray();
if (merge)
{
var currentTags = property.GetTagsValue(storageType, delimiter);
switch (storageType)
{
case TagsStorageType.Csv:
property.SetValue(string.Join(delimiter.ToString(), currentTags.Union(trimmedTags)), culture); // csv string
break;
case TagsStorageType.Json:
property.SetValue(JsonConvert.SerializeObject(currentTags.Union(trimmedTags).ToArray()), culture); // json array
break;
}
}
else
{
switch (storageType)
{
case TagsStorageType.Csv:
property.SetValue(string.Join(delimiter.ToString(), trimmedTags), culture); // csv string
break;
case TagsStorageType.Json:
property.SetValue(JsonConvert.SerializeObject(trimmedTags), culture); // json array
break;
}
}
}
/// <summary>
/// Removes tags.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="tags">The tags.</param>
/// <param name="culture">A culture, for multi-lingual properties.</param>
public static void RemoveTags(this IProperty property, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, IEnumerable<string> tags, string culture = null)
{
if (property == null) throw new ArgumentNullException(nameof(property));
var configuration = property.GetTagConfiguration(propertyEditors, dataTypeService);
if (configuration == null)
throw new NotSupportedException($"Property with alias \"{property.Alias}\" does not support tags.");
property.RemoveTags(tags, configuration.StorageType, configuration.Delimiter, culture);
}
// assumes that parameters are consistent with the datatype configuration
private static void RemoveTags(this IProperty property, IEnumerable<string> tags, TagsStorageType storageType, char delimiter, string culture)
{
// already empty = nothing to do
var value = property.GetValue(culture)?.ToString();
if (string.IsNullOrWhiteSpace(value)) return;
// set the property value
var trimmedTags = tags.Select(x => x.Trim()).ToArray();
var currentTags = property.GetTagsValue(storageType, delimiter, culture);
switch (storageType)
{
case TagsStorageType.Csv:
property.SetValue(string.Join(delimiter.ToString(), currentTags.Except(trimmedTags)), culture); // csv string
break;
case TagsStorageType.Json:
property.SetValue(JsonConvert.SerializeObject(currentTags.Except(trimmedTags).ToArray()), culture); // json array
break;
}
}
// used by ContentRepositoryBase
internal static IEnumerable<string> GetTagsValue(this IProperty property, PropertyEditorCollection propertyEditors, IDataTypeService dataTypeService, string culture = null)
{
if (property == null) throw new ArgumentNullException(nameof(property));
var configuration = property.GetTagConfiguration(propertyEditors, dataTypeService);
if (configuration == null)
throw new NotSupportedException($"Property with alias \"{property.Alias}\" does not support tags.");
return property.GetTagsValue(configuration.StorageType, configuration.Delimiter, culture);
}
private static IEnumerable<string> GetTagsValue(this IProperty property, TagsStorageType storageType, char delimiter, string culture = null)
{
if (property == null) throw new ArgumentNullException(nameof(property));
var value = property.GetValue(culture)?.ToString();
if (string.IsNullOrWhiteSpace(value)) return Enumerable.Empty<string>();
switch (storageType)
{
case TagsStorageType.Csv:
return value.Split(new[] { delimiter }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim());
case TagsStorageType.Json:
try
{
return JsonConvert.DeserializeObject<JArray>(value).Select(x => x.ToString().Trim());
}
catch (JsonException)
{
//cannot parse, malformed
return Enumerable.Empty<string>();
}
default:
throw new NotSupportedException($"Value \"{storageType}\" is not a valid TagsStorageType.");
}
}
/// <summary>
/// Sets tags on a content property, based on the property editor tags configuration.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="value">The property value.</param>
/// <param name="tagConfiguration">The datatype configuration.</param>
/// <param name="culture">A culture, for multi-lingual properties.</param>
/// <remarks>
/// <para>The value is either a string (delimited string) or an enumeration of strings (tag list).</para>
/// <para>This is used both by the content repositories to initialize a property with some tag values, and by the
/// content controllers to update a property with values received from the property editor.</para>
/// </remarks>
public static void SetTagsValue(this IProperty property, object value, TagConfiguration tagConfiguration, string culture)
{
if (property == null) throw new ArgumentNullException(nameof(property));
if (tagConfiguration == null) throw new ArgumentNullException(nameof(tagConfiguration));
var storageType = tagConfiguration.StorageType;
var delimiter = tagConfiguration.Delimiter;
SetTagsValue(property, value, storageType, delimiter, culture);
}
// assumes that parameters are consistent with the datatype configuration
// value can be an enumeration of string, or a serialized value using storageType format
private static void SetTagsValue(IProperty property, object value, TagsStorageType storageType, char delimiter, string culture)
{
if (value == null) value = Enumerable.Empty<string>();
// if value is already an enumeration of strings, just use it
if (value is IEnumerable<string> tags1)
{
property.AssignTags(tags1, false, storageType, delimiter, culture);
return;
}
// otherwise, deserialize value based upon storage type
switch (storageType)
{
case TagsStorageType.Csv:
var tags2 = value.ToString().Split(new[] { delimiter }, StringSplitOptions.RemoveEmptyEntries);
property.AssignTags(tags2, false, storageType, delimiter, culture);
break;
case TagsStorageType.Json:
try
{
var tags3 = JsonConvert.DeserializeObject<IEnumerable<string>>(value.ToString());
property.AssignTags(tags3 ?? Enumerable.Empty<string>(), false, storageType, delimiter, culture);
}
catch (Exception ex)
{
Current.Logger.Warn(typeof(PropertyTagsExtensions), ex, "Could not automatically convert stored json value to an enumerable string '{Json}'", value.ToString());
}
break;
default:
throw new ArgumentOutOfRangeException(nameof(storageType));
}
}
}
}

View File

@@ -0,0 +1,35 @@
using System;
using Umbraco.Core.Composing;
namespace Umbraco.Core.Models.PublishedContent
{
/// <summary>
/// Provides strongly typed published content models services.
/// </summary>
public static class PublishedContentExtensionsForModels
{
/// <summary>
/// Creates a strongly typed published content model for an internal published content.
/// </summary>
/// <param name="content">The internal published content.</param>
/// <returns>The strongly typed published content model.</returns>
public static IPublishedContent CreateModel(this IPublishedContent content, IPublishedModelFactory publishedModelFactory)
{
if (publishedModelFactory == null) throw new ArgumentNullException(nameof(publishedModelFactory));
if (content == null)
return null;
// get model
// if factory returns nothing, throw
var model = publishedModelFactory.CreateModel(content);
if (model == null)
throw new InvalidOperationException("Factory returned null.");
// if factory returns a different type, throw
if (!(model is IPublishedContent publishedContent))
throw new InvalidOperationException($"Factory returned model of type {model.GetType().FullName} which does not implement IPublishedContent.");
return publishedContent;
}
}
}