2020-05-13 16:09:54 +10:00
using Microsoft.AspNetCore.Http ;
using Microsoft.AspNetCore.Mvc ;
using Microsoft.AspNetCore.Mvc.ViewEngines ;
2020-08-21 14:52:47 +01:00
using Microsoft.Extensions.Options ;
2020-05-13 16:09:54 +10:00
using System ;
2020-08-07 00:48:32 +10:00
using System.IO ;
2020-03-30 21:27:35 +02:00
using System.Threading.Tasks ;
2018-03-14 12:55:34 +11:00
using Umbraco.Core ;
using Umbraco.Core.Configuration ;
2020-08-21 14:52:47 +01:00
using Umbraco.Core.Configuration.Models ;
2020-01-21 17:03:46 -08:00
using Umbraco.Core.Configuration.UmbracoSettings ;
2020-02-13 07:56:50 +01:00
using Umbraco.Core.Hosting ;
2020-09-22 10:01:00 +02:00
using Umbraco.Core.Security ;
2019-01-29 15:30:25 +01:00
using Umbraco.Core.Services ;
2020-04-02 17:41:00 +11:00
using Umbraco.Core.WebAssets ;
2020-08-07 00:48:32 +10:00
using Umbraco.Extensions ;
2020-05-13 16:09:54 +10:00
using Umbraco.Web.BackOffice.Filters ;
2020-10-26 13:34:08 +01:00
using Umbraco.Web.BackOffice.ActionResults ;
2020-05-13 16:09:54 +10:00
using Umbraco.Web.Common.Filters ;
using Umbraco.Web.Editors ;
2018-02-27 15:47:47 +01:00
using Umbraco.Web.Features ;
2018-09-10 11:34:31 +10:00
using Umbraco.Web.PublishedCache ;
2020-06-04 13:40:33 +02:00
using Umbraco.Web.Security ;
2020-09-22 08:58:16 +02:00
using Umbraco.Web.Services ;
2020-02-10 11:23:23 +01:00
using Umbraco.Web.Trees ;
2020-04-02 21:19:42 +11:00
using Umbraco.Web.WebAssets ;
2018-09-10 11:34:31 +10:00
using Constants = Umbraco . Core . Constants ;
2018-02-27 15:47:47 +01:00
2020-05-13 16:09:54 +10:00
namespace Umbraco.Web.BackOffice.Controllers
2018-02-27 15:47:47 +01:00
{
[DisableBrowserCache]
2020-05-14 20:59:29 +10:00
[Area(Constants.Web.Mvc.BackOfficeArea)]
2018-02-27 15:47:47 +01:00
public class PreviewController : Controller
{
2018-04-05 12:50:00 +02:00
private readonly UmbracoFeatures _features ;
2020-08-21 14:52:47 +01:00
private readonly GlobalSettings _globalSettings ;
2018-09-10 11:34:31 +10:00
private readonly IPublishedSnapshotService _publishedSnapshotService ;
2020-10-21 16:51:00 +11:00
private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor ;
2020-09-22 10:01:00 +02:00
private readonly ILocalizationService _localizationService ;
2020-02-13 07:56:50 +01:00
private readonly IHostingEnvironment _hostingEnvironment ;
2020-02-19 09:26:51 +01:00
private readonly ICookieManager _cookieManager ;
2020-03-17 10:28:03 +01:00
private readonly IRuntimeMinifier _runtimeMinifier ;
2020-05-13 16:09:54 +10:00
private readonly ICompositeViewEngine _viewEngines ;
2018-04-05 12:50:00 +02:00
2019-01-29 15:30:25 +01:00
public PreviewController (
UmbracoFeatures features ,
2020-08-23 23:36:48 +02:00
IOptions < GlobalSettings > globalSettings ,
2019-01-29 15:30:25 +01:00
IPublishedSnapshotService publishedSnapshotService ,
2020-10-21 16:51:00 +11:00
IBackOfficeSecurityAccessor backofficeSecurityAccessor ,
2019-11-20 10:50:15 +01:00
ILocalizationService localizationService ,
2020-02-19 09:26:51 +01:00
IHostingEnvironment hostingEnvironment ,
2020-03-03 11:18:54 +00:00
ICookieManager cookieManager ,
2020-05-13 16:09:54 +10:00
IRuntimeMinifier runtimeMinifier ,
ICompositeViewEngine viewEngines )
2018-04-05 12:50:00 +02:00
{
_features = features ;
2020-08-21 14:52:47 +01:00
_globalSettings = globalSettings . Value ;
2018-09-10 11:34:31 +10:00
_publishedSnapshotService = publishedSnapshotService ;
2020-09-22 10:01:00 +02:00
_backofficeSecurityAccessor = backofficeSecurityAccessor ;
2019-01-29 15:30:25 +01:00
_localizationService = localizationService ;
2020-02-13 07:56:50 +01:00
_hostingEnvironment = hostingEnvironment ;
2020-02-19 09:26:51 +01:00
_cookieManager = cookieManager ;
2020-03-17 10:28:03 +01:00
_runtimeMinifier = runtimeMinifier ;
2020-05-13 16:09:54 +10:00
_viewEngines = viewEngines ;
2018-04-05 12:50:00 +02:00
}
2020-11-20 14:59:08 +11:00
// TODO: This should really be refactored. Redirection/Challenge is part of Authentication, not part of authorization directly
// We only use this redirectToUmbracoLogin flag in this one instance. I think this
// should be handled as part of the preview authentication process instead.
2020-11-12 11:01:19 +01:00
[UmbracoBackOfficeAuthorize(redirectToUmbracoLogin: true, requireApproval : false)]
2018-09-14 00:14:03 +10:00
[DisableBrowserCache]
2018-02-27 15:47:47 +01:00
public ActionResult Index ( )
{
2019-01-29 15:30:25 +01:00
var availableLanguages = _localizationService . GetAllLanguages ( ) ;
2020-08-07 00:48:32 +10:00
var model = new BackOfficePreviewModel ( _features , availableLanguages ) ;
2018-03-14 13:56:49 +11:00
2018-03-14 15:24:30 +11:00
if ( model . PreviewExtendedHeaderView . IsNullOrWhiteSpace ( ) = = false )
2018-03-14 13:56:49 +11:00
{
2020-05-13 16:09:54 +10:00
var viewEngineResult = _viewEngines . FindView ( ControllerContext , model . PreviewExtendedHeaderView , false ) ;
2018-03-14 13:56:49 +11:00
if ( viewEngineResult . View = = null )
2018-03-14 15:24:30 +11:00
throw new InvalidOperationException ( "Could not find the view " + model . PreviewExtendedHeaderView + ", the following locations were searched: " + Environment . NewLine + string . Join ( Environment . NewLine , viewEngineResult . SearchedLocations ) ) ;
2018-02-28 13:41:49 +01:00
}
2018-03-14 13:56:49 +11:00
2020-08-07 00:48:32 +10:00
var viewPath = Path . Combine (
2020-09-01 18:10:12 +02:00
_globalSettings . UmbracoPath ,
2020-08-07 00:48:32 +10:00
Constants . Web . Mvc . BackOfficeArea ,
ControllerExtensions . GetControllerName < PreviewController > ( ) + ".cshtml" )
. Replace ( "\\" , "/" ) ; // convert to forward slashes since it's a virtual path
return View ( viewPath , model ) ;
2018-02-27 15:47:47 +01:00
}
2018-09-14 00:14:03 +10:00
/// <summary>
/// Returns the JavaScript file for preview
/// </summary>
/// <returns></returns>
[MinifyJavaScriptResult(Order = 0)]
2020-05-13 16:09:54 +10:00
// TODO: Replace this with response caching https://docs.microsoft.com/en-us/aspnet/core/performance/caching/response?view=aspnetcore-3.1
//[OutputCache(Order = 1, VaryByParam = "none", Location = OutputCacheLocation.Server, Duration = 5000)]
2020-03-30 21:27:35 +02:00
public async Task < JavaScriptResult > Application ( )
2018-09-14 00:14:03 +10:00
{
2020-04-02 17:41:00 +11:00
var files = await _runtimeMinifier . GetAssetPathsAsync ( BackOfficeWebAssets . UmbracoPreviewJsBundleName ) ;
2020-04-03 11:03:06 +11:00
var result = BackOfficeJavaScriptInitializer . GetJavascriptInitialization ( files , "umbraco.preview" , _globalSettings , _hostingEnvironment ) ;
2018-09-14 00:14:03 +10:00
2020-05-13 16:09:54 +10:00
return new JavaScriptResult ( result ) ;
2018-09-14 00:14:03 +10:00
}
2018-09-10 11:34:31 +10:00
/// <summary>
/// The endpoint that is loaded within the preview iframe
/// </summary>
/// <returns></returns>
2020-11-12 11:01:19 +01:00
[UmbracoBackOfficeAuthorize]
2018-09-14 00:44:36 +10:00
public ActionResult Frame ( int id , string culture )
2018-09-10 11:34:31 +10:00
{
2020-10-08 16:36:25 +02:00
EnterPreview ( id ) ;
2018-09-10 11:34:31 +10:00
// use a numeric url because content may not be in cache and so .Url would fail
2018-09-14 00:44:36 +10:00
var query = culture . IsNullOrWhiteSpace ( ) ? string . Empty : $"?culture={culture}" ;
2018-09-10 11:34:31 +10:00
2020-08-07 00:48:32 +10:00
return RedirectPermanent ( $"../../{id}.aspx{query}" ) ;
2018-09-10 11:34:31 +10:00
}
2020-10-08 16:36:25 +02:00
public ActionResult EnterPreview ( int id )
{
2020-11-12 12:57:03 +01:00
var user = _backofficeSecurityAccessor . BackOfficeSecurity . CurrentUser ;
2018-09-10 11:34:31 +10:00
2020-10-08 16:36:25 +02:00
var previewToken = _publishedSnapshotService . EnterPreview ( user , id ) ;
2020-11-12 12:57:03 +01:00
_cookieManager . SetCookieValue ( Constants . Web . PreviewCookieName , previewToken ) ;
2020-10-08 16:36:25 +02:00
return null ;
}
2018-12-14 13:11:36 +00:00
public ActionResult End ( string redir = null )
{
2020-02-19 09:26:51 +01:00
var previewToken = _cookieManager . GetPreviewCookieValue ( ) ;
2018-12-14 13:11:36 +00:00
2020-05-13 16:09:54 +10:00
_publishedSnapshotService . ExitPreview ( previewToken ) ;
_cookieManager . ExpireCookie ( Constants . Web . PreviewCookieName ) ;
2018-12-14 13:11:36 +00:00
2020-10-21 13:03:53 +01:00
// Expire Client-side cookie that determines whether the user has accepted to be in Preview Mode when visiting the website.
2020-11-12 12:57:03 +01:00
_cookieManager . ExpireCookie ( Constants . Web . AcceptPreviewCookieName ) ;
2018-12-14 13:11:36 +00:00
if ( Uri . IsWellFormedUriString ( redir , UriKind . Relative )
& & redir . StartsWith ( "//" ) = = false
2020-05-13 16:09:54 +10:00
& & Uri . TryCreate ( redir , UriKind . Relative , out var url ) )
2018-12-14 13:11:36 +00:00
return Redirect ( url . ToString ( ) ) ;
return Redirect ( "/" ) ;
}
2018-02-27 15:47:47 +01:00
}
}