217 lines
8.9 KiB
C#
217 lines
8.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using Newtonsoft.Json;
|
|
using Umbraco.Core.Configuration.UmbracoSettings;
|
|
using Umbraco.Core.Hosting;
|
|
using Umbraco.Core.Services;
|
|
using Umbraco.Web.Common.Attributes;
|
|
using Umbraco.Web.Models;
|
|
using Umbraco.Web.Security;
|
|
using Umbraco.Web.Tour;
|
|
|
|
namespace Umbraco.Web.BackOffice.Controllers
|
|
{
|
|
[PluginController("UmbracoApi")]
|
|
public class TourController : UmbracoAuthorizedJsonController
|
|
{
|
|
private readonly TourFilterCollection _filters;
|
|
private readonly IHostingEnvironment _hostingEnvironment;
|
|
private readonly ITourSettings _tourSettings;
|
|
private readonly IWebSecurity _webSecurity;
|
|
private readonly IContentTypeService _contentTypeService;
|
|
|
|
public TourController(
|
|
TourFilterCollection filters,
|
|
IHostingEnvironment hostingEnvironment,
|
|
ITourSettings tourSettings,
|
|
IWebSecurity webSecurity,
|
|
IContentTypeService contentTypeService)
|
|
{
|
|
_filters = filters;
|
|
_hostingEnvironment = hostingEnvironment;
|
|
|
|
_tourSettings = tourSettings;
|
|
_webSecurity = webSecurity;
|
|
_contentTypeService = contentTypeService;
|
|
}
|
|
|
|
public IEnumerable<BackOfficeTourFile> GetTours()
|
|
{
|
|
var result = new List<BackOfficeTourFile>();
|
|
|
|
if (_tourSettings.EnableTours == false)
|
|
return result;
|
|
|
|
var user = _webSecurity.CurrentUser;
|
|
if (user == null)
|
|
return result;
|
|
|
|
//get all filters that will be applied to all tour aliases
|
|
var aliasOnlyFilters = _filters.Where(x => x.PluginName == null && x.TourFileName == null).ToList();
|
|
|
|
//don't pass in any filters for core tours that have a plugin name assigned
|
|
var nonPluginFilters = _filters.Where(x => x.PluginName == null).ToList();
|
|
|
|
//add core tour files
|
|
var coreToursPath = Path.Combine(_hostingEnvironment.MapPathContentRoot(Core.Constants.SystemDirectories.Config), "BackOfficeTours");
|
|
if (Directory.Exists(coreToursPath))
|
|
{
|
|
foreach (var tourFile in Directory.EnumerateFiles(coreToursPath, "*.json"))
|
|
{
|
|
TryParseTourFile(tourFile, result, nonPluginFilters, aliasOnlyFilters);
|
|
}
|
|
}
|
|
|
|
//collect all tour files in packages
|
|
var appPlugins = _hostingEnvironment.MapPathContentRoot(Core.Constants.SystemDirectories.AppPlugins);
|
|
if (Directory.Exists(appPlugins))
|
|
{
|
|
foreach (var plugin in Directory.EnumerateDirectories(appPlugins))
|
|
{
|
|
var pluginName = Path.GetFileName(plugin.TrimEnd('\\'));
|
|
var pluginFilters = _filters.Where(x => x.PluginName != null && x.PluginName.IsMatch(pluginName))
|
|
.ToList();
|
|
|
|
//If there is any filter applied to match the plugin only (no file or tour alias) then ignore the plugin entirely
|
|
var isPluginFiltered = pluginFilters.Any(x => x.TourFileName == null && x.TourAlias == null);
|
|
if (isPluginFiltered) continue;
|
|
|
|
//combine matched package filters with filters not specific to a package
|
|
var combinedFilters = nonPluginFilters.Concat(pluginFilters).ToList();
|
|
|
|
foreach (var backofficeDir in Directory.EnumerateDirectories(plugin, "backoffice"))
|
|
{
|
|
foreach (var tourDir in Directory.EnumerateDirectories(backofficeDir, "tours"))
|
|
{
|
|
foreach (var tourFile in Directory.EnumerateFiles(tourDir, "*.json"))
|
|
{
|
|
TryParseTourFile(tourFile, result, combinedFilters, aliasOnlyFilters, pluginName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//Get all allowed sections for the current user
|
|
var allowedSections = user.AllowedSections.ToList();
|
|
|
|
var toursToBeRemoved = new List<BackOfficeTourFile>();
|
|
|
|
//Checking to see if the user has access to the required tour sections, else we remove the tour
|
|
foreach (var backOfficeTourFile in result)
|
|
{
|
|
if (backOfficeTourFile.Tours != null)
|
|
{
|
|
foreach (var tour in backOfficeTourFile.Tours)
|
|
{
|
|
if (tour.RequiredSections != null)
|
|
{
|
|
foreach (var toursRequiredSection in tour.RequiredSections)
|
|
{
|
|
if (allowedSections.Contains(toursRequiredSection) == false)
|
|
{
|
|
toursToBeRemoved.Add(backOfficeTourFile);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result.Except(toursToBeRemoved).OrderBy(x => x.FileName, StringComparer.InvariantCultureIgnoreCase);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a tours for a specific doctype
|
|
/// </summary>
|
|
/// <param name="doctypeAlias">The documenttype alias</param>
|
|
/// <returns>A <see cref="BackOfficeTour"/></returns>
|
|
public IEnumerable<BackOfficeTour> GetToursForDoctype(string doctypeAlias)
|
|
{
|
|
var tourFiles = this.GetTours();
|
|
|
|
var doctypeAliasWithCompositions = new List<string>
|
|
{
|
|
doctypeAlias
|
|
};
|
|
|
|
var contentType = _contentTypeService.Get(doctypeAlias);
|
|
|
|
if (contentType != null)
|
|
{
|
|
doctypeAliasWithCompositions.AddRange(contentType.CompositionAliases());
|
|
}
|
|
|
|
return tourFiles.SelectMany(x => x.Tours)
|
|
.Where(x =>
|
|
{
|
|
if (string.IsNullOrEmpty(x.ContentType))
|
|
{
|
|
return false;
|
|
}
|
|
var contentTypes = x.ContentType.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(ct => ct.Trim());
|
|
return contentTypes.Intersect(doctypeAliasWithCompositions).Any();
|
|
});
|
|
}
|
|
|
|
private void TryParseTourFile(string tourFile,
|
|
ICollection<BackOfficeTourFile> result,
|
|
List<BackOfficeTourFilter> filters,
|
|
List<BackOfficeTourFilter> aliasOnlyFilters,
|
|
string pluginName = null)
|
|
{
|
|
var fileName = Path.GetFileNameWithoutExtension(tourFile);
|
|
if (fileName == null) return;
|
|
|
|
//get the filters specific to this file
|
|
var fileFilters = filters.Where(x => x.TourFileName != null && x.TourFileName.IsMatch(fileName)).ToList();
|
|
|
|
//If there is any filter applied to match the file only (no tour alias) then ignore the file entirely
|
|
var isFileFiltered = fileFilters.Any(x => x.TourAlias == null);
|
|
if (isFileFiltered) return;
|
|
|
|
//now combine all aliases to filter below
|
|
var aliasFilters = aliasOnlyFilters.Concat(filters.Where(x => x.TourAlias != null))
|
|
.Select(x => x.TourAlias)
|
|
.ToList();
|
|
|
|
try
|
|
{
|
|
var contents = System.IO.File.ReadAllText(tourFile);
|
|
var tours = JsonConvert.DeserializeObject<BackOfficeTour[]>(contents);
|
|
|
|
var backOfficeTours = tours.Where(x =>
|
|
aliasFilters.Count == 0 || aliasFilters.All(filter => filter.IsMatch(x.Alias)) == false);
|
|
|
|
var user = _webSecurity.CurrentUser;
|
|
|
|
var localizedTours = backOfficeTours.Where(x =>
|
|
string.IsNullOrWhiteSpace(x.Culture) || x.Culture.Equals(user.Language,
|
|
StringComparison.InvariantCultureIgnoreCase)).ToList();
|
|
|
|
var tour = new BackOfficeTourFile
|
|
{
|
|
FileName = Path.GetFileNameWithoutExtension(tourFile),
|
|
PluginName = pluginName,
|
|
Tours = localizedTours
|
|
};
|
|
|
|
//don't add if all of the tours are filtered
|
|
if (tour.Tours.Any())
|
|
result.Add(tour);
|
|
}
|
|
catch (IOException e)
|
|
{
|
|
throw new IOException("Error while trying to read file: " + tourFile, e);
|
|
}
|
|
catch (JsonReaderException e)
|
|
{
|
|
throw new JsonReaderException("Error while trying to parse content as tour data: " + tourFile, e);
|
|
}
|
|
}
|
|
}
|
|
}
|