Migrating the rest of the files from ContentEditing\

This commit is contained in:
Elitsa Marinovska
2020-11-03 16:36:59 +01:00
parent 5104430879
commit 6d23075d9a
16 changed files with 21 additions and 48 deletions

View File

@@ -0,0 +1,63 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Editors;
namespace Umbraco.Web.Models.ContentEditing
{
/// <summary>
/// A model representing a content item to be saved
/// </summary>
[DataContract(Name = "content", Namespace = "")]
public abstract class ContentBaseSave<TPersisted> : ContentItemBasic<ContentPropertyBasic>, IContentSave<TPersisted>
where TPersisted : IContentBase
{
protected ContentBaseSave()
{
UploadedFiles = new List<ContentPropertyFile>();
}
#region IContentSave
/// <inheritdoc />
[DataMember(Name = "action", IsRequired = true)]
[Required]
public ContentSaveAction Action { get; set; }
[DataMember(Name = "properties")]
public override IEnumerable<ContentPropertyBasic> Properties
{
get => base.Properties;
set => base.Properties = value;
}
[IgnoreDataMember]
public List<ContentPropertyFile> UploadedFiles { get; }
//These need explicit implementation because we are using internal models
/// <inheritdoc />
[IgnoreDataMember]
TPersisted IContentSave<TPersisted>.PersistedContent { get; set; }
//Non explicit internal getter so we don't need to explicitly cast in our own code
[IgnoreDataMember]
public TPersisted PersistedContent
{
get => ((IContentSave<TPersisted>)this).PersistedContent;
set => ((IContentSave<TPersisted>) this).PersistedContent = value;
}
/// <summary>
/// The property DTO object is used to gather all required property data including data type information etc... for use with validation - used during inbound model binding
/// </summary>
/// <remarks>
/// We basically use this object to hydrate all required data from the database into one object so we can validate everything we need
/// instead of having to look up all the data individually.
/// This is not used for outgoing model information.
/// </remarks>
[IgnoreDataMember]
public ContentPropertyCollectionDto PropertyCollectionDto { get; set; }
#endregion
}
}

View File

