347 lines
16 KiB
C#
347 lines
16 KiB
C#
using Oqtane.Models;
|
|
using System.Threading.Tasks;
|
|
using System.Linq;
|
|
using System.Collections.Generic;
|
|
using System;
|
|
using Oqtane.Documentation;
|
|
using Microsoft.Extensions.Caching.Memory;
|
|
using Oqtane.Infrastructure;
|
|
using Oqtane.Repository;
|
|
using Oqtane.Security;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Oqtane.Enums;
|
|
using Oqtane.Shared;
|
|
using System.Globalization;
|
|
using Oqtane.Extensions;
|
|
|
|
namespace Oqtane.Services
|
|
{
|
|
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
|
public class ServerSiteService : ISiteService
|
|
{
|
|
private readonly ISiteRepository _sites;
|
|
private readonly IPageRepository _pages;
|
|
private readonly IThemeRepository _themes;
|
|
private readonly IPageModuleRepository _pageModules;
|
|
private readonly IModuleDefinitionRepository _moduleDefinitions;
|
|
private readonly ILanguageRepository _languages;
|
|
private readonly IUserPermissions _userPermissions;
|
|
private readonly ISettingRepository _settings;
|
|
private readonly ITenantManager _tenantManager;
|
|
private readonly ISyncManager _syncManager;
|
|
private readonly IConfigManager _configManager;
|
|
private readonly ILogManager _logger;
|
|
private readonly IMemoryCache _cache;
|
|
private readonly IHttpContextAccessor _accessor;
|
|
private readonly string _private = "[PRIVATE]";
|
|
|
|
public ServerSiteService(ISiteRepository sites, IPageRepository pages, IThemeRepository themes, IPageModuleRepository pageModules, IModuleDefinitionRepository moduleDefinitions, ILanguageRepository languages, IUserPermissions userPermissions, ISettingRepository settings, ITenantManager tenantManager, ISyncManager syncManager, IConfigManager configManager, ILogManager logger, IMemoryCache cache, IHttpContextAccessor accessor)
|
|
{
|
|
_sites = sites;
|
|
_pages = pages;
|
|
_themes = themes;
|
|
_pageModules = pageModules;
|
|
_moduleDefinitions = moduleDefinitions;
|
|
_languages = languages;
|
|
_userPermissions = userPermissions;
|
|
_settings = settings;
|
|
_tenantManager = tenantManager;
|
|
_syncManager = syncManager;
|
|
_configManager = configManager;
|
|
_logger = logger;
|
|
_cache = cache;
|
|
_accessor = accessor;
|
|
}
|
|
|
|
public Task<List<Site>> GetSitesAsync()
|
|
{
|
|
List<Site> sites = new List<Site>();
|
|
if (_accessor.HttpContext.User.IsInRole(RoleNames.Host))
|
|
{
|
|
sites = _sites.GetSites().ToList();
|
|
}
|
|
return Task.FromResult(sites);
|
|
}
|
|
|
|
public Task<Site> GetSiteAsync(int siteId)
|
|
{
|
|
var alias = _tenantManager.GetAlias();
|
|
var site = _cache.GetOrCreate($"site:{alias.SiteKey}", entry =>
|
|
{
|
|
entry.SlidingExpiration = TimeSpan.FromMinutes(30);
|
|
return GetSite(siteId);
|
|
});
|
|
|
|
// clone object so that cache is not mutated
|
|
site = site.Clone();
|
|
|
|
// trim site settings based on user permissions
|
|
site.Settings = site.Settings
|
|
.Where(item => !item.Value.StartsWith(_private) || _accessor.HttpContext.User.IsInRole(RoleNames.Admin))
|
|
.ToDictionary(setting => setting.Key, setting => setting.Value.Replace(_private, ""));
|
|
|
|
// trim pages based on user permissions
|
|
var pages = new List<Page>();
|
|
foreach (Page page in site.Pages)
|
|
{
|
|
if (!page.IsDeleted && _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.View, page.PermissionList) && (Utilities.IsEffectiveAndNotExpired(page.EffectiveDate, page.ExpiryDate) || _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.Edit, page.PermissionList)))
|
|
{
|
|
page.Settings = page.Settings
|
|
.Where(item => !item.Value.StartsWith(_private) || _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.Edit, page.PermissionList))
|
|
.ToDictionary(setting => setting.Key, setting => setting.Value.Replace(_private, ""));
|
|
pages.Add(page);
|
|
}
|
|
}
|
|
site.Pages = pages;
|
|
|
|
// get language display name for user
|
|
foreach (Language language in site.Languages)
|
|
{
|
|
language.Name = CultureInfo.GetCultureInfo(language.Code).DisplayName;
|
|
}
|
|
site.Languages = site.Languages.OrderBy(item => item.Name).ToList();
|
|
|
|
return Task.FromResult(site);
|
|
}
|
|
|
|
private Site GetSite(int siteid)
|
|
{
|
|
var alias = _tenantManager.GetAlias();
|
|
var site = _sites.GetSite(siteid);
|
|
if (site != null && site.SiteId == alias.SiteId)
|
|
{
|
|
// site settings
|
|
site.Settings = _settings.GetSettings(EntityNames.Site, site.SiteId)
|
|
.ToDictionary(setting => setting.SettingName, setting => (setting.IsPrivate ? _private : "") + setting.SettingValue);
|
|
|
|
// populate file extensions
|
|
site.ImageFiles = site.Settings.ContainsKey("ImageFiles") && !string.IsNullOrEmpty(site.Settings["ImageFiles"])
|
|
? site.Settings["ImageFiles"] : Constants.ImageFiles;
|
|
site.UploadableFiles = site.Settings.ContainsKey("UploadableFiles") && !string.IsNullOrEmpty(site.Settings["UploadableFiles"])
|
|
? site.Settings["UploadableFiles"] : Constants.UploadableFiles;
|
|
|
|
// pages
|
|
List<Setting> settings = _settings.GetSettings(EntityNames.Page).ToList();
|
|
site.Pages = new List<Page>();
|
|
foreach (Page page in _pages.GetPages(site.SiteId))
|
|
{
|
|
page.Settings = settings.Where(item => item.EntityId == page.PageId)
|
|
.ToDictionary(setting => setting.SettingName, setting => (setting.IsPrivate ? _private : "") + setting.SettingValue);
|
|
site.Pages.Add(page);
|
|
}
|
|
|
|
// framework modules
|
|
var modules = GetPageModules(site.SiteId);
|
|
site.Settings.Add(Constants.AdminDashboardModule, modules.FirstOrDefault(item => item.ModuleDefinitionName == Constants.AdminDashboardModule).ModuleId.ToString());
|
|
site.Settings.Add(Constants.PageManagementModule, modules.FirstOrDefault(item => item.ModuleDefinitionName == Constants.PageManagementModule).ModuleId.ToString());
|
|
|
|
// languages
|
|
site.Languages = _languages.GetLanguages(site.SiteId).ToList();
|
|
var defaultCulture = CultureInfo.GetCultureInfo(Constants.DefaultCulture);
|
|
if (!site.Languages.Exists(item => item.Code == defaultCulture.Name))
|
|
{
|
|
site.Languages.Add(new Language { Code = defaultCulture.Name, Name = "", Version = Constants.Version, IsDefault = !site.Languages.Any(l => l.IsDefault) });
|
|
}
|
|
|
|
// themes
|
|
site.Themes = _themes.FilterThemes(_themes.GetThemes().ToList());
|
|
|
|
// installation date used for fingerprinting static assets
|
|
site.Fingerprint = Utilities.GenerateSimpleHash(_configManager.GetSetting("InstallationDate", DateTime.UtcNow.ToString("yyyyMMddHHmm")));
|
|
}
|
|
else
|
|
{
|
|
if (site != null)
|
|
{
|
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Get Attempt {SiteId}", siteid);
|
|
site = null;
|
|
}
|
|
}
|
|
return site;
|
|
}
|
|
|
|
private static List<Page> GetPagesHierarchy(List<Page> pages)
|
|
{
|
|
List<Page> hierarchy = new List<Page>();
|
|
Action<List<Page>, Page> getPath = null;
|
|
getPath = (pageList, page) =>
|
|
{
|
|
IEnumerable<Page> children;
|
|
int level;
|
|
if (page == null)
|
|
{
|
|
level = -1;
|
|
children = pages.Where(item => item.ParentId == null);
|
|
}
|
|
else
|
|
{
|
|
level = page.Level;
|
|
children = pages.Where(item => item.ParentId == page.PageId);
|
|
}
|
|
foreach (Page child in children)
|
|
{
|
|
child.Level = level + 1;
|
|
child.HasChildren = pages.Any(item => item.ParentId == child.PageId && !item.IsDeleted && item.IsNavigation);
|
|
hierarchy.Add(child);
|
|
getPath(pageList, child);
|
|
}
|
|
};
|
|
pages = pages.OrderBy(item => item.Order).ToList();
|
|
getPath(pages, null);
|
|
|
|
// add any non-hierarchical items to the end of the list
|
|
foreach (Page page in pages)
|
|
{
|
|
if (hierarchy.Find(item => item.PageId == page.PageId) == null)
|
|
{
|
|
hierarchy.Add(page);
|
|
}
|
|
}
|
|
return hierarchy;
|
|
}
|
|
|
|
public Task<Site> AddSiteAsync(Site site)
|
|
{
|
|
if (_accessor.HttpContext.User.IsInRole(RoleNames.Host))
|
|
{
|
|
site = _sites.AddSite(site);
|
|
_syncManager.AddSyncEvent(_tenantManager.GetAlias(), EntityNames.Site, site.SiteId, SyncEventActions.Create);
|
|
_logger.Log(site.SiteId, LogLevel.Information, this, LogFunction.Create, "Site Added {Site}", site);
|
|
}
|
|
else
|
|
{
|
|
site = null;
|
|
}
|
|
return Task.FromResult(site);
|
|
}
|
|
|
|
public Task<Site> UpdateSiteAsync(Site site)
|
|
{
|
|
if (_accessor.HttpContext.User.IsInRole(RoleNames.Admin))
|
|
{
|
|
var alias = _tenantManager.GetAlias();
|
|
var current = _sites.GetSite(site.SiteId, false);
|
|
if (site.SiteId == alias.SiteId && site.TenantId == alias.TenantId && current != null)
|
|
{
|
|
site = _sites.UpdateSite(site);
|
|
_syncManager.AddSyncEvent(alias, EntityNames.Site, site.SiteId, SyncEventActions.Update);
|
|
string action = SyncEventActions.Refresh;
|
|
if (current.RenderMode != site.RenderMode || current.Runtime != site.Runtime)
|
|
{
|
|
action = SyncEventActions.Reload;
|
|
}
|
|
_syncManager.AddSyncEvent(alias, EntityNames.Site, site.SiteId, action);
|
|
_logger.Log(site.SiteId, LogLevel.Information, this, LogFunction.Update, "Site Updated {Site}", site);
|
|
}
|
|
else
|
|
{
|
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Put Attempt {Site}", site);
|
|
site = null;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
site = null;
|
|
}
|
|
return Task.FromResult(site);
|
|
}
|
|
|
|
public Task DeleteSiteAsync(int siteId)
|
|
{
|
|
if (_accessor.HttpContext.User.IsInRole(RoleNames.Host))
|
|
{
|
|
var alias = _tenantManager.GetAlias();
|
|
var site = _sites.GetSite(siteId);
|
|
if (site != null && site.SiteId == alias.SiteId)
|
|
{
|
|
_sites.DeleteSite(siteId);
|
|
_syncManager.AddSyncEvent(alias, EntityNames.Site, site.SiteId, SyncEventActions.Delete);
|
|
_syncManager.AddSyncEvent(alias, EntityNames.Site, site.SiteId, SyncEventActions.Refresh);
|
|
_logger.Log(siteId, LogLevel.Information, this, LogFunction.Delete, "Site Deleted {SiteId}", siteId);
|
|
}
|
|
else
|
|
{
|
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Delete Attempt {SiteId}", siteId);
|
|
}
|
|
}
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public Task<List<Module>> GetModulesAsync(int siteId, int pageId)
|
|
{
|
|
var alias = _tenantManager.GetAlias();
|
|
var modules = _cache.GetOrCreate($"modules:{alias.SiteKey}", entry =>
|
|
{
|
|
entry.SlidingExpiration = TimeSpan.FromMinutes(30);
|
|
return GetPageModules(siteId);
|
|
});
|
|
|
|
// clone object so that cache is not mutated
|
|
modules = modules.ConvertAll(module => module.Clone());
|
|
|
|
// trim modules for current page based on user permissions
|
|
var pagemodules = new List<Module>();
|
|
foreach (Module module in modules.Where(item => (item.PageId == pageId || pageId == -1) && !item.IsDeleted && _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.View, item.PermissionList)))
|
|
{
|
|
if (Utilities.IsEffectiveAndNotExpired(module.EffectiveDate, module.ExpiryDate) || _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.Edit, module.PermissionList))
|
|
{
|
|
module.Settings = module.Settings
|
|
.Where(item => !item.Value.StartsWith(_private) || _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.Edit, module.PermissionList))
|
|
.ToDictionary(setting => setting.Key, setting => setting.Value.Replace(_private, ""));
|
|
pagemodules.Add(module);
|
|
}
|
|
}
|
|
return Task.FromResult(pagemodules);
|
|
}
|
|
|
|
private List<Module> GetPageModules(int siteId)
|
|
{
|
|
List<ModuleDefinition> moduledefinitions = _moduleDefinitions.GetModuleDefinitions(siteId).ToList();
|
|
var settings = _settings.GetSettings(EntityNames.Module).ToList();
|
|
var modules = new List<Module>();
|
|
|
|
foreach (PageModule pagemodule in _pageModules.GetPageModules(siteId))
|
|
{
|
|
Module module = new Module
|
|
{
|
|
SiteId = pagemodule.Module.SiteId,
|
|
ModuleDefinitionName = pagemodule.Module.ModuleDefinitionName,
|
|
AllPages = pagemodule.Module.AllPages,
|
|
PermissionList = pagemodule.Module.PermissionList,
|
|
CreatedBy = pagemodule.Module.CreatedBy,
|
|
CreatedOn = pagemodule.Module.CreatedOn,
|
|
ModifiedBy = pagemodule.Module.ModifiedBy,
|
|
ModifiedOn = pagemodule.Module.ModifiedOn,
|
|
DeletedBy = pagemodule.DeletedBy,
|
|
DeletedOn = pagemodule.DeletedOn,
|
|
IsDeleted = pagemodule.IsDeleted,
|
|
|
|
PageModuleId = pagemodule.PageModuleId,
|
|
ModuleId = pagemodule.ModuleId,
|
|
PageId = pagemodule.PageId,
|
|
Title = pagemodule.Title,
|
|
Pane = pagemodule.Pane,
|
|
Order = pagemodule.Order,
|
|
ContainerType = pagemodule.ContainerType,
|
|
EffectiveDate = pagemodule.EffectiveDate,
|
|
ExpiryDate = pagemodule.ExpiryDate,
|
|
|
|
ModuleDefinition = _moduleDefinitions.FilterModuleDefinition(moduledefinitions.Find(item => item.ModuleDefinitionName == pagemodule.Module.ModuleDefinitionName)),
|
|
|
|
Settings = settings.Where(item => item.EntityId == pagemodule.ModuleId)
|
|
.ToDictionary(setting => setting.SettingName, setting => (setting.IsPrivate ? _private : "") + setting.SettingValue)
|
|
};
|
|
|
|
modules.Add(module);
|
|
}
|
|
|
|
return modules.OrderBy(item => item.PageId).ThenBy(item => item.Pane).ThenBy(item => item.Order).ToList();
|
|
}
|
|
|
|
[Obsolete("This method is deprecated.", false)]
|
|
public void SetAlias(Alias alias)
|
|
{
|
|
}
|
|
}
|
|
}
|