2013-07-25 16:08:18 +10:00
using System ;
2013-08-12 15:57:54 +10:00
using System.Collections.Generic ;
2013-10-31 16:51:08 +11:00
using System.Globalization ;
2013-08-12 14:16:45 +10:00
using System.Linq ;
2013-12-12 13:27:33 +11:00
using System.Web ;
using System.Web.Mvc ;
using System.Web.Routing ;
2013-07-25 16:08:18 +10:00
using AutoMapper ;
2016-01-06 11:22:15 +01:00
using umbraco ;
2013-05-27 01:23:49 -10:00
using Umbraco.Core ;
using Umbraco.Core.Models ;
2013-07-25 16:08:18 +10:00
using Umbraco.Core.Models.Mapping ;
2013-08-28 17:53:31 +10:00
using Umbraco.Core.Services ;
2013-05-27 01:23:49 -10:00
using Umbraco.Web.Models.ContentEditing ;
2013-12-12 13:27:33 +11:00
using Umbraco.Web.Trees ;
2013-08-12 15:57:54 +10:00
using Umbraco.Web.Routing ;
2013-10-31 16:51:08 +11:00
using umbraco.BusinessLogic.Actions ;
2016-01-06 11:22:15 +01:00
using Umbraco.Core.PropertyEditors ;
2013-05-27 01:23:49 -10:00
namespace Umbraco.Web.Models.Mapping
{
2013-07-25 16:08:18 +10:00
/// <summary>
/// Declares how model mappings for content
/// </summary>
internal class ContentModelMapper : MapperConfiguration
2013-05-27 01:23:49 -10:00
{
2013-07-25 16:08:18 +10:00
public override void ConfigureMappings ( IConfiguration config , ApplicationContext applicationContext )
2013-06-03 23:50:20 -10:00
{
2013-12-12 13:27:33 +11:00
2013-07-25 16:08:18 +10:00
//FROM IContent TO ContentItemDisplay
config . CreateMap < IContent , ContentItemDisplay > ( )
2014-10-02 19:55:24 +10:00
. ForMember (
dto = > dto . Owner ,
expression = > expression . ResolveUsing < OwnerResolver < IContent > > ( ) )
. ForMember (
dto = > dto . Updater ,
expression = > expression . ResolveUsing < CreatorResolver > ( ) )
. ForMember (
dto = > dto . Icon ,
expression = > expression . MapFrom ( content = > content . ContentType . Icon ) )
. ForMember (
dto = > dto . ContentTypeAlias ,
expression = > expression . MapFrom ( content = > content . ContentType . Alias ) )
. ForMember (
dto = > dto . ContentTypeName ,
expression = > expression . MapFrom ( content = > content . ContentType . Name ) )
. ForMember (
dto = > dto . IsContainer ,
expression = > expression . MapFrom ( content = > content . ContentType . IsContainer ) )
2015-10-27 18:13:18 +01:00
. ForMember ( display = > display . IsChildOfListView , expression = > expression . Ignore ( ) )
2014-10-02 19:55:24 +10:00
. ForMember (
dto = > dto . Trashed ,
expression = > expression . MapFrom ( content = > content . Trashed ) )
. ForMember (
dto = > dto . PublishDate ,
expression = > expression . MapFrom ( content = > GetPublishedDate ( content , applicationContext ) ) )
. ForMember (
dto = > dto . TemplateAlias , expression = > expression . MapFrom ( content = > content . Template . Alias ) )
. ForMember (
dto = > dto . Urls ,
expression = > expression . MapFrom ( content = >
UmbracoContext . Current = = null
? new [ ] { "Cannot generate urls without a current Umbraco Context" }
2015-01-05 10:01:58 +11:00
: content . GetContentUrls ( UmbracoContext . Current ) ) )
2014-10-02 19:55:24 +10:00
. ForMember ( display = > display . Properties , expression = > expression . Ignore ( ) )
. ForMember ( display = > display . TreeNodeUrl , expression = > expression . Ignore ( ) )
. ForMember ( display = > display . Notifications , expression = > expression . Ignore ( ) )
. ForMember ( display = > display . Errors , expression = > expression . Ignore ( ) )
. ForMember ( display = > display . Alias , expression = > expression . Ignore ( ) )
2016-01-06 11:22:15 +01:00
. ForMember ( display = > display . Tabs , expression = > expression . ResolveUsing ( new TabsAndPropertiesResolver ( applicationContext . Services . TextService ) ) )
2014-10-02 19:55:24 +10:00
. ForMember ( display = > display . AllowedActions , expression = > expression . ResolveUsing (
new ActionButtonsResolver ( new Lazy < IUserService > ( ( ) = > applicationContext . Services . UserService ) ) ) )
2015-10-22 23:41:18 +02:00
. AfterMap ( ( media , display ) = > AfterMap ( media , display , applicationContext . Services . DataTypeService , applicationContext . Services . TextService ,
2015-10-28 12:28:29 +01:00
applicationContext . Services . ContentTypeService ) ) ;
2013-05-27 01:23:49 -10:00
2013-07-25 16:08:18 +10:00
//FROM IContent TO ContentItemBasic<ContentPropertyBasic, IContent>
config . CreateMap < IContent , ContentItemBasic < ContentPropertyBasic , IContent > > ( )
2014-04-14 15:20:02 +10:00
. ForMember (
dto = > dto . Owner ,
expression = > expression . ResolveUsing < OwnerResolver < IContent > > ( ) )
. ForMember (
2014-09-12 11:53:09 +10:00
dto = > dto . Updater ,
2014-04-14 15:20:02 +10:00
expression = > expression . ResolveUsing < CreatorResolver > ( ) )
. ForMember (
dto = > dto . Icon ,
expression = > expression . MapFrom ( content = > content . ContentType . Icon ) )
2014-10-02 19:55:24 +10:00
. ForMember (
dto = > dto . Trashed ,
expression = > expression . MapFrom ( content = > content . Trashed ) )
2014-04-14 15:20:02 +10:00
. ForMember (
dto = > dto . ContentTypeAlias ,
expression = > expression . MapFrom ( content = > content . ContentType . Alias ) )
. ForMember ( display = > display . Alias , expression = > expression . Ignore ( ) ) ;
2013-06-10 16:43:42 -02:00
2013-07-25 16:08:18 +10:00
//FROM IContent TO ContentItemDto<IContent>
config . CreateMap < IContent , ContentItemDto < IContent > > ( )
2013-08-28 17:53:31 +10:00
. ForMember (
2014-04-14 15:20:02 +10:00
dto = > dto . Owner ,
expression = > expression . ResolveUsing < OwnerResolver < IContent > > ( ) )
2014-09-12 11:53:09 +10:00
. ForMember ( display = > display . Updater , expression = > expression . Ignore ( ) )
2014-04-14 15:20:02 +10:00
. ForMember ( display = > display . Icon , expression = > expression . Ignore ( ) )
. ForMember ( display = > display . Alias , expression = > expression . Ignore ( ) ) ;
2013-06-10 16:43:42 -02:00
2013-12-12 13:27:33 +11:00
}
2013-06-10 16:43:42 -02:00
2013-08-22 15:48:32 +10:00
/// <summary>
/// Maps the generic tab with custom properties for content
/// </summary>
/// <param name="content"></param>
/// <param name="display"></param>
2015-05-13 17:33:59 +10:00
/// <param name="dataTypeService"></param>
/// <param name="localizedText"></param>
2015-10-22 23:41:18 +02:00
/// <param name="contentTypeService"></param>
2015-10-28 12:28:29 +01:00
private static void AfterMap ( IContent content , ContentItemDisplay display , IDataTypeService dataTypeService ,
ILocalizedTextService localizedText , IContentTypeService contentTypeService )
2013-08-22 15:48:32 +10:00
{
2015-10-27 18:13:18 +01:00
//map the IsChildOfListView (this is actually if it is a descendant of a list view!)
//TODO: Fix this shorthand .Ancestors() lookup, at least have an overload to use the current
2015-10-29 12:05:46 +01:00
if ( content . HasIdentity )
{
var ancesctorListView = content . Ancestors ( ) . FirstOrDefault ( x = > x . ContentType . IsContainer ) ;
display . IsChildOfListView = ancesctorListView ! = null ;
}
else
{
//it's new so it doesn't have a path, so we need to look this up by it's parent + ancestors
var parent = content . Parent ( ) ;
2015-10-29 12:19:54 +01:00
if ( parent = = null )
{
display . IsChildOfListView = false ;
}
else if ( parent . ContentType . IsContainer )
2015-10-29 12:05:46 +01:00
{
display . IsChildOfListView = true ;
}
else
{
var ancesctorListView = parent . Ancestors ( ) . FirstOrDefault ( x = > x . ContentType . IsContainer ) ;
display . IsChildOfListView = ancesctorListView ! = null ;
}
}
2015-10-27 18:13:18 +01:00
2013-12-12 14:10:03 +11:00
//map the tree node url
if ( HttpContext . Current ! = null )
{
var urlHelper = new UrlHelper ( new RequestContext ( new HttpContextWrapper ( HttpContext . Current ) , new RouteData ( ) ) ) ;
var url = urlHelper . GetUmbracoApiService < ContentTreeController > ( controller = > controller . GetTreeNode ( display . Id . ToString ( ) , null ) ) ;
2014-10-02 19:55:24 +10:00
display . TreeNodeUrl = url ;
2013-12-12 14:10:03 +11:00
}
2015-05-13 17:33:59 +10:00
2013-08-22 15:48:32 +10:00
//fill in the template config to be passed to the template drop down.
2013-12-12 13:27:33 +11:00
var templateItemConfig = new Dictionary < string , string > { { "" , "Choose..." } } ;
2014-11-26 10:20:19 +11:00
foreach ( var t in content . ContentType . AllowedTemplates
. Where ( t = > t . Alias . IsNullOrWhiteSpace ( ) = = false & & t . Name . IsNullOrWhiteSpace ( ) = = false ) )
2013-09-05 15:14:28 +10:00
{
templateItemConfig . Add ( t . Alias , t . Name ) ;
}
2013-12-12 13:27:33 +11:00
2013-10-01 21:12:32 +10:00
if ( content . ContentType . IsContainer )
{
2016-01-06 11:22:15 +01:00
TabsAndPropertiesResolver . AddListView ( display , "content" , dataTypeService , localizedText ) ;
2013-10-01 21:12:32 +10:00
}
2016-01-06 11:22:15 +01:00
2016-04-05 07:01:05 +01:00
//Added check for publish permissions before adding releaseDate and expireDate
2015-10-28 12:28:29 +01:00
var properties = new List < ContentPropertyDisplay >
2015-10-22 23:41:18 +02:00
{
2016-01-06 11:22:15 +01:00
new ContentPropertyDisplay
{
Alias = string . Format ( "{0}doctype" , Constants . PropertyEditors . InternalGenericPropertiesPrefix ) ,
Label = localizedText . Localize ( "content/documentType" ) ,
Value = localizedText . UmbracoDictionaryTranslate ( display . ContentTypeName ) ,
View = PropertyEditorResolver . Current . GetByAlias ( Constants . PropertyEditors . NoEditAlias ) . ValueEditor . View
} ,
2016-04-05 07:01:05 +01:00
new ContentPropertyDisplay
2015-10-28 12:28:29 +01:00
{
Alias = string . Format ( "{0}releasedate" , Constants . PropertyEditors . InternalGenericPropertiesPrefix ) ,
Label = localizedText . Localize ( "content/releaseDate" ) ,
Value = display . ReleaseDate . HasValue ? display . ReleaseDate . Value . ToIsoString ( ) : null ,
2016-04-05 07:01:05 +01:00
View = display . AllowedActions . Contains ( 'P' ) ? "datepicker" : PropertyEditorResolver . Current . GetByAlias ( Constants . PropertyEditors . NoEditAlias ) . ValueEditor . View //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor
} ,
2013-08-22 15:48:32 +10:00
new ContentPropertyDisplay
2015-10-28 12:28:29 +01:00
{
Alias = string . Format ( "{0}expiredate" , Constants . PropertyEditors . InternalGenericPropertiesPrefix ) ,
Label = localizedText . Localize ( "content/unpublishDate" ) ,
Value = display . ExpireDate . HasValue ? display . ExpireDate . Value . ToIsoString ( ) : null ,
2016-04-05 07:01:05 +01:00
View = display . AllowedActions . Contains ( 'P' ) ? "datepicker" : PropertyEditorResolver . Current . GetByAlias ( Constants . PropertyEditors . NoEditAlias ) . ValueEditor . View //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor
2015-10-28 12:28:29 +01:00
} ,
2013-08-22 15:48:32 +10:00
new ContentPropertyDisplay
2015-10-28 12:28:29 +01:00
{
Alias = string . Format ( "{0}template" , Constants . PropertyEditors . InternalGenericPropertiesPrefix ) ,
2016-01-06 11:22:15 +01:00
Label = localizedText . Localize ( "template/template" ) ,
2015-10-28 12:28:29 +01:00
Value = display . TemplateAlias ,
View = "dropdown" , //TODO: Hard coding until we make a real dropdown property editor to lookup
Config = new Dictionary < string , object >
2013-08-22 15:48:32 +10:00
{
2015-10-28 12:28:29 +01:00
{ "items" , templateItemConfig }
}
} ,
2013-08-22 15:48:32 +10:00
new ContentPropertyDisplay
2015-10-28 12:28:29 +01:00
{
Alias = string . Format ( "{0}urls" , Constants . PropertyEditors . InternalGenericPropertiesPrefix ) ,
Label = localizedText . Localize ( "content/urls" ) ,
Value = string . Join ( "," , display . Urls ) ,
View = "urllist" //TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor
}
} ;
2016-01-06 11:22:15 +01:00
TabsAndPropertiesResolver . MapGenericProperties ( content , display , localizedText , properties . ToArray ( ) ,
2015-10-28 12:28:29 +01:00
genericProperties = >
{
//TODO: This would be much nicer with the IUmbracoContextAccessor so we don't use singletons
2015-11-02 23:34:33 +01:00
//If this is a web request and there's a user signed in and the
// user has access to the settings section, we will
if ( HttpContext . Current ! = null & & UmbracoContext . Current ! = null & & UmbracoContext . Current . Security . CurrentUser ! = null
2015-10-28 12:28:29 +01:00
& & UmbracoContext . Current . Security . CurrentUser . AllowedSections . Any ( x = > x . Equals ( Constants . Applications . Settings ) ) )
2013-08-22 15:48:32 +10:00
{
2015-10-28 12:28:29 +01:00
var currentDocumentType = contentTypeService . GetContentType ( display . ContentTypeAlias ) ;
var currentDocumentTypeName = currentDocumentType = = null ? string . Empty : currentDocumentType . Name ;
var currentDocumentTypeId = currentDocumentType = = null ? string . Empty : currentDocumentType . Id . ToString ( CultureInfo . InvariantCulture ) ;
//TODO: Hard coding this is not good
2015-12-02 14:41:37 +01:00
var docTypeLink = string . Format ( "#/settings/documenttypes/edit/{0}" , currentDocumentTypeId ) ;
2015-10-28 12:28:29 +01:00
//Replace the doc type property
var docTypeProp = genericProperties . First ( x = > x . Alias = = string . Format ( "{0}doctype" , Constants . PropertyEditors . InternalGenericPropertiesPrefix ) ) ;
docTypeProp . Value = new List < object >
{
new
2013-08-22 15:48:32 +10:00
{
2015-10-28 12:28:29 +01:00
linkText = currentDocumentTypeName ,
url = docTypeLink ,
target = "_self" , icon = "icon-item-arrangement"
2013-08-22 15:48:32 +10:00
}
2015-10-28 12:28:29 +01:00
} ;
//TODO: Hard coding this because the templatepicker doesn't necessarily need to be a resolvable (real) property editor
docTypeProp . View = "urllist" ;
}
} ) ;
2013-12-12 13:27:33 +11:00
2015-10-28 12:28:29 +01:00
}
2013-10-01 21:12:32 +10:00
2013-07-25 16:08:18 +10:00
/// <summary>
/// Gets the published date value for the IContent object
/// </summary>
/// <param name="content"></param>
/// <param name="applicationContext"></param>
/// <returns></returns>
private static DateTime ? GetPublishedDate ( IContent content , ApplicationContext applicationContext )
{
if ( content . Published )
{
return content . UpdateDate ;
}
2015-02-10 15:28:48 +01:00
if ( content . HasPublishedVersion )
2013-07-25 16:08:18 +10:00
{
var published = applicationContext . Services . ContentService . GetPublishedVersion ( content . Id ) ;
return published . UpdateDate ;
}
return null ;
}
2013-06-10 16:43:42 -02:00
2013-10-31 16:51:08 +11:00
/// <summary>
/// Creates the list of action buttons allowed for this user - Publish, Send to publish, save, unpublish returned as the button's 'letter'
/// </summary>
private class ActionButtonsResolver : ValueResolver < IContent , IEnumerable < char > >
{
private readonly Lazy < IUserService > _userService ;
public ActionButtonsResolver ( Lazy < IUserService > userService )
{
_userService = userService ;
}
protected override IEnumerable < char > ResolveCore ( IContent source )
{
if ( UmbracoContext . Current = = null )
{
//cannot check permissions without a context
return Enumerable . Empty < char > ( ) ;
}
var svc = _userService . Value ;
2015-08-31 18:04:13 +02:00
var permissions = svc . GetPermissions (
//TODO: This is certainly not ideal usage here - perhaps the best way to deal with this in the future is
// with the IUmbracoContextAccessor. In the meantime, if used outside of a web app this will throw a null
// refrence exception :(
UmbracoContext . Current . Security . CurrentUser ,
// Here we need to do a special check since this could be new content, in which case we need to get the permissions
// from the parent, not the existing one otherwise permissions would be coming from the root since Id is 0.
source . HasIdentity ? source . Id : source . ParentId )
. FirstOrDefault ( ) ;
2016-02-25 17:05:44 +01:00
return permissions = = null
? Enumerable . Empty < char > ( )
: permissions . AssignedPermissions . Where ( x = > x . Length = = 1 ) . Select ( x = > x . ToUpperInvariant ( ) [ 0 ] ) ;
2013-10-31 16:51:08 +11:00
}
2013-12-12 13:27:33 +11:00
}
2013-10-31 16:51:08 +11:00
2013-06-10 16:43:42 -02:00
}
2013-07-25 16:08:18 +10:00
}