2021-01-13 12:48:41 +11:00
|
|
|
using System;
|
2019-06-24 11:58:36 +02:00
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Reflection;
|
2020-09-11 21:13:18 +02:00
|
|
|
using Microsoft.Extensions.Options;
|
2021-02-09 10:22:42 +01:00
|
|
|
using Umbraco.Cms.Core.Configuration;
|
|
|
|
|
using Umbraco.Cms.Core.Configuration.Models;
|
|
|
|
|
using Umbraco.Cms.Core.Events;
|
|
|
|
|
using Umbraco.Cms.Core.IO;
|
|
|
|
|
using Umbraco.Cms.Core.Models;
|
|
|
|
|
using Umbraco.Cms.Core.Services;
|
2021-02-23 12:24:51 +01:00
|
|
|
using Umbraco.Cms.Core.Services.Implement;
|
2021-02-09 10:22:42 +01:00
|
|
|
using Umbraco.Cms.Core.Strings;
|
2021-02-22 09:00:33 +01:00
|
|
|
using Umbraco.Cms.Infrastructure.ModelsBuilder;
|
2021-03-30 14:01:37 +02:00
|
|
|
using Umbraco.Cms.Infrastructure.Services.Notifications;
|
2021-02-15 13:07:12 +01:00
|
|
|
using Umbraco.Cms.Infrastructure.WebAssets;
|
2021-02-10 11:42:04 +01:00
|
|
|
using Umbraco.Cms.Web.Common.ModelBinders;
|
2019-06-24 11:58:36 +02:00
|
|
|
|
2021-02-22 09:00:33 +01:00
|
|
|
namespace Umbraco.Cms.Web.Common.ModelsBuilder
|
2019-06-24 11:58:36 +02:00
|
|
|
{
|
2021-01-13 12:48:41 +11:00
|
|
|
/// <summary>
|
|
|
|
|
/// Handles <see cref="UmbracoApplicationStarting"/> and <see cref="ServerVariablesParsing"/> notifications to initialize MB
|
|
|
|
|
/// </summary>
|
2021-03-30 14:01:37 +02:00
|
|
|
internal class ModelsBuilderNotificationHandler :
|
|
|
|
|
INotificationHandler<ServerVariablesParsing>,
|
|
|
|
|
INotificationHandler<ModelBindingError>,
|
|
|
|
|
INotificationHandler<TemplateSavingNotification>
|
2019-06-24 11:58:36 +02:00
|
|
|
{
|
2020-09-18 12:53:10 +02:00
|
|
|
private readonly ModelsBuilderSettings _config;
|
2019-12-18 18:55:00 +01:00
|
|
|
private readonly IShortStringHelper _shortStringHelper;
|
2021-02-18 08:27:35 +01:00
|
|
|
private readonly IModelsBuilderDashboardProvider _modelsBuilderDashboardProvider;
|
2019-06-24 11:58:36 +02:00
|
|
|
|
2021-01-13 12:48:41 +11:00
|
|
|
public ModelsBuilderNotificationHandler(
|
|
|
|
|
IOptions<ModelsBuilderSettings> config,
|
|
|
|
|
IShortStringHelper shortStringHelper,
|
2021-02-18 08:27:35 +01:00
|
|
|
IModelsBuilderDashboardProvider modelsBuilderDashboardProvider)
|
2019-06-24 11:58:36 +02:00
|
|
|
{
|
2020-09-11 21:13:18 +02:00
|
|
|
_config = config.Value;
|
2019-12-18 18:55:00 +01:00
|
|
|
_shortStringHelper = shortStringHelper;
|
2021-02-18 08:27:35 +01:00
|
|
|
_modelsBuilderDashboardProvider = modelsBuilderDashboardProvider;
|
2019-06-24 11:58:36 +02:00
|
|
|
}
|
|
|
|
|
|
2021-01-13 12:48:41 +11:00
|
|
|
/// <summary>
|
2021-02-01 16:53:24 +11:00
|
|
|
/// Handles the <see cref="ServerVariablesParsing"/> notification to add custom urls and MB mode
|
2021-01-13 12:48:41 +11:00
|
|
|
/// </summary>
|
2021-01-25 07:37:05 +01:00
|
|
|
public void Handle(ServerVariablesParsing notification)
|
2019-06-24 11:58:36 +02:00
|
|
|
{
|
2021-01-20 18:48:18 +11:00
|
|
|
IDictionary<string, object> serverVars = notification.ServerVariables;
|
2020-09-04 00:28:38 +10:00
|
|
|
|
|
|
|
|
if (!serverVars.ContainsKey("umbracoUrls"))
|
2021-01-13 12:48:41 +11:00
|
|
|
{
|
2020-09-04 00:28:38 +10:00
|
|
|
throw new ArgumentException("Missing umbracoUrls.");
|
2021-01-13 12:48:41 +11:00
|
|
|
}
|
|
|
|
|
|
2020-09-04 00:28:38 +10:00
|
|
|
var umbracoUrlsObject = serverVars["umbracoUrls"];
|
|
|
|
|
if (umbracoUrlsObject == null)
|
2021-01-13 12:48:41 +11:00
|
|
|
{
|
2020-09-04 00:28:38 +10:00
|
|
|
throw new ArgumentException("Null umbracoUrls");
|
2021-01-13 12:48:41 +11:00
|
|
|
}
|
|
|
|
|
|
2020-09-04 00:28:38 +10:00
|
|
|
if (!(umbracoUrlsObject is Dictionary<string, object> umbracoUrls))
|
2021-01-13 12:48:41 +11:00
|
|
|
{
|
2020-09-04 00:28:38 +10:00
|
|
|
throw new ArgumentException("Invalid umbracoUrls");
|
2021-01-13 12:48:41 +11:00
|
|
|
}
|
2020-09-04 00:28:38 +10:00
|
|
|
|
|
|
|
|
if (!serverVars.ContainsKey("umbracoPlugins"))
|
2021-01-13 12:48:41 +11:00
|
|
|
{
|
2020-09-04 00:28:38 +10:00
|
|
|
throw new ArgumentException("Missing umbracoPlugins.");
|
2021-01-13 12:48:41 +11:00
|
|
|
}
|
|
|
|
|
|
2020-09-04 00:28:38 +10:00
|
|
|
if (!(serverVars["umbracoPlugins"] is Dictionary<string, object> umbracoPlugins))
|
2021-01-13 12:48:41 +11:00
|
|
|
{
|
2020-09-04 00:28:38 +10:00
|
|
|
throw new ArgumentException("Invalid umbracoPlugins");
|
2021-01-13 12:48:41 +11:00
|
|
|
}
|
|
|
|
|
|
2021-02-18 08:27:35 +01:00
|
|
|
umbracoUrls["modelsBuilderBaseUrl"] = _modelsBuilderDashboardProvider.GetUrl();
|
2021-01-13 12:48:41 +11:00
|
|
|
umbracoPlugins["modelsBuilder"] = GetModelsBuilderSettings();
|
2019-06-24 11:58:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Dictionary<string, object> GetModelsBuilderSettings()
|
|
|
|
|
{
|
|
|
|
|
var settings = new Dictionary<string, object>
|
|
|
|
|
{
|
2021-02-01 16:53:24 +11:00
|
|
|
{"mode", _config.ModelsMode.ToString() }
|
2019-06-24 11:58:36 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return settings;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Used to check if a template is being created based on a document type, in this case we need to
|
|
|
|
|
/// ensure the template markup is correct based on the model name of the document type
|
|
|
|
|
/// </summary>
|
2021-03-30 14:01:37 +02:00
|
|
|
public void Handle(TemplateSavingNotification notification)
|
2019-06-24 11:58:36 +02:00
|
|
|
{
|
2021-03-30 14:01:37 +02:00
|
|
|
if (_config.ModelsMode == ModelsMode.Nothing)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-09 09:39:49 +02:00
|
|
|
// Don't do anything if we're not requested to create a template for a content type
|
|
|
|
|
if (notification.CreateTemplateForContentType is null or false)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-24 11:58:36 +02:00
|
|
|
// ensure we have the content type alias
|
2021-04-09 09:10:59 +02:00
|
|
|
if (notification.ContentTypeAlias is null)
|
2021-01-13 12:48:41 +11:00
|
|
|
{
|
2021-04-09 09:10:59 +02:00
|
|
|
throw new InvalidOperationException("ContentTypeAlias was not found on the notification");
|
2021-01-13 12:48:41 +11:00
|
|
|
}
|
2019-06-24 11:58:36 +02:00
|
|
|
|
2021-03-30 14:01:37 +02:00
|
|
|
foreach (ITemplate template in notification.SavedEntities)
|
2021-01-13 12:48:41 +11:00
|
|
|
{
|
2019-06-24 11:58:36 +02:00
|
|
|
// if it is in fact a new entity (not been saved yet) and the "CreateTemplateForContentType" key
|
|
|
|
|
// is found, then it means a new template is being created based on the creation of a document type
|
|
|
|
|
if (!template.HasIdentity && string.IsNullOrWhiteSpace(template.Content))
|
|
|
|
|
{
|
|
|
|
|
// ensure is safe and always pascal cased, per razor standard
|
|
|
|
|
// + this is how we get the default model name in Umbraco.ModelsBuilder.Umbraco.Application
|
2021-04-09 09:10:59 +02:00
|
|
|
var alias = notification.ContentTypeAlias;
|
2019-06-24 11:58:36 +02:00
|
|
|
var name = template.Name; // will be the name of the content type since we are creating
|
2019-12-20 17:36:44 +01:00
|
|
|
var className = UmbracoServices.GetClrName(_shortStringHelper, name, alias);
|
2019-06-24 11:58:36 +02:00
|
|
|
|
|
|
|
|
var modelNamespace = _config.ModelsNamespace;
|
|
|
|
|
|
|
|
|
|
// we do not support configuring this at the moment, so just let Umbraco use its default value
|
2021-01-13 12:48:41 +11:00
|
|
|
// var modelNamespaceAlias = ...;
|
2019-06-24 11:58:36 +02:00
|
|
|
var markup = ViewHelper.GetDefaultFileContent(
|
|
|
|
|
modelClassName: className,
|
|
|
|
|
modelNamespace: modelNamespace/*,
|
|
|
|
|
modelNamespaceAlias: modelNamespaceAlias*/);
|
|
|
|
|
|
2021-01-13 12:48:41 +11:00
|
|
|
// set the template content to the new markup
|
2019-06-24 11:58:36 +02:00
|
|
|
template.Content = markup;
|
|
|
|
|
}
|
2021-01-13 12:48:41 +11:00
|
|
|
}
|
2019-06-24 11:58:36 +02:00
|
|
|
}
|
|
|
|
|
|
2021-02-01 15:37:41 +11:00
|
|
|
/// <summary>
|
|
|
|
|
/// Handles when a model binding error occurs
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void Handle(ModelBindingError notification)
|
2019-06-24 11:58:36 +02:00
|
|
|
{
|
2021-02-01 15:37:41 +11:00
|
|
|
ModelsBuilderAssemblyAttribute sourceAttr = notification.SourceType.Assembly.GetCustomAttribute<ModelsBuilderAssemblyAttribute>();
|
|
|
|
|
ModelsBuilderAssemblyAttribute modelAttr = notification.ModelType.Assembly.GetCustomAttribute<ModelsBuilderAssemblyAttribute>();
|
2019-06-24 11:58:36 +02:00
|
|
|
|
|
|
|
|
// if source or model is not a ModelsBuider type...
|
|
|
|
|
if (sourceAttr == null || modelAttr == null)
|
|
|
|
|
{
|
|
|
|
|
// if neither are ModelsBuilder types, give up entirely
|
|
|
|
|
if (sourceAttr == null && modelAttr == null)
|
2021-01-13 12:48:41 +11:00
|
|
|
{
|
2019-06-24 11:58:36 +02:00
|
|
|
return;
|
2021-01-13 12:48:41 +11:00
|
|
|
}
|
2019-06-24 11:58:36 +02:00
|
|
|
|
|
|
|
|
// else report, but better not restart (loops?)
|
2021-02-01 15:37:41 +11:00
|
|
|
notification.Message.Append(" The ");
|
|
|
|
|
notification.Message.Append(sourceAttr == null ? "view model" : "source");
|
|
|
|
|
notification.Message.Append(" is a ModelsBuilder type, but the ");
|
|
|
|
|
notification.Message.Append(sourceAttr != null ? "view model" : "source");
|
|
|
|
|
notification.Message.Append(" is not. The application is in an unstable state and should be restarted.");
|
2019-06-24 11:58:36 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// both are ModelsBuilder types
|
2019-10-28 18:02:52 +11:00
|
|
|
var pureSource = sourceAttr.PureLive;
|
|
|
|
|
var pureModel = modelAttr.PureLive;
|
2019-06-24 11:58:36 +02:00
|
|
|
|
2019-10-28 18:02:52 +11:00
|
|
|
if (sourceAttr.PureLive || modelAttr.PureLive)
|
2021-01-13 12:48:41 +11:00
|
|
|
{
|
2019-10-28 18:02:52 +11:00
|
|
|
if (pureSource == false || pureModel == false)
|
|
|
|
|
{
|
2019-06-24 11:58:36 +02:00
|
|
|
// only one is pure - report, but better not restart (loops?)
|
2021-02-01 15:37:41 +11:00
|
|
|
notification.Message.Append(pureSource
|
2019-10-28 18:02:52 +11:00
|
|
|
? " The content model is PureLive, but the view model is not."
|
|
|
|
|
: " The view model is PureLive, but the content model is not.");
|
2021-02-01 15:37:41 +11:00
|
|
|
notification.Message.Append(" The application is in an unstable state and should be restarted.");
|
2019-10-28 18:02:52 +11:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-06-24 11:58:36 +02:00
|
|
|
// both are pure - report, and if different versions, restart
|
|
|
|
|
// if same version... makes no sense... and better not restart (loops?)
|
2021-02-01 16:53:24 +11:00
|
|
|
Version sourceVersion = notification.SourceType.Assembly.GetName().Version;
|
|
|
|
|
Version modelVersion = notification.ModelType.Assembly.GetName().Version;
|
2021-02-01 15:37:41 +11:00
|
|
|
notification.Message.Append(" Both view and content models are PureLive, with ");
|
|
|
|
|
notification.Message.Append(sourceVersion == modelVersion
|
2019-10-28 18:02:52 +11:00
|
|
|
? "same version. The application is in an unstable state and should be restarted."
|
2021-02-01 16:53:24 +11:00
|
|
|
: "different versions. The application is in an unstable state and should be restarted.");
|
2019-10-28 18:02:52 +11:00
|
|
|
}
|
2021-01-13 12:48:41 +11:00
|
|
|
}
|
2019-06-24 11:58:36 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|