@@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Runtime.Serialization;
namespace Umbraco.Web.Models.ContentEditing
{
/// <summary>
/// A model representing a basic content item
/// </summary>
[DataContract(Name = "content", Namespace = "")]
public class ContentItemBasic : EntityBasic
{
[DataMember(Name = "updateDate")]
public DateTime UpdateDate { get; set; }
[DataMember(Name = "createDate")]
public DateTime CreateDate { get; set; }
/// <summary>
/// Boolean indicating if this item is published or not based on it's <see cref="State"/>
/// </summary>
[DataMember(Name = "published")]
public bool Published => State == ContentSavedState.Published || State == ContentSavedState.PublishedPendingChanges;
/// <summary>
/// Determines if the content item is a draft
/// </summary>
[DataMember(Name = "edited")]
public bool Edited { get; set; }
[DataMember(Name = "owner")]
public UserProfile Owner { get; set; }
[DataMember(Name = "updater")]
public UserProfile Updater { get; set; }
public int ContentTypeId { get; set; }
[DataMember(Name = "contentTypeAlias", IsRequired = true)]
[Required(AllowEmptyStrings = false)]
public string ContentTypeAlias { get; set; }
[DataMember(Name = "sortOrder")]
public int SortOrder { get; set; }
/// <summary>
/// The saved/published state of an item
/// </summary>
/// <remarks>
/// This is nullable since it's only relevant for content (non-content like media + members will be null)
/// </remarks>
[DataMember(Name = "state")]
public ContentSavedState? State { get; set; }
[DataMember(Name = "variesByCulture")]
public bool VariesByCulture { get; set; }
protected bool Equals(ContentItemBasic other)
{
return Id == other.Id;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
var other = obj as ContentItemBasic;
return other != null && Equals(other);
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
/// <summary>
/// A model representing a basic content item with properties
/// </summary>
[DataContract(Name = "content", Namespace = "")]
public class ContentItemBasic<T> : ContentItemBasic, IContentProperties<T>
where T : ContentPropertyBasic
{
public ContentItemBasic()
{
//ensure its not null
_properties = Enumerable.Empty<T>();
}
private IEnumerable<T> _properties;
public virtual IEnumerable<T> Properties
{
get => _properties;
set => _properties = value;
}
}
}

View File

@@ -0,0 +1,217 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.ContentEditing;
using Umbraco.Web.Routing;
namespace Umbraco.Web.Models.ContentEditing
{
/// <summary>
/// A model representing a content item to be displayed in the back office
/// </summary>
[DataContract(Name = "content", Namespace = "")]
public class ContentItemDisplay : INotificationModel, IErrorModel //ListViewAwareContentItemDisplayBase<ContentPropertyDisplay, IContent>
{
public ContentItemDisplay()
{
AllowPreview = true;
Notifications = new List<BackOfficeNotification>();
Errors = new Dictionary<string, object>();
Variants = new List<ContentVariantDisplay>();
ContentApps = new List<ContentApp>();
}
[DataMember(Name = "id", IsRequired = true)]
[Required]
public int Id { get; set; }
[DataMember(Name = "udi")]
[ReadOnly(true)]
public Udi Udi { get; set; }
[DataMember(Name = "icon")]
public string Icon { get; set; }
[DataMember(Name = "trashed")]
[ReadOnly(true)]
public bool Trashed { get; set; }
/// <summary>
/// This is the unique Id stored in the database - but could also be the unique id for a custom membership provider
/// </summary>
[DataMember(Name = "key")]
public Guid Key { get; set; }
[DataMember(Name = "parentId", IsRequired = true)]
[Required]
public int ParentId { get; set; }
/// <summary>
/// The path of the entity
/// </summary>
[DataMember(Name = "path")]
public string Path { get; set; }
/// <summary>
/// A collection of content variants
/// </summary>
/// <remarks>
/// If a content item is invariant, this collection will only contain one item, else it will contain all culture variants
/// </remarks>
[DataMember(Name = "variants")]
public IEnumerable<ContentVariantDisplay> Variants { get; set; }
[DataMember(Name = "owner")]
public UserProfile Owner { get; set; }
[DataMember(Name = "updater")]
public UserProfile Updater { get; set; }
/// <summary>
/// The name of the content type
/// </summary>
[DataMember(Name = "contentTypeName")]
public string ContentTypeName { get; set; }
/// <summary>
/// Indicates if the content is configured as a list view container
/// </summary>
[DataMember(Name = "isContainer")]
public bool IsContainer { get; set; }
/// <summary>
/// Indicates if the content is configured as an element
/// </summary>
[DataMember(Name = "isElement")]
public bool IsElement { get; set; }
/// <summary>
/// Property indicating if this item is part of a list view parent
/// </summary>
[DataMember(Name = "isChildOfListView")]
public bool IsChildOfListView { get; set; }
/// <summary>
/// Property for the entity's individual tree node URL
/// </summary>
/// <remarks>
/// This is required if the item is a child of a list view since the tree won't actually be loaded,
/// so the app will need to go fetch the individual tree node in order to be able to load it's action list (menu)
/// </remarks>
[DataMember(Name = "treeNodeUrl")]
public string TreeNodeUrl { get; set; }
[DataMember(Name = "contentTypeId")]
public int ContentTypeId { get; set; }
[DataMember(Name = "contentTypeKey")]
public Guid ContentTypeKey { get; set; }
[DataMember(Name = "contentTypeAlias", IsRequired = true)]
[Required(AllowEmptyStrings = false)]
public string ContentTypeAlias { get; set; }
[DataMember(Name = "sortOrder")]
public int SortOrder { get; set; }
/// <summary>
/// This is the last updated date for the entire content object regardless of variants
/// </summary>
/// <remarks>
/// Each variant has it's own update date assigned as well
/// </remarks>
[DataMember(Name = "updateDate")]
public DateTime UpdateDate { get; set; }
[DataMember(Name = "template")]
public string TemplateAlias { get; set; }
[DataMember(Name = "templateId")]
public int TemplateId { get; set; }
[DataMember(Name = "allowedTemplates")]
public IDictionary<string, string> AllowedTemplates { get; set; }
[DataMember(Name = "documentType")]
public ContentTypeBasic DocumentType { get; set; }
[DataMember(Name = "urls")]
public UrlInfo[] Urls { get; set; }
/// <summary>
/// Determines whether previewing is allowed for this node
/// </summary>
/// <remarks>
/// By default this is true but by using events developers can toggle this off for certain documents if there is nothing to preview
/// </remarks>
[DataMember(Name = "allowPreview")]
public bool AllowPreview { get; set; }
/// <summary>
/// The allowed 'actions' based on the user's permissions - Create, Update, Publish, Send to publish
/// </summary>
/// <remarks>
/// Each char represents a button which we can then map on the front-end to the correct actions
/// </remarks>
[DataMember(Name = "allowedActions")]
public IEnumerable<string> AllowedActions { get; set; }
[DataMember(Name = "isBlueprint")]
public bool IsBlueprint { get; set; }
[DataMember(Name = "apps")]
public IEnumerable<ContentApp> ContentApps { get; set; }
/// <summary>
/// The real persisted content object - used during inbound model binding
/// </summary>
/// <remarks>
/// This is not used for outgoing model information.
/// </remarks>
[IgnoreDataMember]
public IContent PersistedContent { get; set; }
/// <summary>
/// The DTO object used to gather all required content data including data type information etc... for use with validation - used during inbound model binding
/// </summary>
/// <remarks>
/// We basically use this object to hydrate all required data from the database into one object so we can validate everything we need
/// instead of having to look up all the data individually.
/// This is not used for outgoing model information.
/// </remarks>
[IgnoreDataMember]
public ContentPropertyCollectionDto ContentDto { get; set; }
/// <summary>
/// This is used to add custom localized messages/strings to the response for the app to use for localized UI purposes.
/// </summary>
[DataMember(Name = "notifications")]
[ReadOnly(true)]
public List<BackOfficeNotification> Notifications { get; private set; }
/// <summary>
/// This is used for validation of a content item.
/// </summary>
/// <remarks>
/// A content item can be invalid but still be saved. This occurs when there's property validation errors, we will
/// still save the item but it cannot be published. So we need a way of returning validation errors as well as the
/// updated model.
///
/// NOTE: The ProperCase is important because when we return ModeState normally it will always be proper case.
/// </remarks>
[DataMember(Name = "ModelState")]
[ReadOnly(true)]
public IDictionary<string, object> Errors { get; set; }
/// <summary>
/// A collection of extra data that is available for this specific entity/entity type
/// </summary>
[DataMember(Name = "metaData")]
[ReadOnly(true)]
public IDictionary<string, object> AdditionalData { get; private set; }
}
}

View File

@@ -0,0 +1,49 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.Serialization;
namespace Umbraco.Web.Models.ContentEditing
{
public abstract class ContentItemDisplayBase<T> : TabbedContentItem<T>, INotificationModel, IErrorModel
where T : ContentPropertyBasic
{
protected ContentItemDisplayBase()
{
Notifications = new List<BackOfficeNotification>();
Errors = new Dictionary<string, object>();
}
/// <summary>
/// The name of the content type
/// </summary>
[DataMember(Name = "contentTypeName")]
public string ContentTypeName { get; set; }
/// <summary>
/// Indicates if the content is configured as a list view container
/// </summary>
[DataMember(Name = "isContainer")]
public bool IsContainer { get; set; }
/// <summary>
/// This is used to add custom localized messages/strings to the response for the app to use for localized UI purposes.
/// </summary>
[DataMember(Name = "notifications")]
[ReadOnly(true)]
public List<BackOfficeNotification> Notifications { get; private set; }
/// <summary>
/// This is used for validation of a content item.
/// </summary>
/// <remarks>
/// A content item can be invalid but still be saved. This occurs when there's property validation errors, we will
/// still save the item but it cannot be published. So we need a way of returning validation errors as well as the
/// updated model.
///
/// NOTE: The ProperCase is important because when we return ModeState normally it will always be proper case.
/// </remarks>
[DataMember(Name = "ModelState")]
[ReadOnly(true)]
public IDictionary<string, object> Errors { get; set; }
}
}

View File

@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.Serialization;
namespace Umbraco.Web.Models.ContentEditing
{
/// <summary>
/// Represents the variant info for a content item
/// </summary>
[DataContract(Name = "contentVariant", Namespace = "")]
public class ContentVariantDisplay : ITabbedContent<ContentPropertyDisplay>, IContentProperties<ContentPropertyDisplay>, INotificationModel
{
public ContentVariantDisplay()
{
Tabs = new List<Tab<ContentPropertyDisplay>>();
Notifications = new List<BackOfficeNotification>();
}
[DataMember(Name = "name", IsRequired = true)]
public string Name { get; set; }
[DataMember(Name = "displayName")]
public string DisplayName { get; set; }
/// <summary>
/// Defines the tabs containing display properties
/// </summary>
[DataMember(Name = "tabs")]
public IEnumerable<Tab<ContentPropertyDisplay>> Tabs { get; set; }
/// <summary>
/// Internal property used for tests to get all properties from all tabs
/// </summary>
[IgnoreDataMember]
IEnumerable<ContentPropertyDisplay> IContentProperties<ContentPropertyDisplay>.Properties => Tabs.SelectMany(x => x.Properties);
/// <summary>
/// The language/culture assigned to this content variation
/// </summary>
/// <remarks>
/// If this is null it means this content variant is an invariant culture
/// </remarks>
[DataMember(Name = "language")]
public Language Language { get; set; }
[DataMember(Name = "segment")]
public string Segment { get; set; }
[DataMember(Name = "state")]
public ContentSavedState State { get; set; }
[DataMember(Name = "updateDate")]
public DateTime UpdateDate { get; set; }
[DataMember(Name = "createDate")]
public DateTime CreateDate { get; set; }
[DataMember(Name = "publishDate")]
public DateTime? PublishDate { get; set; }
[DataMember(Name = "releaseDate")]
public DateTime? ReleaseDate { get; set; }
[DataMember(Name = "expireDate")]
public DateTime? ExpireDate { get; set; }
/// <summary>
/// This is used to add custom localized messages/strings to the response for the app to use for localized UI purposes.
/// </summary>
/// <remarks>
/// The notifications assigned to a variant are currently only used to show custom messages in the save/publish dialogs.
/// </remarks>
[DataMember(Name = "notifications")]
[ReadOnly(true)]
public List<BackOfficeNotification> Notifications { get; private set; }
}
}

View File

@@ -0,0 +1,28 @@
using System.Runtime.Serialization;
namespace Umbraco.Web.Models.ContentEditing
{
/// <summary>
/// An abstract model representing a content item that can be contained in a list view
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class ListViewAwareContentItemDisplayBase<T> : ContentItemDisplayBase<T>
where T : ContentPropertyBasic
{
/// <summary>
/// Property indicating if this item is part of a list view parent
/// </summary>
[DataMember(Name = "isChildOfListView")]
public bool IsChildOfListView { get; set; }
/// <summary>
/// Property for the entity's individual tree node URL
/// </summary>
/// <remarks>
/// This is required if the item is a child of a list view since the tree won't actually be loaded,
/// so the app will need to go fetch the individual tree node in order to be able to load it's action list (menu)
/// </remarks>
[DataMember(Name = "treeNodeUrl")]
public string TreeNodeUrl { get; set; }
}
}

View File

@@ -0,0 +1,27 @@
using System.Collections.Generic;
using System.Runtime.Serialization;
using Umbraco.Core.Models.ContentEditing;
namespace Umbraco.Web.Models.ContentEditing
{
/// <summary>
/// A model representing a media item to be displayed in the back office
/// </summary>
[DataContract(Name = "content", Namespace = "")]
public class MediaItemDisplay : ListViewAwareContentItemDisplayBase<ContentPropertyDisplay>
{
public MediaItemDisplay()
{
ContentApps = new List<ContentApp>();
}
[DataMember(Name = "contentType")]
public ContentTypeBasic ContentType { get; set; }
[DataMember(Name = "mediaLink")]
public string MediaLink { get; set; }
[DataMember(Name = "apps")]
public IEnumerable<ContentApp> ContentApps { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
using System.Runtime.Serialization;
using Umbraco.Core.Models;
namespace Umbraco.Web.Models.ContentEditing
{
/// <summary>
/// A model representing a media item to be saved
/// </summary>
[DataContract(Name = "content", Namespace = "")]
public class MediaItemSave : ContentBaseSave<IMedia>
{
}
}

View File

@@ -0,0 +1,24 @@
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace Umbraco.Web.Models.ContentEditing
{
/// <summary>
/// Used for basic member information
/// </summary>
public class MemberBasic : ContentItemBasic<ContentPropertyBasic>
{
[DataMember(Name = "username")]
public string Username { get; set; }
[DataMember(Name = "email")]
public string Email { get; set; }
[DataMember(Name = "properties")]
public override IEnumerable<ContentPropertyBasic> Properties
{
get => base.Properties;
set => base.Properties = value;
}
}
}

View File

@@ -0,0 +1,42 @@
using System.Collections.Generic;
using System.Runtime.Serialization;
using Umbraco.Core.Models.ContentEditing;
namespace Umbraco.Web.Models.ContentEditing
{
/// <summary>
/// A model representing a member to be displayed in the back office
/// </summary>
[DataContract(Name = "content", Namespace = "")]
public class MemberDisplay : ListViewAwareContentItemDisplayBase<ContentPropertyDisplay>
{
public MemberDisplay()
{
// MemberProviderFieldMapping = new Dictionary<string, string>();
ContentApps = new List<ContentApp>();
}
[DataMember(Name = "contentType")]
public ContentTypeBasic ContentType { get; set; }
[DataMember(Name = "username")]
public string Username { get; set; }
[DataMember(Name = "email")]
public string Email { get; set; }
//[DataMember(Name = "membershipScenario")]
//public MembershipScenario MembershipScenario { get; set; }
// /// <summary>
// /// This is used to indicate how to map the membership provider properties to the save model, this mapping
// /// will change if a developer has opted to have custom member property aliases specified in their membership provider config,
// /// or if we are editing a member that is not an Umbraco member (custom provider)
// /// </summary>
// [DataMember(Name = "fieldConfig")]
// public IDictionary<string, string> MemberProviderFieldMapping { get; set; }
[DataMember(Name = "apps")]
public IEnumerable<ContentApp> ContentApps { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
using System.Collections.Generic;
using System.Runtime.Serialization;
using Umbraco.Core.Models.ContentEditing;
namespace Umbraco.Web.Models.ContentEditing
{
/// <summary>
/// A model representing a member list to be displayed in the back office
/// </summary>
[DataContract(Name = "content", Namespace = "")]
public class MemberListDisplay : ContentItemDisplayBase<ContentPropertyDisplay>
{
[DataMember(Name = "apps")]
public IEnumerable<ContentApp> ContentApps { get; set; }
}
}

View File

@@ -0,0 +1,53 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Runtime.Serialization;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Validation;
namespace Umbraco.Web.Models.ContentEditing
{
/// <inheritdoc />
public class MemberSave : ContentBaseSave<IMember>
{
[DataMember(Name = "username", IsRequired = true)]
[RequiredForPersistence(AllowEmptyStrings = false, ErrorMessage = "Required")]
public string Username { get; set; }
[DataMember(Name = "email", IsRequired = true)]
[RequiredForPersistence(AllowEmptyStrings = false, ErrorMessage = "Required")]
[EmailAddress]
public string Email { get; set; }
[DataMember(Name = "password")]
public ChangingPasswordModel Password { get; set; }
[DataMember(Name = "memberGroups")]
public IEnumerable<string> Groups { get; set; }
/// <summary>
/// Returns the value from the Comments property
/// </summary>
public string Comments => GetPropertyValue<string>(Constants.Conventions.Member.Comments);
/// <summary>
/// Returns the value from the IsLockedOut property
/// </summary>
public bool IsLockedOut => GetPropertyValue<bool>(Constants.Conventions.Member.IsLockedOut);
/// <summary>
/// Returns the value from the IsApproved property
/// </summary>
public bool IsApproved => GetPropertyValue<bool>(Constants.Conventions.Member.IsApproved);
private T GetPropertyValue<T>(string alias)
{
var prop = Properties.FirstOrDefault(x => x.Alias == alias);
if (prop == null) return default;
var converted = prop.Value.TryConvertTo<T>();
return converted.ResultOr(default);
}
}
}

View File

@@ -0,0 +1,20 @@
using System.Runtime.Serialization;
namespace Umbraco.Web.Models.ContentEditing
{
[DataContract(Name = "publicAccess", Namespace = "")]
public class PublicAccess
{
[DataMember(Name = "groups")]
public MemberGroupDisplay[] Groups { get; set; }
[DataMember(Name = "loginPage")]
public EntityBasic LoginPage { get; set; }
[DataMember(Name = "errorPage")]
public EntityBasic ErrorPage { get; set; }
[DataMember(Name = "members")]
public MemberDisplay[] Members { get; set; }
}
}

View File

@@ -0,0 +1,24 @@
using System.Runtime.Serialization;
namespace Umbraco.Web.Models.ContentEditing
{
[DataContract(Name = "richtexteditorcommand", Namespace = "")]
public class RichTextEditorCommand
{
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "alias")]
public string Alias { get; set; }
[DataMember(Name = "mode")]
public RichTextEditorCommandMode Mode { get; set; }
}
public enum RichTextEditorCommandMode
{
Insert,
Selection,
All
}
}

View File

@@ -0,0 +1,24 @@
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace Umbraco.Web.Models.ContentEditing
{
[DataContract(Name = "richtexteditorconfiguration", Namespace = "")]
public class RichTextEditorConfiguration
{
[DataMember(Name = "plugins")]
public IEnumerable<RichTextEditorPlugin> Plugins { get; set; }
[DataMember(Name = "commands")]
public IEnumerable<RichTextEditorCommand> Commands { get; set; }
[DataMember(Name = "validElements")]
public string ValidElements { get; set; }
[DataMember(Name = "inValidElements")]
public string InvalidElements { get; set; }
[DataMember(Name = "customConfig")]
public IDictionary<string,string> CustomConfig { get; set; }
}
}

View File

@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
namespace Umbraco.Web.Models.ContentEditing
{
public abstract class TabbedContentItem<T> : ContentItemBasic<T>, ITabbedContent<T> where T : ContentPropertyBasic
{
protected TabbedContentItem()
{
Tabs = new List<Tab<T>>();
}
/// <summary>
/// Defines the tabs containing display properties
/// </summary>
[DataMember(Name = "tabs")]
public IEnumerable<Tab<T>> Tabs { get; set; }
/// <summary>
/// Override the properties property to ensure we don't serialize this
/// and to simply return the properties based on the properties in the tabs collection
/// </summary>
/// <remarks>
/// This property cannot be set
/// </remarks>
[IgnoreDataMember]
public override IEnumerable<T> Properties
{
get => Tabs.SelectMany(x => x.Properties);
set => throw new NotImplementedException();
}
}
}