Files
Umbraco-CMS/src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComponent.cs

188 lines
8.7 KiB
C#
Raw Normal View History

2019-06-24 11:58:36 +02:00
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Umbraco.Configuration;
using Umbraco.Core.Configuration;
2019-06-24 11:58:36 +02:00
using Umbraco.Core.Composing;
using Umbraco.Core.IO;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Implement;
using Umbraco.Core.Strings;
using Umbraco.ModelsBuilder.Embedded.BackOffice;
2019-06-24 11:58:36 +02:00
using Umbraco.Web;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebAssets;
2019-06-24 11:58:36 +02:00
namespace Umbraco.ModelsBuilder.Embedded.Compose
2019-06-24 11:58:36 +02:00
{
internal class ModelsBuilderComponent : IComponent
2019-06-24 11:58:36 +02:00
{
private readonly IModelsBuilderConfig _config;
private readonly IShortStringHelper _shortStringHelper;
private readonly LiveModelsProvider _liveModelsProvider;
private readonly OutOfDateModelsStatus _outOfDateModels;
2019-06-24 11:58:36 +02:00
Merge branch 'netcore/dev' into feature/7371-short-string-helper # Conflicts: # src/Umbraco.Core/StringExtensions.cs # src/Umbraco.Core/TypeExtensions.cs # src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs # src/Umbraco.Infrastructure/Persistence/Factories/DataTypeFactory.cs # src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs # src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComponent.cs # src/Umbraco.ModelsBuilder.Embedded/UmbracoServices.cs # src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs # src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs # src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs # src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs # src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs # src/Umbraco.Tests/Strings/StringExtensionsTests.cs # src/Umbraco.Tests/Web/Controllers/ContentControllerTests.cs # src/Umbraco.Tests/Web/Controllers/UsersControllerTests.cs # src/Umbraco.Web/Editors/CodeFileController.cs # src/Umbraco.Web/Editors/ContentController.cs # src/Umbraco.Web/Editors/ContentControllerBase.cs # src/Umbraco.Web/Editors/ContentTypeController.cs # src/Umbraco.Web/Editors/CurrentUserController.cs # src/Umbraco.Web/Editors/DashboardController.cs # src/Umbraco.Web/Editors/EntityController.cs # src/Umbraco.Web/Editors/MacroRenderingController.cs # src/Umbraco.Web/Editors/MacrosController.cs # src/Umbraco.Web/Editors/MediaController.cs # src/Umbraco.Web/Editors/MemberController.cs # src/Umbraco.Web/Editors/RelationTypeController.cs # src/Umbraco.Web/Editors/TinyMceController.cs # src/Umbraco.Web/Editors/UsersController.cs # src/Umbraco.Web/Macros/PublishedContentHashtableConverter.cs # src/Umbraco.Web/Models/Mapping/UserMapDefinition.cs # src/Umbraco.Web/Mvc/RenderRouteHandler.cs # src/Umbraco.Web/PropertyEditors/RichTextEditorPastedImages.cs # src/Umbraco.Web/Runtime/WebInitialComponent.cs # src/Umbraco.Web/Templates/TemplateRenderer.cs
2019-12-24 09:08:47 +01:00
public ModelsBuilderComponent(IModelsBuilderConfig config, IShortStringHelper shortStringHelper, LiveModelsProvider liveModelsProvider, OutOfDateModelsStatus outOfDateModels)
2019-06-24 11:58:36 +02:00
{
_config = config;
_shortStringHelper = shortStringHelper;
_liveModelsProvider = liveModelsProvider;
_outOfDateModels = outOfDateModels;
_shortStringHelper = shortStringHelper;
2019-06-24 11:58:36 +02:00
}
public void Initialize()
{
// always setup the dashboard
// note: UmbracoApiController instances are automatically registered
InstallServerVars();
ContentModelBinder.ModelBindingException += ContentModelBinder_ModelBindingException;
2019-10-29 11:02:18 +11:00
if (_config.Enable)
FileService.SavingTemplate += FileService_SavingTemplate;
2019-06-24 11:58:36 +02:00
if (_config.ModelsMode.IsLiveNotPure())
_liveModelsProvider.Install();
2019-06-24 11:58:36 +02:00
if (_config.FlagOutOfDateModels)
_outOfDateModels.Install();
2019-06-24 11:58:36 +02:00
}
public void Terminate()
{ }
private void InstallServerVars()
{
// register our url - for the backoffice api
ServerVariablesParser.Parsing += (sender, serverVars) =>
{
if (!serverVars.ContainsKey("umbracoUrls"))
throw new ArgumentException("Missing umbracoUrls.");
2019-06-24 11:58:36 +02:00
var umbracoUrlsObject = serverVars["umbracoUrls"];
if (umbracoUrlsObject == null)
throw new ArgumentException("Null umbracoUrls");
2019-06-24 11:58:36 +02:00
if (!(umbracoUrlsObject is Dictionary<string, object> umbracoUrls))
throw new ArgumentException("Invalid umbracoUrls");
2019-06-24 11:58:36 +02:00
if (!serverVars.ContainsKey("umbracoPlugins"))
throw new ArgumentException("Missing umbracoPlugins.");
2019-06-24 11:58:36 +02:00
if (!(serverVars["umbracoPlugins"] is Dictionary<string, object> umbracoPlugins))
throw new ArgumentException("Invalid umbracoPlugins");
2019-06-24 11:58:36 +02:00
if (HttpContext.Current == null) throw new InvalidOperationException("HttpContext is null");
var urlHelper = new UrlHelper(new RequestContext(new HttpContextWrapper(HttpContext.Current), new RouteData()));
umbracoUrls["modelsBuilderBaseUrl"] = urlHelper.GetUmbracoApiServiceBaseUrl<ModelsBuilderDashboardController>(controller => controller.BuildModels());
2019-06-24 11:58:36 +02:00
umbracoPlugins["modelsBuilder"] = GetModelsBuilderSettings();
};
}
private Dictionary<string, object> GetModelsBuilderSettings()
{
var settings = new Dictionary<string, object>
{
2019-10-29 11:02:18 +11:00
{"enabled", _config.Enable}
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>
/// <param name="sender"></param>
/// <param name="e"></param>
private void FileService_SavingTemplate(IFileService sender, Core.Events.SaveEventArgs<Core.Models.ITemplate> e)
{
// don't do anything if the factory is not enabled
// because, no factory = no models (even if generation is enabled)
if (!_config.EnableFactory) return;
// don't do anything if this special key is not found
if (!e.AdditionalData.ContainsKey("CreateTemplateForContentType")) return;
// ensure we have the content type alias
if (!e.AdditionalData.ContainsKey("ContentTypeAlias"))
throw new InvalidOperationException("The additionalData key: ContentTypeAlias was not found");
foreach (var template in e.SavedEntities)
// 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
var alias = e.AdditionalData["ContentTypeAlias"].ToString();
var name = template.Name; // will be the name of the content type since we are creating
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
//var modelNamespaceAlias = ...;
var markup = ViewHelper.GetDefaultFileContent(
modelClassName: className,
modelNamespace: modelNamespace/*,
modelNamespaceAlias: modelNamespaceAlias*/);
//set the template content to the new markup
template.Content = markup;
}
}
private void ContentModelBinder_ModelBindingException(object sender, ContentModelBinder.ModelBindingArgs args)
{
var sourceAttr = args.SourceType.Assembly.GetCustomAttribute<ModelsBuilderAssemblyAttribute>();
var modelAttr = args.ModelType.Assembly.GetCustomAttribute<ModelsBuilderAssemblyAttribute>();
// 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)
return;
// else report, but better not restart (loops?)
args.Message.Append(" The ");
args.Message.Append(sourceAttr == null ? "view model" : "source");
args.Message.Append(" is a ModelsBuilder type, but the ");
args.Message.Append(sourceAttr != null ? "view model" : "source");
args.Message.Append(" is not. The application is in an unstable state and should be restarted.");
return;
}
// both are ModelsBuilder types
var pureSource = sourceAttr.PureLive;
var pureModel = modelAttr.PureLive;
2019-06-24 11:58:36 +02:00
if (sourceAttr.PureLive || modelAttr.PureLive)
if (pureSource == false || pureModel == false)
{
2019-06-24 11:58:36 +02:00
// only one is pure - report, but better not restart (loops?)
args.Message.Append(pureSource
? " The content model is PureLive, but the view model is not."
: " The view model is PureLive, but the content model is not.");
args.Message.Append(" The application is in an unstable state and should be restarted.");
}
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?)
var sourceVersion = args.SourceType.Assembly.GetName().Version;
2019-06-24 11:58:36 +02:00
var modelVersion = args.ModelType.Assembly.GetName().Version;
args.Message.Append(" Both view and content models are PureLive, with ");
args.Message.Append(sourceVersion == modelVersion
? "same version. The application is in an unstable state and should be restarted."
: "different versions. The application is in an unstable state and is going to be restarted.");
args.Restart = sourceVersion != modelVersion;
}
2019-06-24 11:58:36 +02:00
}
}
}