Files
Umbraco-CMS/src/Umbraco.Web/Install/Controllers/InstallApiController.cs

329 lines
13 KiB
C#
Raw Normal View History

using System;
2014-02-26 18:25:59 +11:00
using System.Collections.Generic;
using System.Linq;
using System.Net;
2014-02-26 18:25:59 +11:00
using System.Net.Http;
2014-03-04 16:21:45 +11:00
using System.Reflection;
using System.Text;
using System.Web.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
2014-02-26 18:25:59 +11:00
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
2014-02-26 18:25:59 +11:00
using Umbraco.Web.Install.Models;
using Umbraco.Web.WebApi;
namespace Umbraco.Web.Install.Controllers
{
2014-02-26 18:25:59 +11:00
[AngularJsonOnlyConfiguration]
[HttpInstallAuthorize]
public class InstallApiController : ApiController
{
protected InstallApiController()
: this(UmbracoContext.Current)
{
}
protected InstallApiController(UmbracoContext umbracoContext)
{
if (umbracoContext == null) throw new ArgumentNullException("umbracoContext");
UmbracoContext = umbracoContext;
}
/// <summary>
/// Returns the current UmbracoContext
/// </summary>
public UmbracoContext UmbracoContext { get; private set; }
public ApplicationContext ApplicationContext
{
get { return UmbracoContext.Application; }
}
2014-03-04 16:21:45 +11:00
private InstallHelper _helper;
internal InstallHelper InstallHelper
{
get
{
return _helper ?? (_helper = new InstallHelper(UmbracoContext));
}
}
2014-02-26 18:25:59 +11:00
/// <summary>
/// Gets the install setup
/// </summary>
/// <returns></returns>
public InstallSetup GetSetup()
{
var setup = new InstallSetup();
2014-02-26 18:25:59 +11:00
//TODO: Check for user/site token
var steps = new List<InstallSetupStep>();
2014-02-26 18:25:59 +11:00
var installSteps = InstallHelper.GetStepsForCurrentInstallType().ToArray();
//only get the steps that are targetting the current install type
steps.AddRange(installSteps);
setup.Steps = steps;
2014-02-26 18:25:59 +11:00
InstallStatusTracker.Initialize(setup.InstallId, installSteps);
return setup;
2014-02-26 18:25:59 +11:00
}
/// <summary>
/// Checks if the db can be connected to
/// </summary>
/// <returns></returns>
public HttpResponseMessage PostCheckDbConnection()
{
throw new NotImplementedException();
}
/// <summary>
/// Checks if the db credentials are correct
/// </summary>
/// <returns></returns>
public HttpResponseMessage PostCheckDbCredentials()
{
throw new NotImplementedException();
}
public IEnumerable<Package> GetPackages()
{
var r = new org.umbraco.our.Repository();
var modules = r.Modules();
2014-03-04 16:21:45 +11:00
return modules.Select(package => new Package()
{
Id = package.RepoGuid,
Name = package.Text,
2014-03-04 16:21:45 +11:00
Thumbnail = package.Thumbnail
});
}
2014-02-26 18:25:59 +11:00
/// <summary>
/// Does the install
/// </summary>
/// <returns></returns>
public InstallProgressResultModel PostPerformInstall(InstallInstructions installModel)
2014-02-26 18:25:59 +11:00
{
2014-03-04 16:21:45 +11:00
if (installModel == null) throw new ArgumentNullException("installModel");
2014-02-26 18:25:59 +11:00
2014-03-04 16:21:45 +11:00
var status = InstallStatusTracker.GetStatus().ToArray();
//there won't be any statuses returned if the app pool has restarted so we need to re-read from file.
2014-03-04 16:21:45 +11:00
if (status.Any() == false)
{
status = InstallStatusTracker.InitializeFromFile(installModel.InstallId).ToArray();
}
//var queue = new Queue<InstallTrackingItem>(status);
//while (queue.Count > 0)
//{
// var stepStatus = queue.Dequeue();
// //if it is not complete, then we need to execute it
// if (stepStatus.IsComplete == false)
// {
// var step = InstallHelper.GetAllSteps().Single(x => x.Name == stepStatus.Name);
// JToken instruction = null;
// if (step.HasUIElement)
// {
// //Since this is a UI instruction, we will extract the model from it
// if (installModel.Instructions.Any(x => x.Key == step.Name) == false)
// {
// throw new HttpResponseException(Request.CreateValidationErrorResponse("No instruction defined for step: " + step.Name));
// }
// instruction = installModel.Instructions[step.Name];
// }
// //If this step doesn't require execution then continue to the next one.
// if (step.RequiresExecution() == false)
// {
// //set this as complete and continue
// InstallStatusTracker.SetComplete(installModel.InstallId, stepStatus.Name, null);
// continue;
// }
// try
// {
// var setupData = ExecuteStep(step, instruction);
// //update the status
// InstallStatusTracker.SetComplete(installModel.InstallId, step.Name, setupData != null ? setupData.SavedStepData : null);
// //get the next step if there is one
// var nextStep = "";
// if ((index + 1) < status.Length)
// {
// nextStep = status[index + 1].Name;
// }
// //check if there's a custom view to return for this step
// if (setupData != null && setupData.View.IsNullOrWhiteSpace() == false)
// {
// return new InstallProgressResultModel(false, step.Name, nextStep, setupData.View, setupData.ViewModel);
// }
// return new InstallProgressResultModel(false, step.Name, nextStep);
// }
// catch (Exception ex)
// {
// if (ex is TargetInvocationException && ex.InnerException != null)
// {
// ex = ex.InnerException;
// }
// var installException = ex as InstallException;
// if (installException != null)
// {
// throw new HttpResponseException(Request.CreateValidationErrorResponse(new
// {
// view = installException.View,
// model = installException.ViewModel,
// message = installException.Message
// }));
// }
// throw new HttpResponseException(
// Request.CreateValidationErrorResponse("An error occurred executing the step: " + step.Name + ". Error: " + ex.Message));
// }
// }
//}
for (var index = 0; index < status.Length; index++)
{
var stepStatus = status[index];
//if it is not complete, then we need to execute it
2014-03-04 16:21:45 +11:00
if (stepStatus.IsComplete == false)
{
var step = InstallHelper.GetAllSteps().Single(x => x.Name == stepStatus.Name);
2014-03-04 16:21:45 +11:00
JToken instruction = null;
if (step.HasUIElement)
{
//Since this is a UI instruction, we will extract the model from it
2014-03-04 16:21:45 +11:00
if (installModel.Instructions.Any(x => x.Key == step.Name) == false)
{
throw new HttpResponseException(Request.CreateValidationErrorResponse("No instruction defined for step: " + step.Name));
}
2014-03-04 16:21:45 +11:00
instruction = installModel.Instructions[step.Name];
}
//If this step doesn't require execution then continue to the next one.
if (step.RequiresExecution() == false)
{
2014-03-04 16:21:45 +11:00
//set this as complete and continue
InstallStatusTracker.SetComplete(installModel.InstallId, stepStatus.Name, null);
continue;
}
try
{
var setupData = ExecuteStep(step, instruction);
//update the status
2014-03-04 16:21:45 +11:00
InstallStatusTracker.SetComplete(installModel.InstallId, step.Name, setupData != null ? setupData.SavedStepData : null);
//get the next step if there is one
var nextStep = "";
if ((index + 1) < status.Length)
2014-03-04 16:21:45 +11:00
{
nextStep = status[index + 1].Name;
2014-03-04 16:21:45 +11:00
}
//check if there's a custom view to return for this step
if (setupData != null && setupData.View.IsNullOrWhiteSpace() == false)
{
return new InstallProgressResultModel(false, step.Name, nextStep, setupData.View, setupData.ViewModel);
}
2014-03-04 16:21:45 +11:00
return new InstallProgressResultModel(false, step.Name, nextStep);
}
catch (Exception ex)
{
2014-03-04 16:21:45 +11:00
if (ex is TargetInvocationException && ex.InnerException != null)
{
ex = ex.InnerException;
}
2014-03-04 19:11:27 +01:00
//return custom view if we have an install exception
2014-03-04 16:21:45 +11:00
var installException = ex as InstallException;
if (installException != null)
{
throw new HttpResponseException(Request.CreateValidationErrorResponse(new
2014-03-04 16:21:45 +11:00
{
2014-03-04 19:11:27 +01:00
step = step.Name,
2014-03-04 16:21:45 +11:00
view = installException.View,
model = installException.ViewModel,
message = installException.Message
}));
2014-03-04 16:21:45 +11:00
}
throw new HttpResponseException(
Request.CreateValidationErrorResponse("An error occurred executing the step: " + step.Name + ". Error: " + ex.Message));
2014-03-04 19:11:27 +01:00
//return standard view + step and message to display generic message
return Json(new
{
step = step.Name,
view = "error",
message = ex.Message
}, HttpStatusCode.BadRequest);
//return Request.CreateValidationErrorResponse("An error occurred executing the step: " + step.Name + ". Error: " + ex.Message);
}
}
}
InstallStatusTracker.Reset();
return new InstallProgressResultModel(true, "", "");
//return Json(new { complete = true }, HttpStatusCode.OK);
2014-02-26 18:25:59 +11:00
}
//private InstallSetupStep IterateNextRequiredStep(Queue<InstallTrackingItem> queue)
//{
// var step = InstallHelper.GetAllSteps().Single(x => x.Name == stepStatus.Name);
//}
internal InstallSetupResult ExecuteStep(InstallSetupStep step, JToken instruction)
2014-02-26 18:25:59 +11:00
{
2014-03-04 16:21:45 +11:00
using (DisposableTimer.TraceDuration<InstallApiController>("Executing installation step: " + step.Name, "Step completed"))
{
2014-03-04 16:21:45 +11:00
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 == "Execute");
return (InstallSetupResult)method.Invoke(step, new object[] { model });
}
catch (Exception ex)
{
LogHelper.Error<InstallApiController>("Installation step " + step.Name + " failed.", ex);
throw;
}
}
}
private HttpResponseMessage Json(object jsonObject, HttpStatusCode status)
{
var response = Request.CreateResponse(status);
var json = JObject.FromObject(jsonObject);
response.Content = new StringContent(json.ToString(), Encoding.UTF8, "application/json");
return response;
}
}
}