2014-02-26 04:15:14 +11:00
|
|
|
|
using System;
|
2014-02-26 18:25:59 +11:00
|
|
|
|
using System.Collections.Generic;
|
2014-02-26 16:01:31 +01:00
|
|
|
|
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;
|
2014-02-26 16:01:31 +01:00
|
|
|
|
using System.Text;
|
2014-02-26 04:15:14 +11:00
|
|
|
|
using System.Web.Http;
|
2014-02-26 16:01:31 +01:00
|
|
|
|
using Newtonsoft.Json;
|
|
|
|
|
|
using Newtonsoft.Json.Linq;
|
2014-02-26 18:25:59 +11:00
|
|
|
|
using Umbraco.Core;
|
|
|
|
|
|
using Umbraco.Core.Configuration;
|
2014-02-26 16:01:31 +01:00
|
|
|
|
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;
|
2014-02-26 04:15:14 +11:00
|
|
|
|
|
|
|
|
|
|
namespace Umbraco.Web.Install.Controllers
|
|
|
|
|
|
{
|
2014-02-26 18:25:59 +11:00
|
|
|
|
[AngularJsonOnlyConfiguration]
|
2014-02-26 04:15:14 +11:00
|
|
|
|
[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; }
|
|
|
|
|
|
|
2014-02-26 16:01:31 +01:00
|
|
|
|
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()
|
|
|
|
|
|
{
|
2014-03-04 11:16:42 +11:00
|
|
|
|
var setup = new InstallSetup()
|
2014-02-26 18:25:59 +11:00
|
|
|
|
{
|
2014-03-04 16:21:45 +11:00
|
|
|
|
Status = InstallHelper.GetStatus()
|
2014-02-26 18:25:59 +11:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//TODO: Check for user/site token
|
|
|
|
|
|
|
2014-02-26 16:01:31 +01:00
|
|
|
|
var steps = new List<InstallSetupStep>();
|
2014-02-26 18:25:59 +11:00
|
|
|
|
|
2014-03-04 16:21:45 +11:00
|
|
|
|
steps.AddRange(InstallHelper.GetSteps().Where(x => x.RequiresExecution()));
|
2014-03-04 11:16:42 +11:00
|
|
|
|
setup.Steps = steps;
|
2014-02-26 18:25:59 +11:00
|
|
|
|
|
2014-03-04 11:16:42 +11:00
|
|
|
|
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();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2014-03-03 08:57:00 +01:00
|
|
|
|
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,
|
|
|
|
|
|
Thumbnail = package.Thumbnail
|
|
|
|
|
|
});
|
2014-03-03 08:57:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2014-02-26 18:25:59 +11:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Does the install
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
2014-03-04 16:21:45 +11:00
|
|
|
|
public HttpResponseMessage 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();
|
|
|
|
|
|
if (status.Any() == false)
|
2014-02-26 16:01:31 +01:00
|
|
|
|
{
|
2014-03-04 16:21:45 +11:00
|
|
|
|
status = InstallStatusTracker.Initialize(installModel.InstallId, InstallHelper.GetSteps()).ToArray();
|
2014-02-26 16:01:31 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2014-03-04 16:21:45 +11:00
|
|
|
|
foreach (var stepStatus in status)
|
2014-02-26 16:01:31 +01:00
|
|
|
|
{
|
|
|
|
|
|
//if it is not complete, then we need to execute it
|
2014-03-04 16:21:45 +11:00
|
|
|
|
if (stepStatus.IsComplete == false)
|
2014-02-26 16:01:31 +01:00
|
|
|
|
{
|
2014-03-04 16:21:45 +11:00
|
|
|
|
var step = InstallHelper.GetSteps().Single(x => x.Name == stepStatus.Name);
|
|
|
|
|
|
|
2014-02-26 16:01:31 +01:00
|
|
|
|
JToken instruction = null;
|
2014-03-04 11:16:42 +11:00
|
|
|
|
if (step.HasUIElement)
|
2014-02-26 16:01:31 +01:00
|
|
|
|
{
|
|
|
|
|
|
//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)
|
2014-02-26 16:01:31 +01:00
|
|
|
|
{
|
|
|
|
|
|
return Request.CreateValidationErrorResponse("No instruction defined for step: " + step.Name);
|
|
|
|
|
|
}
|
2014-03-04 16:21:45 +11:00
|
|
|
|
instruction = installModel.Instructions[step.Name];
|
2014-02-26 16:01:31 +01:00
|
|
|
|
}
|
2014-03-04 11:16:42 +11:00
|
|
|
|
|
|
|
|
|
|
//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, step.Name, null);
|
2014-03-04 11:16:42 +11:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2014-02-26 16:01:31 +01:00
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
//check if there's a custom view to return for this step
|
|
|
|
|
|
if (setupData != null && setupData.View.IsNullOrWhiteSpace() == false)
|
|
|
|
|
|
{
|
|
|
|
|
|
return Json(new
|
|
|
|
|
|
{
|
|
|
|
|
|
complete = false,
|
|
|
|
|
|
stepCompleted = step.Name,
|
|
|
|
|
|
view = setupData.View,
|
|
|
|
|
|
model = setupData.ViewModel
|
|
|
|
|
|
}, HttpStatusCode.OK);
|
|
|
|
|
|
}
|
2014-03-03 08:57:00 +01:00
|
|
|
|
|
2014-02-26 16:01:31 +01:00
|
|
|
|
return Json(new
|
|
|
|
|
|
{
|
|
|
|
|
|
complete = false,
|
2014-03-04 16:21:45 +11:00
|
|
|
|
stepCompleted = step.Name
|
2014-02-26 16:01:31 +01:00
|
|
|
|
}, HttpStatusCode.OK);
|
2014-03-04 16:21:45 +11:00
|
|
|
|
|
2014-02-26 16:01:31 +01:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
2014-03-04 16:21:45 +11:00
|
|
|
|
if (ex is TargetInvocationException && ex.InnerException != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
ex = ex.InnerException;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var installException = ex as InstallException;
|
|
|
|
|
|
if (installException != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return Json(new
|
|
|
|
|
|
{
|
|
|
|
|
|
view = installException.View,
|
|
|
|
|
|
model = installException.ViewModel,
|
|
|
|
|
|
message = installException.Message
|
|
|
|
|
|
}, HttpStatusCode.BadRequest);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2014-02-26 16:01:31 +01:00
|
|
|
|
return Request.CreateValidationErrorResponse("An error occurred executing the step: " + step.Name + ". Error: " + ex.Message);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
InstallStatusTracker.Reset();
|
|
|
|
|
|
|
|
|
|
|
|
return Json(new { complete = true }, HttpStatusCode.OK);
|
2014-02-26 18:25:59 +11:00
|
|
|
|
}
|
|
|
|
|
|
|
2014-03-04 11:16:42 +11:00
|
|
|
|
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-02-26 16:01:31 +01:00
|
|
|
|
{
|
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;
|
|
|
|
|
|
}
|
2014-02-26 16:01:31 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2014-03-04 11:16:42 +11:00
|
|
|
|
|
2014-02-26 16:01:31 +01:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2014-02-26 04:15:14 +11:00
|
|
|
|
}
|
|
|
|
|
|
}
|