Updates the RequiresExecution logic so we can skip steps based on some user input (i.e. skip the starter kit installation). Fixes the start kit js stuff to update the model correctly and continue. Fixes the error view to restart - it cannot just go back because there might not be a view there.
This commit is contained in:
@@ -40,7 +40,7 @@ namespace Umbraco.Tests.Install
|
||||
|
||||
var expected = new[]
|
||||
{
|
||||
typeof (FilePermissionsStep), typeof (UserStep), typeof(MajorVersion7UpgradeReport), typeof (DatabaseConfigureStep), typeof (DatabaseInstallStep),
|
||||
typeof (FilePermissionsStep), typeof (NewInstallStep), typeof(MajorVersion7UpgradeReport), typeof (DatabaseConfigureStep), typeof (DatabaseInstallStep),
|
||||
typeof (DatabaseUpgradeStep), typeof (StarterKitDownloadStep), typeof (StarterKitInstallStep), typeof (StarterKitCleanupStep),
|
||||
typeof (SetUmbracoVersionStep)
|
||||
};
|
||||
|
||||
@@ -20,4 +20,8 @@ angular.module("umbraco.install").controller("Umbraco.InstallerController",
|
||||
$scope.gotoStep = function(step){
|
||||
installerService.gotoNamedStep(step);
|
||||
};
|
||||
|
||||
$scope.restart = function () {
|
||||
installerService.gotoStep(0);
|
||||
};
|
||||
});
|
||||
|
||||
@@ -89,20 +89,20 @@ angular.module("umbraco.install").factory('installerService', function($q, $time
|
||||
},
|
||||
|
||||
gotoNamedStep : function(stepName){
|
||||
var step = _.find(service.status.steps, function(s, index){
|
||||
if (s.view && s.name === stepName) {
|
||||
service.status.index = index;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
step.view = resolveView(step.view);
|
||||
if(!step.model){
|
||||
step.model = {};
|
||||
var step = _.find(service.status.steps, function(s, index){
|
||||
if (s.view && s.name === stepName) {
|
||||
service.status.index = index;
|
||||
return true;
|
||||
}
|
||||
service.retrieveCurrentStep();
|
||||
service.status.current = step;
|
||||
return false;
|
||||
});
|
||||
|
||||
step.view = resolveView(step.view);
|
||||
if(!step.model){
|
||||
step.model = {};
|
||||
}
|
||||
service.retrieveCurrentStep();
|
||||
service.status.current = step;
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<div>
|
||||
<h1>Continue Umbraco Installation</h1>
|
||||
<p>
|
||||
You see this screen because your Umbraco installation did not complete correctly.
|
||||
</p>
|
||||
<p>
|
||||
Simply click <strong>continue</strong> below to be guided through the rest of the installation process.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<button class="btn btn-success" ng-click="install()">Continue</button>
|
||||
</p>
|
||||
</div>
|
||||
@@ -1,7 +1,9 @@
|
||||
<div class="error">
|
||||
<h1>Error during installation</h1>
|
||||
<h1>Error during installation</h1>
|
||||
|
||||
<p class="message">{{installer.current.model.message}}</p>
|
||||
<p class="message">{{installer.current.model.message}}</p>
|
||||
|
||||
<button class="btn btn-success" ng-click="gotoStep(installer.current.model.step)">Go back</button>
|
||||
<p><small>See log for full details</small></p>
|
||||
|
||||
<button class="btn btn-success" ng-click="restart()">Go back</button>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,8 @@ angular.module("umbraco.install").controller("Umbraco.Installer.PackagesControll
|
||||
$scope.packages = response.data;
|
||||
});
|
||||
|
||||
$scope.setPackageAndContinue = function (pck) {
|
||||
$scope.setPackageAndContinue = function (pckId) {
|
||||
installerService.status.current.model = pckId;
|
||||
installerService.forward();
|
||||
};
|
||||
|
||||
|
||||
@@ -6,14 +6,15 @@
|
||||
and simple foundation to build on top of.
|
||||
</p>
|
||||
|
||||
<ul class="thumbnails">
|
||||
<li class="span3" ng-repeat="package in packages">
|
||||
<a href ng-click="installer.current.model = package.id; install()" class="thumbnail">
|
||||
<img ng-src="http://our.umbraco.org{{package.thumbnail}}" alt="{{package.name}}">
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="thumbnails">
|
||||
<li class="span3" ng-repeat="pck in packages">
|
||||
<a href ng-click="setPackageAndContinue(pck.id)" class="thumbnail">
|
||||
<img ng-src="http://our.umbraco.org{{pck.thumbnail}}" alt="{{pck.name}}">
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<a href ng-click="install()" class="btn btn-link">No thanks, I do not want to install a starter website</a>
|
||||
<a href ng-click="setPackageAndContinue('00000000-0000-0000-0000-000000000000')" class="btn btn-link">
|
||||
No thanks, I do not want to install a starter website
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
it is completely harmless and will simply ensure your website is kept as fast, secure and uptodate as possible.
|
||||
</p>
|
||||
<p>
|
||||
Simply click <strong>continue</strong> below to be guided through the rest of the upgrade</p>
|
||||
Simply click <strong>continue</strong> below to be guided through the rest of the upgrade
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -10,7 +10,7 @@ NOTES:
|
||||
* Compression/Combination/Minification is not enabled unless debug="false" is specified on the 'compiliation' element in the web.config
|
||||
* A new version will invalidate both client and server cache and create new persisted files
|
||||
-->
|
||||
<clientDependency version="1678677019" fileDependencyExtensions=".js,.css" loggerType="Umbraco.Web.UI.CdfLogger, umbraco">
|
||||
<clientDependency version="394389720" fileDependencyExtensions=".js,.css" loggerType="Umbraco.Web.UI.CdfLogger, umbraco">
|
||||
|
||||
<!--
|
||||
This section is used for Web Forms only, the enableCompositeFiles="true" is optional and by default is set to true.
|
||||
|
||||
@@ -135,9 +135,9 @@ namespace Umbraco.Web.Install.Controllers
|
||||
{
|
||||
instruction = installModel.Instructions[step.Name];
|
||||
}
|
||||
|
||||
|
||||
//If this step doesn't require execution then continue to the next one, this is just a fail-safe check.
|
||||
if (step.RequiresExecution() == false)
|
||||
if (StepRequiresExecution(step, instruction) == false)
|
||||
{
|
||||
//set this as complete and continue
|
||||
InstallStatusTracker.SetComplete(installModel.InstallId, stepStatus.Name, null);
|
||||
@@ -152,7 +152,7 @@ namespace Umbraco.Web.Install.Controllers
|
||||
InstallStatusTracker.SetComplete(installModel.InstallId, step.Name, setupData != null ? setupData.SavedStepData : null);
|
||||
|
||||
//Determine's the next step in the queue and dequeue's any items that don't need to execute
|
||||
var nextStep = IterateNextRequiredStep(step, queue, installModel.InstallId);
|
||||
var nextStep = IterateNextRequiredStep(step, queue, installModel.InstallId, installModel);
|
||||
|
||||
//check if there's a custom view to return for this step
|
||||
if (setupData != null && setupData.View.IsNullOrWhiteSpace() == false)
|
||||
@@ -164,6 +164,9 @@ namespace Umbraco.Web.Install.Controllers
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
LogHelper.Error<InstallApiController>("An error occurred during installation step " + step.Name, ex);
|
||||
|
||||
if (ex is TargetInvocationException && ex.InnerException != null)
|
||||
{
|
||||
ex = ex.InnerException;
|
||||
@@ -200,23 +203,36 @@ namespace Umbraco.Web.Install.Controllers
|
||||
/// <param name="current"></param>
|
||||
/// <param name="queue"></param>
|
||||
/// <param name="installId"></param>
|
||||
/// <param name="installModel"></param>
|
||||
/// <returns></returns>
|
||||
private string IterateNextRequiredStep(InstallSetupStep current, Queue<InstallTrackingItem> queue, Guid installId)
|
||||
private string IterateNextRequiredStep(InstallSetupStep current, Queue<InstallTrackingItem> queue, Guid installId, InstallInstructions installModel)
|
||||
{
|
||||
if (queue.Count > 0)
|
||||
{
|
||||
var next = queue.Peek();
|
||||
var step = InstallHelper.GetAllSteps().Single(x => x.Name == next.Name);
|
||||
|
||||
|
||||
//If the current step restarts the app pool then we must simply return the next one in the queue,
|
||||
// we cannot peek ahead as the next step might rely on the app restart and therefore RequiresExecution
|
||||
// will rely on that too.
|
||||
//Otherwise if it requires execution then of course return it.
|
||||
if (current.PerformsAppRestart || step.RequiresExecution())
|
||||
// will rely on that too.
|
||||
if (current.PerformsAppRestart)
|
||||
{
|
||||
return step.Name;
|
||||
}
|
||||
|
||||
|
||||
JToken instruction = null;
|
||||
//If this step has any instructions then extract them
|
||||
if (installModel.Instructions.Any(x => x.Key == step.Name))
|
||||
{
|
||||
instruction = installModel.Instructions[step.Name];
|
||||
}
|
||||
|
||||
//if the step requires execution then return it's name
|
||||
if (StepRequiresExecution(step, instruction))
|
||||
{
|
||||
return step.Name;
|
||||
}
|
||||
|
||||
//this step no longer requires execution, this could be due to a new config change during installation,
|
||||
// so we'll dequeue this one from the queue and recurse
|
||||
queue.Dequeue();
|
||||
@@ -225,13 +241,37 @@ namespace Umbraco.Web.Install.Controllers
|
||||
InstallStatusTracker.SetComplete(installId, step.Name, null);
|
||||
|
||||
//recurse
|
||||
return IterateNextRequiredStep(step, queue, installId);
|
||||
return IterateNextRequiredStep(step, queue, installId, installModel);
|
||||
}
|
||||
|
||||
//there is no more steps
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the step requires execution
|
||||
/// </summary>
|
||||
/// <param name="step"></param>
|
||||
/// <param name="instruction"></param>
|
||||
/// <returns></returns>
|
||||
internal bool StepRequiresExecution(InstallSetupStep step, JToken instruction)
|
||||
{
|
||||
var model = instruction == null ? null : instruction.ToObject(step.StepType);
|
||||
var genericStepType = typeof(InstallSetupStep<>);
|
||||
Type[] typeArgs = { step.StepType };
|
||||
var typedStepType = genericStepType.MakeGenericType(typeArgs);
|
||||
try
|
||||
{
|
||||
var method = typedStepType.GetMethods().Single(x => x.Name == "RequiresExecution");
|
||||
return (bool)method.Invoke(step, new object[] { model });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<InstallApiController>("Checking if step requires execution (" + step.Name + ") failed.", ex);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
internal InstallSetupResult ExecuteStep(InstallSetupStep step, JToken instruction)
|
||||
{
|
||||
using (DisposableTimer.TraceDuration<InstallApiController>("Executing installation step: " + step.Name, "Step completed"))
|
||||
|
||||
@@ -37,8 +37,8 @@ namespace Umbraco.Web.Install
|
||||
{
|
||||
return new List<InstallSetupStep>
|
||||
{
|
||||
new UserStep(_umbContext.Application),
|
||||
new Upgrade(),
|
||||
new NewInstallStep(_umbContext.Application),
|
||||
new UpgradeStep(),
|
||||
new FilePermissionsStep(),
|
||||
new MajorVersion7UpgradeReport(_umbContext.Application),
|
||||
new DatabaseConfigureStep(_umbContext.Application),
|
||||
@@ -62,13 +62,13 @@ namespace Umbraco.Web.Install
|
||||
|
||||
public InstallationType GetInstallationType()
|
||||
{
|
||||
return _installationType ?? (_installationType = IsNewInstall ? InstallationType.NewInstall : InstallationType.Upgrade).Value;
|
||||
return _installationType ?? (_installationType = IsBrandNewInstall ? InstallationType.NewInstall : InstallationType.Upgrade).Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if this is a brand new install meaning that there is no configured version and there is no configured database connection
|
||||
/// </summary>
|
||||
private bool IsNewInstall
|
||||
private bool IsBrandNewInstall
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -79,6 +79,34 @@ namespace Umbraco.Web.Install
|
||||
//no version or conn string configured, must be a brand new install
|
||||
return true;
|
||||
}
|
||||
|
||||
//now we have to check if this is really a new install, the db might be configured and might contain data
|
||||
|
||||
if (_umbContext.Application.DatabaseContext.IsConnectionStringConfigured(databaseSettings) == false
|
||||
|| _umbContext.Application.DatabaseContext.IsDatabaseConfigured == false)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//check if we have the default user configured already
|
||||
var result = _umbContext.Application.DatabaseContext.Database.ExecuteScalar<int>(
|
||||
"SELECT COUNT(*) FROM umbracoUser WHERE id=0 AND userPassword='default'");
|
||||
if (result == 1)
|
||||
{
|
||||
//the user has not been configured
|
||||
return true;
|
||||
}
|
||||
|
||||
// //check if there are any content types configured, if there isn't then we will consider this a new install
|
||||
// result = _umbContext.Application.DatabaseContext.Database.ExecuteScalar<int>(
|
||||
// @"SELECT COUNT(*) FROM cmsContentType
|
||||
// INNER JOIN umbracoNode ON cmsContentType.nodeId = umbracoNode.id
|
||||
// WHERE umbracoNode.nodeObjectType = @contentType", new {contentType = Constants.ObjectTypes.DocumentType});
|
||||
// if (result == 0)
|
||||
// {
|
||||
// //no content types have been created
|
||||
// return true;
|
||||
// }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace Umbraco.Web.Install.InstallSteps
|
||||
get { return ShouldDisplayView() ? base.View : ""; }
|
||||
}
|
||||
|
||||
public override bool RequiresExecution()
|
||||
public override bool RequiresExecution(DatabaseModel model)
|
||||
{
|
||||
return ShouldDisplayView();
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace Umbraco.Web.Install.InstallSteps
|
||||
}
|
||||
}
|
||||
|
||||
public override bool RequiresExecution()
|
||||
public override bool RequiresExecution(object model)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Umbraco.Web.Install.InstallSteps
|
||||
return null;
|
||||
}
|
||||
|
||||
public override bool RequiresExecution()
|
||||
public override bool RequiresExecution(object model)
|
||||
{
|
||||
//if it's properly configured (i.e. the versions match) then no upgrade necessary
|
||||
if (_applicationContext.IsConfigured)
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace Umbraco.Web.Install.InstallSteps
|
||||
}
|
||||
}
|
||||
|
||||
public override bool RequiresExecution()
|
||||
public override bool RequiresExecution(object model)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Umbraco.Web.Install.InstallSteps
|
||||
return new InstallSetupResult("version7upgradereport", CreateReport());
|
||||
}
|
||||
|
||||
public override bool RequiresExecution()
|
||||
public override bool RequiresExecution(object model)
|
||||
{
|
||||
//if it's configured, then no need to run
|
||||
if (_applicationContext.IsConfigured)
|
||||
|
||||
@@ -8,14 +8,21 @@ using Umbraco.Web.Install.Models;
|
||||
|
||||
namespace Umbraco.Web.Install.InstallSteps
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This is the first UI step for a brand new install
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// By default this will show the user view which is the most basic information to configure a new install, but if an install get's interupted because of an
|
||||
/// error, etc... and the end-user refreshes the installer then we cannot show the user screen because they've already entered that information so instead we'll
|
||||
/// display a simple continue installation view.
|
||||
/// </remarks>
|
||||
[InstallSetupStep(InstallationType.NewInstall,
|
||||
"User", "user", 20, "Saving your user credentials")]
|
||||
internal class UserStep : InstallSetupStep<UserModel>
|
||||
"User", 20, "Saving your user credentials")]
|
||||
internal class NewInstallStep : InstallSetupStep<UserModel>
|
||||
{
|
||||
private readonly ApplicationContext _applicationContext;
|
||||
|
||||
public UserStep(ApplicationContext applicationContext)
|
||||
public NewInstallStep(ApplicationContext applicationContext)
|
||||
{
|
||||
_applicationContext = applicationContext;
|
||||
}
|
||||
@@ -71,10 +78,14 @@ namespace Umbraco.Web.Install.InstallSteps
|
||||
|
||||
public override string View
|
||||
{
|
||||
get { return RequiresExecution() ? base.View : string.Empty; }
|
||||
get { return RequiresExecution(null)
|
||||
//the user UI
|
||||
? "user"
|
||||
//the continue install UI
|
||||
: "continueinstall"; }
|
||||
}
|
||||
|
||||
public override bool RequiresExecution()
|
||||
public override bool RequiresExecution(UserModel model)
|
||||
{
|
||||
//if there's already a version then there should def be a user
|
||||
if (GlobalSettings.ConfigurationStatus.IsNullOrWhiteSpace() == false) return false;
|
||||
@@ -51,7 +51,7 @@ namespace Umbraco.Web.Install.InstallSteps
|
||||
return null;
|
||||
}
|
||||
|
||||
public override bool RequiresExecution()
|
||||
public override bool RequiresExecution(object model)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Umbraco.Web.Install.InstallSteps
|
||||
library.RefreshContent();
|
||||
}
|
||||
|
||||
public override bool RequiresExecution()
|
||||
public override bool RequiresExecution(object model)
|
||||
{
|
||||
var installSteps = InstallStatusTracker.GetStatus().ToArray();
|
||||
//this step relies on the preious one completed - because it has stored some information we need
|
||||
|
||||
@@ -32,6 +32,12 @@ namespace Umbraco.Web.Install.InstallSteps
|
||||
var defaultPackageId = modules.First().RepoGuid;
|
||||
starterKitId = defaultPackageId;
|
||||
}
|
||||
else if (starterKitId.Value == Guid.Empty)
|
||||
{
|
||||
//if the startkit id is an empty GUID then it means the user has decided not to install one
|
||||
// so we'll just exit
|
||||
return null;
|
||||
}
|
||||
|
||||
var result = DownloadPackageFiles(starterKitId.Value);
|
||||
|
||||
@@ -78,8 +84,14 @@ namespace Umbraco.Web.Install.InstallSteps
|
||||
get { return (InstalledPackage.GetAllInstalledPackages().Count > 0) ? string.Empty : base.View; }
|
||||
}
|
||||
|
||||
public override bool RequiresExecution()
|
||||
public override bool RequiresExecution(Guid? model)
|
||||
{
|
||||
//Don't execute if it's an empty GUID - meaning the user has chosen not to install one
|
||||
if (model.HasValue && model.Value == Guid.Empty)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (InstalledPackage.GetAllInstalledPackages().Count > 0)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace Umbraco.Web.Install.InstallSteps
|
||||
installer.InstallBusinessLogic(manifestId, packageFile);
|
||||
}
|
||||
|
||||
public override bool RequiresExecution()
|
||||
public override bool RequiresExecution(object model)
|
||||
{
|
||||
var installSteps = InstallStatusTracker.GetStatus().ToArray();
|
||||
//this step relies on the preious one completed - because it has stored some information we need
|
||||
|
||||
@@ -7,9 +7,9 @@ namespace Umbraco.Web.Install.InstallSteps
|
||||
/// </summary>
|
||||
[InstallSetupStep(InstallationType.Upgrade,
|
||||
"Upgrade", "upgrade", 1, "Upgrading umbraco")]
|
||||
internal class Upgrade : InstallSetupStep<object>
|
||||
internal class UpgradeStep : InstallSetupStep<object>
|
||||
{
|
||||
public override bool RequiresExecution()
|
||||
public override bool RequiresExecution(object model)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -25,6 +25,12 @@ namespace Umbraco.Web.Install.Models
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
public abstract InstallSetupResult Execute(T model);
|
||||
|
||||
/// <summary>
|
||||
/// Determines if this step needs to execute based on the current state of the application and/or install process
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public abstract bool RequiresExecution(T model);
|
||||
}
|
||||
|
||||
[DataContract(Name = "step", Namespace = "")]
|
||||
@@ -60,12 +66,6 @@ namespace Umbraco.Web.Install.Models
|
||||
[IgnoreDataMember]
|
||||
public bool PerformsAppRestart { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines if this step needs to execute based on the current state of the application and/or install process
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public abstract bool RequiresExecution();
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
|
||||
@@ -313,8 +313,8 @@
|
||||
<Compile Include="Install\InstallSteps\StarterKitCleanupStep.cs" />
|
||||
<Compile Include="Install\InstallSteps\StarterKitDownloadStep.cs" />
|
||||
<Compile Include="Install\InstallSteps\StarterKitInstallStep.cs" />
|
||||
<Compile Include="Install\InstallSteps\Upgrade.cs" />
|
||||
<Compile Include="Install\InstallSteps\UserStep.cs" />
|
||||
<Compile Include="Install\InstallSteps\UpgradeStep.cs" />
|
||||
<Compile Include="Install\InstallSteps\NewInstallStep.cs" />
|
||||
<Compile Include="Install\Models\DatabaseModel.cs" />
|
||||
<Compile Include="Install\Models\DatabaseType.cs" />
|
||||
<Compile Include="Install\Models\InstallationType.cs" />
|
||||
|
||||
Reference in New Issue
Block a user