diff --git a/src/Umbraco.Tests/Install/InstallApiControllerTests.cs b/src/Umbraco.Tests/Install/InstallApiControllerTests.cs deleted file mode 100644 index ddc73b3079..0000000000 --- a/src/Umbraco.Tests/Install/InstallApiControllerTests.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using NUnit.Framework; -using Umbraco.Core.Logging; -using Umbraco.Web.Install.Controllers; -using Umbraco.Web.Install.Models; - -namespace Umbraco.Tests.Install -{ - [TestFixture] - public class InstallApiControllerTests - { - - //[Test] - //public void Can_Execute_Step() - //{ - // var step = new InstallSetupStep() - // { - // Name = "Database", - // View = "database", - // ServerOrder = 0, - // RequiresRestart = true, - // ExecuteCallback = model => LogHelper.Info("installing....") - // }; - - // var instruction = JObject.FromObject(new - // { - // dbType = 0, - // server = "localhost", - // databaseName = "test", - // login = "sa", - // password = "test", - // integratedAuth = false, - // connectionString = string.Empty - // }); - - // Assert.DoesNotThrow(() => InstallApiController.ExecuteStep(step, instruction)); - - //} - - } -} diff --git a/src/Umbraco.Tests/Install/InstallHelperTests.cs b/src/Umbraco.Tests/Install/InstallHelperTests.cs new file mode 100644 index 0000000000..8764dd5183 --- /dev/null +++ b/src/Umbraco.Tests/Install/InstallHelperTests.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web; +using Moq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Logging; +using Umbraco.Web; +using Umbraco.Web.Install; +using Umbraco.Web.Install.Controllers; +using Umbraco.Web.Install.InstallSteps; +using Umbraco.Web.Install.Models; + +namespace Umbraco.Tests.Install +{ + [TestFixture] + public class InstallHelperTests + { + + [Test] + public void Get_Steps() + { + var appCtx = new ApplicationContext(CacheHelper.CreateDisabledCacheHelper()); + ApplicationContext.EnsureContext(appCtx, true); + + var umbCtx = UmbracoContext.EnsureContext( + new Mock().Object, + appCtx, + true); + + var helper = new InstallHelper(umbCtx, InstallStatusType.NewInstall); + + var steps = helper.GetSteps().ToArray(); + + var expected = new[] + { + typeof (FilePermissionsStep), typeof (UserStep), typeof(MajorVersion7UpgradeReport), typeof (DatabaseConfigureStep), typeof (DatabaseInstallStep), + typeof (DatabaseUpgradeStep), typeof (StarterKitDownloadStep), typeof (StarterKitInstallStep), typeof (StarterKitCleanupStep), + typeof (SetUmbracoVersionStep) + }; + + Assert.AreEqual(expected.Length, steps.Length); + + for (int i = 0; i < expected.Length; i++) + { + var type = expected[i]; + Assert.AreEqual(type, steps[i].GetType()); + } + } + + [Test] + public void Get_Steps_New_Install() + { + var appCtx = new ApplicationContext(CacheHelper.CreateDisabledCacheHelper()); + ApplicationContext.EnsureContext(appCtx, true); + + var umbCtx = UmbracoContext.EnsureContext( + new Mock().Object, + appCtx, + true); + + var helper = new InstallHelper(umbCtx, InstallStatusType.NewInstall); + + var steps = helper.GetSteps().ToArray(); + + //for new installs 2, don't require execution + Assert.AreEqual(2, steps.Count(x => x.RequiresExecution() == false)); + + } + + [Test] + public void Get_Steps_Upgrade() + { + var appCtx = new ApplicationContext(CacheHelper.CreateDisabledCacheHelper()); + ApplicationContext.EnsureContext(appCtx, true); + + var umbCtx = UmbracoContext.EnsureContext( + new Mock().Object, + appCtx, + true); + + var helper = new InstallHelper(umbCtx, InstallStatusType.Upgrade); + + var steps = helper.GetSteps().ToArray(); + + //for new installs 4, don't require execution + Assert.AreEqual(4, steps.Count(x => x.RequiresExecution() == false)); + + } + + } +} diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 824771333b..a13b05163f 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -169,7 +169,7 @@ - + diff --git a/src/Umbraco.Web/Install/Controllers/InstallApiController.cs b/src/Umbraco.Web/Install/Controllers/InstallApiController.cs index 05658e3fd0..99fe37d05c 100644 --- a/src/Umbraco.Web/Install/Controllers/InstallApiController.cs +++ b/src/Umbraco.Web/Install/Controllers/InstallApiController.cs @@ -48,31 +48,21 @@ namespace Umbraco.Web.Install.Controllers /// public InstallSetup GetSetup() { - var status = new InstallSetup() + var helper = new InstallHelper(UmbracoContext); + + var setup = new InstallSetup() { - Status = GlobalSettings.ConfigurationStatus.IsNullOrWhiteSpace() - ? InstallStatus.NewInstall - : InstallStatus.Upgrade + Status = helper.GetStatus() }; //TODO: Check for user/site token var steps = new List(); - if (status.Status == InstallStatus.NewInstall) - { - //The step order returned here is how they will appear on the front-end - steps.AddRange(InstallHelper.GetSteps(UmbracoContext, status.Status)); - status.Steps = steps; + steps.AddRange(helper.GetSteps()); + setup.Steps = steps; - //TODO: In case someone presses f5 during install, we will attempt to resume, in order to do this?? - } - else - { - //TODO: Add steps for upgrades - } - - return status; + return setup; } /// @@ -117,7 +107,7 @@ namespace Umbraco.Web.Install.Controllers if (stepStatus.Value.IsComplete == false) { JToken instruction = null; - if (step.View.IsNullOrWhiteSpace() == false) + if (step.HasUIElement) { //Since this is a UI instruction, we will extract the model from it if (instructions.Any(x => x.Key == step.Name) == false) @@ -126,13 +116,19 @@ namespace Umbraco.Web.Install.Controllers } instruction = instructions[step.Name]; } - + + //If this step doesn't require execution then continue to the next one. + if (step.RequiresExecution() == false) + { + continue; + } + try { var setupData = ExecuteStep(step, instruction); //update the status - InstallStatusTracker.SetComplete(step.Name, setupData); + InstallStatusTracker.SetComplete(step.Name, setupData.SavedStepData); return Json(new { complete = false, @@ -155,7 +151,7 @@ namespace Umbraco.Web.Install.Controllers return Json(new { complete = true }, HttpStatusCode.OK); } - internal IDictionary ExecuteStep(InstallSetupStep step, JToken instruction) + internal InstallSetupResult ExecuteStep(InstallSetupStep step, JToken instruction) { var model = instruction == null ? null : instruction.ToObject(step.StepType); var genericStepType = typeof(InstallSetupStep<>); @@ -164,7 +160,7 @@ namespace Umbraco.Web.Install.Controllers try { var method = typedStepType.GetMethods().Single(x => x.Name == "Execute"); - return (IDictionary)method.Invoke(step, new object[] { model }); + return (InstallSetupResult)method.Invoke(step, new object[] { model }); } catch (Exception ex) { @@ -172,7 +168,7 @@ namespace Umbraco.Web.Install.Controllers throw; } } - + private HttpResponseMessage Json(object jsonObject, HttpStatusCode status) { var response = Request.CreateResponse(status); diff --git a/src/Umbraco.Web/Install/InstallHelper.cs b/src/Umbraco.Web/Install/InstallHelper.cs index d1885818b3..a31f7c6b97 100644 --- a/src/Umbraco.Web/Install/InstallHelper.cs +++ b/src/Umbraco.Web/Install/InstallHelper.cs @@ -2,66 +2,64 @@ using System.Collections; using System.Collections.Generic; using System.Configuration; +using System.Linq; +using System.Web; using System.Web.Script.Serialization; using System.Web.UI; + +using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Web.Install.InstallSteps; using Umbraco.Web.Install.Models; namespace Umbraco.Web.Install { - internal static class InstallHelper + internal class InstallHelper { + private readonly UmbracoContext _umbContext; + private readonly InstallStatusType _status; - public static IEnumerable GetSteps( - UmbracoContext umbracoContext, - InstallStatus status) + internal InstallHelper(UmbracoContext umbContext) + : this(umbContext, GlobalSettings.ConfigurationStatus.IsNullOrWhiteSpace() + ? InstallStatusType.NewInstall + : InstallStatusType.Upgrade) { - //TODO: Add UserToken step to save our user token with Mother - - var steps = new List(new InstallSetupStep[] - { - new FilePermissionsStep() - { - ServerOrder = 0, - }, - new UserStep(umbracoContext.Application, status) - { - ServerOrder = 4, - }, - new DatabaseConfigureStep(umbracoContext.Application) - { - ServerOrder = 1, - }, - new DatabaseInstallStep(umbracoContext.Application) - { - ServerOrder = 2, - }, - new DatabaseUpgradeStep(umbracoContext.Application) - { - ServerOrder = 3, - }, - new StarterKitDownloadStep(status) - { - ServerOrder = 5, - }, - new StarterKitInstallStep(status, umbracoContext.Application, umbracoContext.HttpContext) - { - ServerOrder = 6, - }, - new StarterKitCleanupStep(status) - { - ServerOrder = 7, - }, - new SetUmbracoVersionStep(umbracoContext.Application, umbracoContext.HttpContext) - { - ServerOrder = 8 - } - }); - - return steps; } + internal InstallHelper(UmbracoContext umbContext, InstallStatusType status) + { + _umbContext = umbContext; + _status = status; + } + + public InstallStatusType GetStatus() + { + return _status; + } + + /// + /// Get the installer steps + /// + /// + /// + /// The step order returned here is how they will appear on the front-end + /// + public IEnumerable GetSteps() + { + return new List + { + new FilePermissionsStep(), + new UserStep(_umbContext.Application, _status), + new DatabaseConfigureStep(_umbContext.Application), + new DatabaseInstallStep(_umbContext.Application), + new DatabaseUpgradeStep(_umbContext.Application, _status), + new StarterKitDownloadStep(_status), + new StarterKitInstallStep(_status, _umbContext.Application, _umbContext.HttpContext), + new StarterKitCleanupStep(_status), + new SetUmbracoVersionStep(_umbContext.Application, _umbContext.HttpContext), + }; + } + //public static bool IsNewInstall //{ // get diff --git a/src/Umbraco.Web/Install/InstallSteps/DatabaseConfigureStep.cs b/src/Umbraco.Web/Install/InstallSteps/DatabaseConfigureStep.cs index b5bbbe3a91..90c2384485 100644 --- a/src/Umbraco.Web/Install/InstallSteps/DatabaseConfigureStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/DatabaseConfigureStep.cs @@ -13,7 +13,7 @@ using Umbraco.Web.Install.Models; namespace Umbraco.Web.Install.InstallSteps { - [InstallSetupStep("DatabaseConfigure", "database")] + [InstallSetupStep("DatabaseConfigure", "database", 3)] internal class DatabaseConfigureStep : InstallSetupStep { private readonly ApplicationContext _applicationContext; @@ -23,7 +23,7 @@ namespace Umbraco.Web.Install.InstallSteps _applicationContext = applicationContext; } - public override IDictionary Execute(DatabaseModel database) + public override InstallSetupResult Execute(DatabaseModel database) { if (CheckConnection(database) == false) { @@ -93,6 +93,12 @@ namespace Umbraco.Web.Install.InstallSteps get { return ShouldDisplayView() ? base.View : ""; } } + public override bool RequiresExecution() + { + //TODO: We need to determine if we should run this based on whether the conn string is configured already + return true; + } + private bool ShouldDisplayView() { //If the connection string is already present in web.config we don't need to show the settings page and we jump to installing/upgrading. diff --git a/src/Umbraco.Web/Install/InstallSteps/DatabaseInstallStep.cs b/src/Umbraco.Web/Install/InstallSteps/DatabaseInstallStep.cs index a901bba842..2c1f50b1b8 100644 --- a/src/Umbraco.Web/Install/InstallSteps/DatabaseInstallStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/DatabaseInstallStep.cs @@ -8,7 +8,7 @@ using Umbraco.Web.Install.Models; namespace Umbraco.Web.Install.InstallSteps { - [InstallSetupStep("DatabaseInstall", "")] + [InstallSetupStep("DatabaseInstall", 4)] internal class DatabaseInstallStep : InstallSetupStep { private readonly ApplicationContext _applicationContext; @@ -18,16 +18,16 @@ namespace Umbraco.Web.Install.InstallSteps _applicationContext = applicationContext; } - public override IDictionary Execute(object model) + public override InstallSetupResult Execute(object model) { var result = _applicationContext.DatabaseContext.CreateDatabaseSchemaAndData(); if (result.RequiresUpgrade == false) { HandleConnectionStrings(); - return new Dictionary + return new InstallSetupResult(new Dictionary { {"upgrade", true} - }; + }); } return null; } @@ -46,5 +46,10 @@ namespace Umbraco.Web.Install.InstallSteps throw ex; } } + + public override bool RequiresExecution() + { + return true; + } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs b/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs index 83d3279a11..01d5f13b1c 100644 --- a/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs @@ -7,18 +7,22 @@ using Umbraco.Web.Install.Models; namespace Umbraco.Web.Install.InstallSteps { - [InstallSetupStep("DatabaseUpgrade", "")] + [InstallSetupStep("DatabaseUpgrade", 5)] internal class DatabaseUpgradeStep : InstallSetupStep { private readonly ApplicationContext _applicationContext; + private readonly InstallStatusType _status; - public DatabaseUpgradeStep(ApplicationContext applicationContext) + public DatabaseUpgradeStep(ApplicationContext applicationContext, InstallStatusType status) { _applicationContext = applicationContext; + _status = status; } - public override IDictionary Execute(object model) + public override InstallSetupResult Execute(object model) { + if (_status == InstallStatusType.NewInstall) return null; + var installSteps = InstallStatusTracker.GetStatus(); //this step relies on the preious one completed - because it has stored some information we need if (installSteps.Any(x => x.Key == "DatabaseConfigure") == false) @@ -40,5 +44,9 @@ namespace Umbraco.Web.Install.InstallSteps return null; } + public override bool RequiresExecution() + { + return _status != InstallStatusType.NewInstall; + } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Install/InstallSteps/FilePermissionsStep.cs b/src/Umbraco.Web/Install/InstallSteps/FilePermissionsStep.cs index 7babeaa2f8..9c74c30eeb 100644 --- a/src/Umbraco.Web/Install/InstallSteps/FilePermissionsStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/FilePermissionsStep.cs @@ -8,10 +8,10 @@ using Umbraco.Web.Install.Models; namespace Umbraco.Web.Install.InstallSteps { - [InstallSetupStep("Permissions", "")] + [InstallSetupStep("Permissions", 0)] internal class FilePermissionsStep : InstallSetupStep { - public override IDictionary Execute(object model) + public override InstallSetupResult Execute(object model) { //first validate file permissions var permissionsOk = true; @@ -124,5 +124,9 @@ namespace Umbraco.Web.Install.InstallSteps } } + public override bool RequiresExecution() + { + return true; + } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Install/InstallSteps/MajorVersion7UpgradeReport.cs b/src/Umbraco.Web/Install/InstallSteps/MajorVersion7UpgradeReport.cs new file mode 100644 index 0000000000..2d368d8be8 --- /dev/null +++ b/src/Umbraco.Web/Install/InstallSteps/MajorVersion7UpgradeReport.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using Umbraco.Core; +using Umbraco.Core.Configuration; +using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.SqlSyntax; +using Umbraco.Core.PropertyEditors; +using Umbraco.Web.Install.Models; + +namespace Umbraco.Web.Install.InstallSteps +{ + [InstallSetupStep("MajorVersion7UpgradeReport", 2)] + internal class MajorVersion7UpgradeReport : InstallSetupStep + { + private readonly ApplicationContext _applicationContext; + private readonly InstallStatusType _status; + + public MajorVersion7UpgradeReport(ApplicationContext applicationContext, InstallStatusType status) + { + _applicationContext = applicationContext; + _status = status; + } + + public override InstallSetupResult Execute(object model) + { + if (_status == InstallStatusType.NewInstall) + { + return null; + } + //we cannot run this step if the db is not configured. + if (_applicationContext.DatabaseContext.IsDatabaseConfigured == false) + { + return null; + } + + return new InstallSetupResult("version7upgradereport", CreateReport()); + } + + public override bool RequiresExecution() + { + if (_status == InstallStatusType.NewInstall) + { + return false; + } + + //we cannot run this step if the db is not configured. + if (_applicationContext.DatabaseContext.IsDatabaseConfigured == false) + { + return false; + } + + var result = _applicationContext.DatabaseContext.ValidateDatabaseSchema(); + var determinedVersion = result.DetermineInstalledVersion(); + if ((string.IsNullOrWhiteSpace(GlobalSettings.ConfigurationStatus) == false || determinedVersion.Equals(new Version(0, 0, 0)) == false) + && UmbracoVersion.Current.Major > determinedVersion.Major) + { + //it's an upgrade to a major version so we're gonna show this step + return true; + } + return false; + } + + private IEnumerable> CreateReport() + { + var errorReport = new List>(); + + var sql = new Sql(); + sql + .Select( + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumn("cmsDataType", "controlId"), + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumn("umbracoNode", "text")) + .From(SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName("cmsDataType")) + .InnerJoin(SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName("umbracoNode")) + .On( + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumn("cmsDataType", "nodeId") + " = " + + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumn("umbracoNode", "id")); + + var list = _applicationContext.DatabaseContext.Database.Fetch(sql); + foreach (var item in list) + { + Guid legacyId = item.controlId; + //check for a map entry + var alias = LegacyPropertyEditorIdToAliasConverter.GetAliasFromLegacyId(legacyId); + if (alias != null) + { + //check that the new property editor exists with that alias + var editor = PropertyEditorResolver.Current.GetByAlias(alias); + if (editor == null) + { + errorReport.Add(new Tuple(false, string.Format("Property Editor with ID '{0}' (assigned to Data Type '{1}') has a valid GUID -> Alias map but no property editor was found. It will be replaced with a Readonly/Label property editor.", item.controlId, item.text))); + } + } + else + { + errorReport.Add(new Tuple(false, string.Format("Property Editor with ID '{0}' (assigned to Data Type '{1}') does not have a valid GUID -> Alias map. It will be replaced with a Readonly/Label property editor.", item.controlId, item.text))); + } + } + + return errorReport; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Install/InstallSteps/SetUmbracoVersionStep.cs b/src/Umbraco.Web/Install/InstallSteps/SetUmbracoVersionStep.cs index 611a14be1b..6708f21e68 100644 --- a/src/Umbraco.Web/Install/InstallSteps/SetUmbracoVersionStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/SetUmbracoVersionStep.cs @@ -10,7 +10,7 @@ using GlobalSettings = umbraco.GlobalSettings; namespace Umbraco.Web.Install.InstallSteps { - [InstallSetupStep("UmbracoVersion", "")] + [InstallSetupStep("UmbracoVersion", 9)] internal class SetUmbracoVersionStep : InstallSetupStep { private readonly ApplicationContext _applicationContext; @@ -22,7 +22,7 @@ namespace Umbraco.Web.Install.InstallSteps _httpContext = httpContext; } - public override IDictionary Execute(object model) + public override InstallSetupResult Execute(object model) { // Update configurationStatus try @@ -48,5 +48,10 @@ namespace Umbraco.Web.Install.InstallSteps //security.ClearCurrentLogin(); return null; } + + public override bool RequiresExecution() + { + return true; + } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitCleanupStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitCleanupStep.cs index 9766fda371..3ea1059945 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitCleanupStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitCleanupStep.cs @@ -7,19 +7,19 @@ using Umbraco.Web.Install.Models; namespace Umbraco.Web.Install.InstallSteps { - [InstallSetupStep("StarterKitCleanup", "")] + [InstallSetupStep("StarterKitCleanup", 8)] internal class StarterKitCleanupStep : InstallSetupStep { - private readonly InstallStatus _status; + private readonly InstallStatusType _status; - public StarterKitCleanupStep(InstallStatus status) + public StarterKitCleanupStep(InstallStatusType status) { _status = status; } - public override IDictionary Execute(object model) + public override InstallSetupResult Execute(object model) { - if (_status != InstallStatus.NewInstall) return null; + if (_status != InstallStatusType.NewInstall) return null; var installSteps = InstallStatusTracker.GetStatus(); //this step relies on the preious one completed - because it has stored some information we need @@ -46,5 +46,9 @@ namespace Umbraco.Web.Install.InstallSteps library.RefreshContent(); } + public override bool RequiresExecution() + { + return _status == InstallStatusType.NewInstall; + } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs index 58891e0992..f7fb5f782a 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitDownloadStep.cs @@ -6,29 +6,29 @@ using Umbraco.Web.Install.Models; namespace Umbraco.Web.Install.InstallSteps { - [InstallSetupStep("StarterKitDownload", "starterKit")] + [InstallSetupStep("StarterKitDownload", "starterKit", 6)] internal class StarterKitDownloadStep : InstallSetupStep { - private readonly InstallStatus _status; + private readonly InstallStatusType _status; - public StarterKitDownloadStep(InstallStatus status) + public StarterKitDownloadStep(InstallStatusType status) { _status = status; } private const string RepoGuid = "65194810-1f85-11dd-bd0b-0800200c9a66"; - public override IDictionary Execute(Guid starterKitId) + public override InstallSetupResult Execute(Guid starterKitId) { - if (_status != InstallStatus.NewInstall) return null; + if (_status != InstallStatusType.NewInstall) return null; var result = DownloadPackageFiles(starterKitId); - return new Dictionary + return new InstallSetupResult(new Dictionary { {"manifestId", result.Item2}, {"packageFile", result.Item1} - }; + }); } private Tuple DownloadPackageFiles(Guid kitGuid) @@ -62,5 +62,9 @@ namespace Umbraco.Web.Install.InstallSteps } + public override bool RequiresExecution() + { + return _status == InstallStatusType.NewInstall; + } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs b/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs index 8deda42115..9bf3661335 100644 --- a/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/StarterKitInstallStep.cs @@ -7,14 +7,14 @@ using Umbraco.Web.Install.Models; namespace Umbraco.Web.Install.InstallSteps { - [InstallSetupStep("StarterKitInstall", "")] + [InstallSetupStep("StarterKitInstall", 7)] internal class StarterKitInstallStep : InstallSetupStep { - private readonly InstallStatus _status; + private readonly InstallStatusType _status; private readonly ApplicationContext _applicationContext; private readonly HttpContextBase _httContext; - public StarterKitInstallStep(InstallStatus status, ApplicationContext applicationContext, HttpContextBase httContext) + public StarterKitInstallStep(InstallStatusType status, ApplicationContext applicationContext, HttpContextBase httContext) { _status = status; _applicationContext = applicationContext; @@ -22,9 +22,9 @@ namespace Umbraco.Web.Install.InstallSteps } - public override IDictionary Execute(object model) + public override InstallSetupResult Execute(object model) { - if (_status != InstallStatus.NewInstall) return null; + if (_status != InstallStatusType.NewInstall) return null; var installSteps = InstallStatusTracker.GetStatus(); //this step relies on the preious one completed - because it has stored some information we need @@ -51,5 +51,9 @@ namespace Umbraco.Web.Install.InstallSteps installer.InstallBusinessLogic(manifestId, packageFile); } + public override bool RequiresExecution() + { + return _status == InstallStatusType.NewInstall; + } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Install/InstallSteps/UserStep.cs b/src/Umbraco.Web/Install/InstallSteps/UserStep.cs index f63dd63a08..a72d2dbf50 100644 --- a/src/Umbraco.Web/Install/InstallSteps/UserStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/UserStep.cs @@ -8,13 +8,13 @@ using Umbraco.Web.Install.Models; namespace Umbraco.Web.Install.InstallSteps { - [InstallSetupStep("User", "user")] + [InstallSetupStep("User", "user", 4)] internal class UserStep : InstallSetupStep { private readonly ApplicationContext _applicationContext; - private readonly InstallStatus _status; + private readonly InstallStatusType _status; - public UserStep(ApplicationContext applicationContext, InstallStatus status) + public UserStep(ApplicationContext applicationContext, InstallStatusType status) { _applicationContext = applicationContext; _status = status; @@ -33,7 +33,7 @@ namespace Umbraco.Web.Install.InstallSteps } } - public override IDictionary Execute(UserModel user) + public override InstallSetupResult Execute(UserModel user) { var admin = _applicationContext.Services.UserService.GetUserById(0); if (admin == null) @@ -71,7 +71,12 @@ namespace Umbraco.Web.Install.InstallSteps public override string View { - get { return _status == InstallStatus.NewInstall ? base.View : string.Empty; } + get { return _status == InstallStatusType.NewInstall ? base.View : string.Empty; } + } + + public override bool RequiresExecution() + { + return _status == InstallStatusType.NewInstall; } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Install/Models/InstallSetup.cs b/src/Umbraco.Web/Install/Models/InstallSetup.cs index 62a1757c24..e6ed557bf9 100644 --- a/src/Umbraco.Web/Install/Models/InstallSetup.cs +++ b/src/Umbraco.Web/Install/Models/InstallSetup.cs @@ -3,6 +3,7 @@ using System.Runtime.Serialization; namespace Umbraco.Web.Install.Models { + /// /// Model containing all the install steps for setting up the UI /// @@ -15,7 +16,7 @@ namespace Umbraco.Web.Install.Models } [DataMember(Name = "status")] - public InstallStatus Status { get; set; } + public InstallStatusType Status { get; set; } [DataMember(Name = "steps")] public IEnumerable Steps { get; set; } diff --git a/src/Umbraco.Web/Install/Models/InstallSetupResult.cs b/src/Umbraco.Web/Install/Models/InstallSetupResult.cs new file mode 100644 index 0000000000..e71e987894 --- /dev/null +++ b/src/Umbraco.Web/Install/Models/InstallSetupResult.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; + +namespace Umbraco.Web.Install.Models +{ + public class InstallSetupResult + { + public InstallSetupResult() + { + + } + + public InstallSetupResult(IDictionary savedStepData, string view, object viewModel = null) + { + ViewModel = viewModel; + SavedStepData = savedStepData; + View = view; + } + + public InstallSetupResult(IDictionary savedStepData) + { + SavedStepData = savedStepData; + } + + public InstallSetupResult(string view, object viewModel = null) + { + ViewModel = viewModel; + View = view; + } + + /// + /// Data that is persisted to the installation file which can be used from other installation steps + /// + public IDictionary SavedStepData { get; private set; } + + /// + /// The UI view to show when this step executes, by default no views are shown for the completion of a step unless explicitly specified. + /// + public string View { get; private set; } + + /// + /// The view model to return to the UI if this step is returning a view (optional) + /// + public object ViewModel { get; private set; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Install/Models/InstallSetupStep.cs b/src/Umbraco.Web/Install/Models/InstallSetupStep.cs index 5349ccbc50..f252598950 100644 --- a/src/Umbraco.Web/Install/Models/InstallSetupStep.cs +++ b/src/Umbraco.Web/Install/Models/InstallSetupStep.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Runtime.Serialization; using Umbraco.Core; @@ -11,18 +10,6 @@ namespace Umbraco.Web.Install.Models [DataContract(Name = "step", Namespace = "")] public abstract class InstallSetupStep : InstallSetupStep { - protected InstallSetupStep() - { - var att = GetType().GetCustomAttribute(false); - if (att == null) - { - throw new InvalidOperationException("Each step must be attributed"); - } - _attribute = att; - } - - private readonly InstallSetupStepAttribute _attribute; - /// /// Defines the step model type on the server side so we can bind it /// @@ -32,18 +19,12 @@ namespace Umbraco.Web.Install.Models get { return typeof(T); } } - public abstract IDictionary Execute(T model); - - [IgnoreDataMember] - public bool HasUIElement - { - get { return View.IsNullOrWhiteSpace() == false; } - } - - public override string View - { - get { return _attribute.View; } - } + /// + /// The step execution method + /// + /// + /// + public abstract InstallSetupResult Execute(T model); } [DataContract(Name = "step", Namespace = "")] @@ -58,6 +39,7 @@ namespace Umbraco.Web.Install.Models } Name = att.Name; View = att.View; + ServerOrder = att.ServerOrder; } [DataMember(Name = "name")] @@ -65,19 +47,31 @@ namespace Umbraco.Web.Install.Models [DataMember(Name = "view")] public virtual string View { get; private set; } + + /// + /// Determines if this step needs to execute given it's ctor arguments + /// + /// + public abstract bool RequiresExecution(); /// /// Defines what order this step needs to execute on the server side since the /// steps might be shown out of order on the front-end /// [IgnoreDataMember] - public int ServerOrder { get; set; } + public int ServerOrder { get; private set; } /// /// Defines the step model type on the server side so we can bind it /// [IgnoreDataMember] public abstract Type StepType { get; } + + [IgnoreDataMember] + public bool HasUIElement + { + get { return View.IsNullOrWhiteSpace() == false; } + } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Install/Models/InstallSetupStepAttribute.cs b/src/Umbraco.Web/Install/Models/InstallSetupStepAttribute.cs index e14eece2b3..e6b62d7f26 100644 --- a/src/Umbraco.Web/Install/Models/InstallSetupStepAttribute.cs +++ b/src/Umbraco.Web/Install/Models/InstallSetupStepAttribute.cs @@ -4,13 +4,22 @@ namespace Umbraco.Web.Install.Models { public sealed class InstallSetupStepAttribute : Attribute { - public InstallSetupStepAttribute(string name, string view) + public InstallSetupStepAttribute(string name, string view, int serverOrder) { Name = name; View = view; + ServerOrder = serverOrder; + } + + public InstallSetupStepAttribute(string name, int serverOrder) + { + Name = name; + View = string.Empty; + ServerOrder = serverOrder; } public string Name { get; private set; } public string View { get; private set; } + public int ServerOrder { get; private set; } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Install/Models/InstallStatus.cs b/src/Umbraco.Web/Install/Models/InstallStatusType.cs similarity index 94% rename from src/Umbraco.Web/Install/Models/InstallStatus.cs rename to src/Umbraco.Web/Install/Models/InstallStatusType.cs index 4512c06da2..727db4028b 100644 --- a/src/Umbraco.Web/Install/Models/InstallStatus.cs +++ b/src/Umbraco.Web/Install/Models/InstallStatusType.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; namespace Umbraco.Web.Install.Models { - public enum InstallStatus + public enum InstallStatusType { NewInstall, Upgrade, @@ -23,4 +23,5 @@ namespace Umbraco.Web.Install.Models ///// //InProgress } + } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 62d5c21188..29cf45debe 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -308,6 +308,7 @@ + @@ -316,6 +317,7 @@ + @@ -324,7 +326,7 @@ - + diff --git a/src/Umbraco.Web/UmbracoContext.cs b/src/Umbraco.Web/UmbracoContext.cs index 96c52f7cb4..f8a29d2a06 100644 --- a/src/Umbraco.Web/UmbracoContext.cs +++ b/src/Umbraco.Web/UmbracoContext.cs @@ -216,7 +216,7 @@ namespace Umbraco.Web IPublishedCaches publishedCaches, WebSecurity webSecurity, bool? preview = null) - : this(httpContext, applicationContext, new Lazy(() => publishedCaches), preview) + : this(httpContext, applicationContext, new Lazy(() => publishedCaches), webSecurity, preview) { } @@ -226,11 +226,13 @@ namespace Umbraco.Web /// /// /// The published caches. + /// /// An optional value overriding detection of preview mode. internal UmbracoContext( HttpContextBase httpContext, ApplicationContext applicationContext, Lazy publishedCaches, + WebSecurity webSecurity, bool? preview = null) { //This ensures the dispose method is called when the request terminates, though