@@ -2,7 +2,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
<Version>10.0.4</Version>
|
<Version>10.1.0</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.4</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.1.0</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -12,10 +12,10 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.2" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.3" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="10.0.2" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="10.0.3" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="10.0.2" />
|
<PackageReference Include="Microsoft.Extensions.Localization" Version="10.0.3" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.2" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Oqtane.Client" Version="10.0.4" />
|
<PackageReference Include="Oqtane.Client" Version="10.1.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
@using Microsoft.AspNetCore.Components.Web
|
@using Microsoft.AspNetCore.Components.Web
|
||||||
@using Microsoft.Extensions.Localization
|
@using Microsoft.Extensions.Localization
|
||||||
@using Microsoft.JSInterop
|
@using Microsoft.JSInterop
|
||||||
|
@using Microsoft.AspNetCore.Authorization
|
||||||
|
|
||||||
@using Oqtane
|
@using Oqtane
|
||||||
@using Oqtane.Models
|
@using Oqtane.Models
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Application.Template</id>
|
<id>Oqtane.Application.Template</id>
|
||||||
<version>10.0.4</version>
|
<version>10.1.0</version>
|
||||||
<title>Oqtane Application Template For Blazor</title>
|
<title>Oqtane Application Template For Blazor</title>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
|
|||||||
@@ -22,9 +22,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="10.0.2" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="10.0.3" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.2" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="10.0.3" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.2" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Oqtane.Server" Version="10.0.4" />
|
<PackageReference Include="Oqtane.Server" Version="10.1.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
@namespace [Owner].Module.[Module]
|
@namespace [Owner].Module.[Module]
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject I[Module]Service [Module]Service
|
@inject I[Module]Service Client[Module]Service
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject IStringLocalizer<Edit> Localizer
|
@inject IStringLocalizer<Edit> Localizer
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
if (PageState.Action == "Edit")
|
if (PageState.Action == "Edit")
|
||||||
{
|
{
|
||||||
_id = Int32.Parse(PageState.QueryString["id"]);
|
_id = Int32.Parse(PageState.QueryString["id"]);
|
||||||
[Module] [Module] = await [Module]Service.Get[Module]Async(_id, ModuleState.ModuleId);
|
[Module] [Module] = await Client[Module]Service.Get[Module]Async(_id, ModuleState.ModuleId);
|
||||||
if ([Module] != null)
|
if ([Module] != null)
|
||||||
{
|
{
|
||||||
_name = [Module].Name;
|
_name = [Module].Name;
|
||||||
@@ -81,14 +81,14 @@
|
|||||||
[Module] [Module] = new [Module]();
|
[Module] [Module] = new [Module]();
|
||||||
[Module].ModuleId = ModuleState.ModuleId;
|
[Module].ModuleId = ModuleState.ModuleId;
|
||||||
[Module].Name = _name;
|
[Module].Name = _name;
|
||||||
[Module] = await [Module]Service.Add[Module]Async([Module]);
|
[Module] = await Client[Module]Service.Add[Module]Async([Module]);
|
||||||
await logger.LogInformation("[Module] Added {[Module]}", [Module]);
|
await logger.LogInformation("[Module] Added {[Module]}", [Module]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
[Module] [Module] = await [Module]Service.Get[Module]Async(_id, ModuleState.ModuleId);
|
[Module] [Module] = await Client[Module]Service.Get[Module]Async(_id, ModuleState.ModuleId);
|
||||||
[Module].Name = _name;
|
[Module].Name = _name;
|
||||||
await [Module]Service.Update[Module]Async([Module]);
|
await Client[Module]Service.Update[Module]Async([Module]);
|
||||||
await logger.LogInformation("[Module] Updated {[Module]}", [Module]);
|
await logger.LogInformation("[Module] Updated {[Module]}", [Module]);
|
||||||
}
|
}
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
@namespace [Owner].Module.[Module]
|
@namespace [Owner].Module.[Module]
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject I[Module]Service [Module]Service
|
@inject I[Module]Service Client[Module]Service
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ else
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_[Module]s = await [Module]Service.Get[Module]sAsync(ModuleState.ModuleId);
|
_[Module]s = await Client[Module]Service.Get[Module]sAsync(ModuleState.ModuleId);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -65,9 +65,9 @@ else
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await [Module]Service.Delete[Module]Async([Module].[Module]Id, ModuleState.ModuleId);
|
await Client[Module]Service.Delete[Module]Async([Module].[Module]Id, ModuleState.ModuleId);
|
||||||
await logger.LogInformation("[Module] Deleted {[Module]}", [Module]);
|
await logger.LogInformation("[Module] Deleted {[Module]}", [Module]);
|
||||||
_[Module]s = await [Module]Service.Get[Module]sAsync(ModuleState.ModuleId);
|
_[Module]s = await Client[Module]Service.Get[Module]sAsync(ModuleState.ModuleId);
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
@@ -7,22 +7,10 @@ using Oqtane.Shared;
|
|||||||
|
|
||||||
namespace [Owner].Module.[Module].Services
|
namespace [Owner].Module.[Module].Services
|
||||||
{
|
{
|
||||||
public interface I[Module]Service
|
|
||||||
|
public class Client[Module]Service : ServiceBase, I[Module]Service
|
||||||
{
|
{
|
||||||
Task<List<Models.[Module]>> Get[Module]sAsync(int ModuleId);
|
public Client[Module]Service(HttpClient http, SiteState siteState) : base(http, siteState) { }
|
||||||
|
|
||||||
Task<Models.[Module]> Get[Module]Async(int [Module]Id, int ModuleId);
|
|
||||||
|
|
||||||
Task<Models.[Module]> Add[Module]Async(Models.[Module] [Module]);
|
|
||||||
|
|
||||||
Task<Models.[Module]> Update[Module]Async(Models.[Module] [Module]);
|
|
||||||
|
|
||||||
Task Delete[Module]Async(int [Module]Id, int ModuleId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class [Module]Service : ServiceBase, I[Module]Service
|
|
||||||
{
|
|
||||||
public [Module]Service(HttpClient http, SiteState siteState) : base(http, siteState) { }
|
|
||||||
|
|
||||||
private string Apiurl => CreateApiUrl("[Module]");
|
private string Apiurl => CreateApiUrl("[Module]");
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ namespace [Owner].Module.[Module].Startup
|
|||||||
{
|
{
|
||||||
if (!services.Any(s => s.ServiceType == typeof(I[Module]Service)))
|
if (!services.Any(s => s.ServiceType == typeof(I[Module]Service)))
|
||||||
{
|
{
|
||||||
services.AddScoped<I[Module]Service, [Module]Service>();
|
services.AddScoped<I[Module]Service, Client[Module]Service>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace [Owner].Module.[Module].Services
|
||||||
|
{
|
||||||
|
public interface I[Module]Service
|
||||||
|
{
|
||||||
|
Task<List<Models.[Module]>> Get[Module]sAsync(int ModuleId);
|
||||||
|
|
||||||
|
Task<Models.[Module]> Get[Module]Async(int [Module]Id, int ModuleId);
|
||||||
|
|
||||||
|
Task<Models.[Module]> Add[Module]Async(Models.[Module] [Module]);
|
||||||
|
|
||||||
|
Task<Models.[Module]> Update[Module]Async(Models.[Module] [Module]);
|
||||||
|
|
||||||
|
Task Delete[Module]Async(int [Module]Id, int ModuleId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Oqtane.Shared" Version="10.0.4" />
|
<PackageReference Include="Oqtane.Shared" Version="10.1.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -57,6 +57,9 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||||||
services.AddScoped<ICookieConsentService, CookieConsentService>();
|
services.AddScoped<ICookieConsentService, CookieConsentService>();
|
||||||
services.AddScoped<ITimeZoneService, TimeZoneService>();
|
services.AddScoped<ITimeZoneService, TimeZoneService>();
|
||||||
services.AddScoped<IMigrationHistoryService, MigrationHistoryService>();
|
services.AddScoped<IMigrationHistoryService, MigrationHistoryService>();
|
||||||
|
services.AddScoped<ISiteGroupService, SiteGroupService>();
|
||||||
|
services.AddScoped<ISiteGroupMemberService, SiteGroupMemberService>();
|
||||||
|
services.AddScoped<ISiteTaskService, SiteTaskService>();
|
||||||
services.AddScoped<IOutputCacheService, OutputCacheService>();
|
services.AddScoped<IOutputCacheService, OutputCacheService>();
|
||||||
|
|
||||||
// providers
|
// providers
|
||||||
|
|||||||
117
Oqtane.Client/Modules/Admin/GlobalReplace/Index.razor
Normal file
117
Oqtane.Client/Modules/Admin/GlobalReplace/Index.razor
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
@namespace Oqtane.Modules.Admin.GlobalReplace
|
||||||
|
@using System.Text.Json
|
||||||
|
@inherits ModuleBase
|
||||||
|
@inject ISiteTaskService SiteTaskService
|
||||||
|
@inject IStringLocalizer<Index> Localizer
|
||||||
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="find" HelpText="Specify the content which needs to be replaced" ResourceKey="Find">Find What: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="find" class="form-control" @bind="@_find" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="replace" HelpText="Specify the replacement content" ResourceKey="Replace">Replace With: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="replace" class="form-control" @bind="@_replace" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="casesensitive" HelpText="Specify if the replacement operation should be case sensitive" ResourceKey="CaseSensitive">Match Case? </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="casesensitive" class="form-select" @bind="@_caseSensitive">
|
||||||
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="site" HelpText="Specify if site properties should be updated (ie. name, headcontent, bodycontent)" ResourceKey="Site">Site Properties? </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="site" class="form-select" @bind="@_site">
|
||||||
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="pages" HelpText="Specify if page properties should be updated (ie. name, title, headcontent, bodycontent)" ResourceKey="Pages">Page Properties? </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="pages" class="form-select" @bind="@_pages">
|
||||||
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="modules" HelpText="Specify if module properties should be updated (ie. title, header, footer)" ResourceKey="Modules">Module Properties? </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="modules" class="form-select" @bind="@_modules">
|
||||||
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="content" HelpText="Specify if module content should be updated" ResourceKey="Content">Module Content? </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="content" class="form-select" @bind="@_content">
|
||||||
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br /><br />
|
||||||
|
<ActionDialog Header="Global Replace" Message="This Operation is Permanent. Are You Sure You Wish To Proceed?" Action="Replace" Class="btn btn-primary" OnClick="@(async () => await Save())" ResourceKey="GlobalReplace" />
|
||||||
|
<br /><br />
|
||||||
|
|
||||||
|
@code {
|
||||||
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||||
|
public override string Title => "Global Replace";
|
||||||
|
|
||||||
|
private string _find;
|
||||||
|
private string _replace;
|
||||||
|
private string _caseSensitive = "True";
|
||||||
|
private string _site = "True";
|
||||||
|
private string _pages = "True";
|
||||||
|
private string _modules = "True";
|
||||||
|
private string _content = "True";
|
||||||
|
|
||||||
|
private async Task Save()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(_find) && !string.IsNullOrEmpty(_replace))
|
||||||
|
{
|
||||||
|
var replace = new GlobalReplace
|
||||||
|
{
|
||||||
|
Find = _find,
|
||||||
|
Replace = _replace,
|
||||||
|
CaseSensitive = bool.Parse(_caseSensitive),
|
||||||
|
Site = bool.Parse(_site),
|
||||||
|
Pages = bool.Parse(_pages),
|
||||||
|
Modules = bool.Parse(_modules),
|
||||||
|
Content = bool.Parse(_content)
|
||||||
|
};
|
||||||
|
|
||||||
|
var siteTask = new SiteTask(PageState.Site.SiteId, "Global Replace", "Oqtane.Infrastructure.GlobalReplaceTask, Oqtane.Server", JsonSerializer.Serialize(replace));
|
||||||
|
await SiteTaskService.AddSiteTaskAsync(siteTask);
|
||||||
|
|
||||||
|
AddModuleMessage(Localizer["Success.Save"], MessageType.Success);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Saving Global Replace Settings {Error}", ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.Save"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -46,6 +46,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
<br />
|
||||||
<Section Name="Information" ResourceKey="Information">
|
<Section Name="Information" ResourceKey="Information">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@@ -97,6 +98,12 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="fingerprint" HelpText="A unique identifier for the module's static resources. This value can be changed by clicking the Save option below (ie. cache busting)." ResourceKey="Fingerprint">Fingerprint: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="fingerprint" class="form-control" @bind="@_fingerprint" disabled />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
<br />
|
<br />
|
||||||
@@ -231,6 +238,7 @@
|
|||||||
private string _url = "";
|
private string _url = "";
|
||||||
private string _contact = "";
|
private string _contact = "";
|
||||||
private string _license = "";
|
private string _license = "";
|
||||||
|
private string _fingerprint = "";
|
||||||
private List<Permission> _permissions = null;
|
private List<Permission> _permissions = null;
|
||||||
private string _createdby;
|
private string _createdby;
|
||||||
private DateTime _createdon;
|
private DateTime _createdon;
|
||||||
@@ -266,6 +274,7 @@
|
|||||||
_url = moduleDefinition.Url;
|
_url = moduleDefinition.Url;
|
||||||
_contact = moduleDefinition.Contact;
|
_contact = moduleDefinition.Contact;
|
||||||
_license = moduleDefinition.License;
|
_license = moduleDefinition.License;
|
||||||
|
_fingerprint = moduleDefinition.Fingerprint;
|
||||||
_permissions = moduleDefinition.PermissionList;
|
_permissions = moduleDefinition.PermissionList;
|
||||||
_createdby = moduleDefinition.CreatedBy;
|
_createdby = moduleDefinition.CreatedBy;
|
||||||
_createdon = moduleDefinition.CreatedOn;
|
_createdon = moduleDefinition.CreatedOn;
|
||||||
|
|||||||
@@ -73,16 +73,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="page" HelpText="The page that the module is located on" ResourceKey="Page">Page: </Label>
|
<Label Class="col-sm-3" For="page" HelpText="The page that the module is located on. Please note that shared modules cannot be moved to other pages." ResourceKey="Page">Page: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="page" class="form-select" @bind="@_pageId" required>
|
@if (PageState.Page.UserId != null || _isShared)
|
||||||
@if (PageState.Page.UserId != null)
|
|
||||||
{
|
{
|
||||||
|
<select id="page" class="form-select" @bind="@_pageId" required disabled>
|
||||||
<option value="@PageState.Page.PageId">@(PageState.Page.Name)</option>
|
<option value="@PageState.Page.PageId">@(PageState.Page.Name)</option>
|
||||||
|
</select>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (_pages != null)
|
<select id="page" class="form-select" @bind="@_pageId" required>
|
||||||
|
@if (_pages != null)
|
||||||
{
|
{
|
||||||
foreach (Page p in _pages)
|
foreach (Page p in _pages)
|
||||||
{
|
{
|
||||||
@@ -92,8 +94,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</select>
|
</select>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -161,6 +163,7 @@
|
|||||||
private string _pane;
|
private string _pane;
|
||||||
private string _containerType;
|
private string _containerType;
|
||||||
private string _allPages = "false";
|
private string _allPages = "false";
|
||||||
|
private bool _isShared = false;
|
||||||
private string _header = "";
|
private string _header = "";
|
||||||
private string _footer = "";
|
private string _footer = "";
|
||||||
private string _permissionNames = "";
|
private string _permissionNames = "";
|
||||||
@@ -207,6 +210,7 @@
|
|||||||
_expirydate = Utilities.UtcAsLocalDate(pagemodule.ExpiryDate);
|
_expirydate = Utilities.UtcAsLocalDate(pagemodule.ExpiryDate);
|
||||||
|
|
||||||
_allPages = pagemodule.Module.AllPages.ToString();
|
_allPages = pagemodule.Module.AllPages.ToString();
|
||||||
|
_isShared = pagemodule.Module.IsShared;
|
||||||
createdby = pagemodule.Module.CreatedBy;
|
createdby = pagemodule.Module.CreatedBy;
|
||||||
createdon = pagemodule.Module.CreatedOn;
|
createdon = pagemodule.Module.CreatedOn;
|
||||||
modifiedby = pagemodule.Module.ModifiedBy;
|
modifiedby = pagemodule.Module.ModifiedBy;
|
||||||
@@ -276,7 +280,6 @@
|
|||||||
var interop = new Interop(JSRuntime);
|
var interop = new Interop(JSRuntime);
|
||||||
if (await interop.FormValid(form))
|
if (await interop.FormValid(form))
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(_title))
|
if (!string.IsNullOrEmpty(_title))
|
||||||
{
|
{
|
||||||
if (!Utilities.ValidateEffectiveExpiryDates(_effectivedate, _expirydate))
|
if (!Utilities.ValidateEffectiveExpiryDates(_effectivedate, _expirydate))
|
||||||
@@ -284,7 +287,32 @@
|
|||||||
AddModuleMessage(SharedLocalizer["Message.EffectiveExpiryDateError"], MessageType.Warning);
|
AddModuleMessage(SharedLocalizer["Message.EffectiveExpiryDateError"], MessageType.Warning);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update module settings first
|
||||||
|
if (_moduleSettingsType != null)
|
||||||
|
{
|
||||||
|
if (_moduleSettings is ISettingsControl moduleSettingsControl)
|
||||||
|
{
|
||||||
|
// module settings updated using explicit interface
|
||||||
|
await moduleSettingsControl.UpdateSettings();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// legacy support - module settings updated by convention ( ie. by calling a public method named "UpdateSettings" in settings component )
|
||||||
|
_moduleSettings?.GetType().GetMethod("UpdateSettings")?.Invoke(_moduleSettings, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update container settings
|
||||||
|
if (_containerSettingsType != null && _containerSettings is ISettingsControl containerSettingsControl)
|
||||||
|
{
|
||||||
|
await containerSettingsControl.UpdateSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
// update page module
|
||||||
var pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
|
var pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
|
||||||
|
var pageId = pagemodule.PageId; // preserve
|
||||||
|
var pane = pagemodule.Pane; // preserve
|
||||||
pagemodule.PageId = int.Parse(_pageId);
|
pagemodule.PageId = int.Parse(_pageId);
|
||||||
pagemodule.Title = _title;
|
pagemodule.Title = _title;
|
||||||
pagemodule.Pane = _pane;
|
pagemodule.Pane = _pane;
|
||||||
@@ -302,33 +330,21 @@
|
|||||||
pagemodule.Header = _header;
|
pagemodule.Header = _header;
|
||||||
pagemodule.Footer = _footer;
|
pagemodule.Footer = _footer;
|
||||||
await PageModuleService.UpdatePageModuleAsync(pagemodule);
|
await PageModuleService.UpdatePageModuleAsync(pagemodule);
|
||||||
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
|
|
||||||
|
|
||||||
|
// update page module order if page or pane changed
|
||||||
|
if (pageId != pagemodule.PageId || pane != pagemodule.Pane)
|
||||||
|
{
|
||||||
|
await PageModuleService.UpdatePageModuleOrderAsync(pageId, pane); // old page/pane
|
||||||
|
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane); // new page/pane
|
||||||
|
}
|
||||||
|
|
||||||
|
// update module
|
||||||
var module = await ModuleService.GetModuleAsync(ModuleState.ModuleId);
|
var module = await ModuleService.GetModuleAsync(ModuleState.ModuleId);
|
||||||
module.AllPages = bool.Parse(_allPages);
|
module.AllPages = bool.Parse(_allPages);
|
||||||
module.PageModuleId = ModuleState.PageModuleId;
|
module.PageModuleId = ModuleState.PageModuleId;
|
||||||
module.PermissionList = _permissionGrid.GetPermissionList();
|
module.PermissionList = _permissionGrid.GetPermissionList();
|
||||||
await ModuleService.UpdateModuleAsync(module);
|
await ModuleService.UpdateModuleAsync(module);
|
||||||
|
|
||||||
if (_moduleSettingsType != null)
|
|
||||||
{
|
|
||||||
if (_moduleSettings is ISettingsControl moduleSettingsControl)
|
|
||||||
{
|
|
||||||
// module settings updated using explicit interface
|
|
||||||
await moduleSettingsControl.UpdateSettings();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// legacy support - module settings updated by convention ( ie. by calling a public method named "UpdateSettings" in settings component )
|
|
||||||
_moduleSettings?.GetType().GetMethod("UpdateSettings")?.Invoke(_moduleSettings, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_containerSettingsType != null && _containerSettings is ISettingsControl containerSettingsControl)
|
|
||||||
{
|
|
||||||
await containerSettingsControl.UpdateSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
NavigationManager.NavigateTo(PageState.ReturnUrl);
|
NavigationManager.NavigateTo(PageState.ReturnUrl);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
<Label Class="col-sm-3" For="move" HelpText="Select the location where you would like the page to be moved in relation to other pages" ResourceKey="Move">Move: </Label>
|
<Label Class="col-sm-3" For="move" HelpText="Select the location where you would like the page to be moved in relation to other pages" ResourceKey="Move">Move: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="move" class="form-select" @bind="@_insert" required>
|
<select id="move" class="form-select" @bind="@_insert" required>
|
||||||
@if (_parentid == _currentparentid)
|
@if (_parentid == _currentparentid && !_copy)
|
||||||
{
|
{
|
||||||
<option value="="><@Localizer["ThisLocation.Keep"]></option>
|
<option value="="><@Localizer["ThisLocation.Keep"]></option>
|
||||||
}
|
}
|
||||||
@@ -225,7 +225,10 @@
|
|||||||
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
|
@if (!_copy)
|
||||||
|
{
|
||||||
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon" DeletedBy="@_deletedby" DeletedOn="@_deletedon"></AuditInfo>
|
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon" DeletedBy="@_deletedby" DeletedOn="@_deletedon"></AuditInfo>
|
||||||
|
}
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel Name="Permissions" ResourceKey="Permissions" Heading="Permissions">
|
<TabPanel Name="Permissions" ResourceKey="Permissions" Heading="Permissions">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -247,6 +250,8 @@
|
|||||||
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
||||||
</div>
|
</div>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
@if (!_copy)
|
||||||
|
{
|
||||||
<TabPanel Name="PageModules" Heading="Modules" ResourceKey="PageModules">
|
<TabPanel Name="PageModules" Heading="Modules" ResourceKey="PageModules">
|
||||||
<Pager Items="_pageModules">
|
<Pager Items="_pageModules">
|
||||||
<Header>
|
<Header>
|
||||||
@@ -272,6 +277,8 @@
|
|||||||
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
</TabStrip>
|
</TabStrip>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -349,6 +356,7 @@
|
|||||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||||
private List<Page> _pages;
|
private List<Page> _pages;
|
||||||
private int _pageId;
|
private int _pageId;
|
||||||
|
private bool _copy = false;
|
||||||
private string _name;
|
private string _name;
|
||||||
private string _currentparentid;
|
private string _currentparentid;
|
||||||
private string _parentid = "-1";
|
private string _parentid = "-1";
|
||||||
@@ -394,6 +402,10 @@
|
|||||||
{
|
{
|
||||||
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
|
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
|
||||||
_pageId = Int32.Parse(PageState.QueryString["id"]);
|
_pageId = Int32.Parse(PageState.QueryString["id"]);
|
||||||
|
if (PageState.QueryString.ContainsKey("copy"))
|
||||||
|
{
|
||||||
|
_copy = bool.Parse(PageState.QueryString["copy"]);
|
||||||
|
}
|
||||||
_page = await PageService.GetPageAsync(_pageId);
|
_page = await PageService.GetPageAsync(_pageId);
|
||||||
_icons = await SystemService.GetIconsAsync();
|
_icons = await SystemService.GetIconsAsync();
|
||||||
_iconresources = Utilities.GetFullTypeName(typeof(IconResources).AssemblyQualifiedName);
|
_iconresources = Utilities.GetFullTypeName(typeof(IconResources).AssemblyQualifiedName);
|
||||||
@@ -413,7 +425,7 @@
|
|||||||
_children = new List<Page>();
|
_children = new List<Page>();
|
||||||
foreach (Page p in _pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid, CultureInfo.InvariantCulture))))
|
foreach (Page p in _pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid, CultureInfo.InvariantCulture))))
|
||||||
{
|
{
|
||||||
if (p.PageId != _pageId && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
if ((p.PageId != _pageId || _copy) && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||||
{
|
{
|
||||||
_children.Add(p);
|
_children.Add(p);
|
||||||
}
|
}
|
||||||
@@ -440,6 +452,12 @@
|
|||||||
_expirydate = Utilities.UtcAsLocalDate(_page.ExpiryDate);
|
_expirydate = Utilities.UtcAsLocalDate(_page.ExpiryDate);
|
||||||
_ispersonalizable = _page.IsPersonalizable.ToString();
|
_ispersonalizable = _page.IsPersonalizable.ToString();
|
||||||
|
|
||||||
|
if (_copy)
|
||||||
|
{
|
||||||
|
_insert = ">";
|
||||||
|
_childid = _page.PageId;
|
||||||
|
}
|
||||||
|
|
||||||
// appearance
|
// appearance
|
||||||
_title = _page.Title;
|
_title = _page.Title;
|
||||||
_themetype = _page.ThemeType;
|
_themetype = _page.ThemeType;
|
||||||
@@ -470,6 +488,19 @@
|
|||||||
// permissions
|
// permissions
|
||||||
_permissions = _page.PermissionList;
|
_permissions = _page.PermissionList;
|
||||||
_updatemodulepermissions = "True";
|
_updatemodulepermissions = "True";
|
||||||
|
if (_copy)
|
||||||
|
{
|
||||||
|
_permissions = _page.PermissionList.Select(item => new Permission
|
||||||
|
{
|
||||||
|
SiteId = item.SiteId,
|
||||||
|
EntityName = item.EntityName,
|
||||||
|
EntityId = -1,
|
||||||
|
PermissionName = item.PermissionName,
|
||||||
|
RoleName = item.RoleName,
|
||||||
|
UserId = item.UserId,
|
||||||
|
IsAuthorized = item.IsAuthorized,
|
||||||
|
}).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
// page modules
|
// page modules
|
||||||
var modules = await ModuleService.GetModulesAsync(PageState.Site.SiteId);
|
var modules = await ModuleService.GetModulesAsync(PageState.Site.SiteId);
|
||||||
@@ -484,6 +515,13 @@
|
|||||||
_deletedon = _page.DeletedOn;
|
_deletedon = _page.DeletedOn;
|
||||||
|
|
||||||
ThemeSettings();
|
ThemeSettings();
|
||||||
|
|
||||||
|
if (_copy)
|
||||||
|
{
|
||||||
|
_name = "";
|
||||||
|
_path = "";
|
||||||
|
}
|
||||||
|
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -576,10 +614,18 @@
|
|||||||
await ScrollToPageTop();
|
await ScrollToPageTop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(_themetype) && _containertype != "-")
|
if (!string.IsNullOrEmpty(_themetype) && _containertype != "-")
|
||||||
{
|
{
|
||||||
string currentPath = _page.Path;
|
string currentPath = _page.Path;
|
||||||
|
|
||||||
|
if (_copy)
|
||||||
|
{
|
||||||
|
_page = new Page();
|
||||||
|
_page.SiteId = PageState.Site.SiteId;
|
||||||
|
currentPath = "";
|
||||||
|
}
|
||||||
|
|
||||||
_page.Name = _name;
|
_page.Name = _name;
|
||||||
|
|
||||||
if (_parentid == "-1")
|
if (_parentid == "-1")
|
||||||
@@ -635,6 +681,13 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update theme settings
|
||||||
|
if (_themeSettingsType != null && _themeSettings is ISettingsControl themeSettingsControl)
|
||||||
|
{
|
||||||
|
await themeSettingsControl.UpdateSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
// default page properties
|
||||||
if (_insert != "=")
|
if (_insert != "=")
|
||||||
{
|
{
|
||||||
Page child;
|
Page child;
|
||||||
@@ -688,7 +741,21 @@
|
|||||||
_page.UpdateModulePermissions = bool.Parse(_updatemodulepermissions);
|
_page.UpdateModulePermissions = bool.Parse(_updatemodulepermissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_copy)
|
||||||
|
{
|
||||||
|
// create page
|
||||||
|
_page = await PageService.AddPageAsync(_page);
|
||||||
|
await PageService.CopyPageAsync(_pageId, _page.PageId, bool.Parse(_updatemodulepermissions));
|
||||||
|
await logger.LogInformation("Page Added {Page}", _page);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// update page
|
||||||
_page = await PageService.UpdatePageAsync(_page);
|
_page = await PageService.UpdatePageAsync(_page);
|
||||||
|
await logger.LogInformation("Page Saved {Page}", _page);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update page order
|
||||||
await PageService.UpdatePageOrderAsync(_page.SiteId, _page.PageId, _page.ParentId);
|
await PageService.UpdatePageOrderAsync(_page.SiteId, _page.PageId, _page.ParentId);
|
||||||
if (_currentparentid == string.Empty)
|
if (_currentparentid == string.Empty)
|
||||||
{
|
{
|
||||||
@@ -699,12 +766,6 @@
|
|||||||
await PageService.UpdatePageOrderAsync(_page.SiteId, _page.PageId, int.Parse(_currentparentid));
|
await PageService.UpdatePageOrderAsync(_page.SiteId, _page.PageId, int.Parse(_currentparentid));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_themeSettingsType != null && _themeSettings is ISettingsControl themeSettingsControl)
|
|
||||||
{
|
|
||||||
await themeSettingsControl.UpdateSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
await logger.LogInformation("Page Saved {Page}", _page);
|
|
||||||
if (!string.IsNullOrEmpty(PageState.ReturnUrl))
|
if (!string.IsNullOrEmpty(PageState.ReturnUrl))
|
||||||
{
|
{
|
||||||
NavigationManager.NavigateTo(PageState.ReturnUrl, true); // redirect to page being edited and reload
|
NavigationManager.NavigateTo(PageState.ReturnUrl, true); // redirect to page being edited and reload
|
||||||
|
|||||||
@@ -3,10 +3,11 @@
|
|||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject IUserService UserService
|
@inject IUserService UserService
|
||||||
@inject IStringLocalizer<Index> Localizer
|
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
|
||||||
@inject ISettingService SettingService
|
@inject ISettingService SettingService
|
||||||
@inject ITimeZoneService TimeZoneService
|
@inject ITimeZoneService TimeZoneService
|
||||||
|
@inject ILanguageService LanguageService
|
||||||
|
@inject IStringLocalizer<Index> Localizer
|
||||||
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
@if (_initialized)
|
@if (_initialized)
|
||||||
{
|
{
|
||||||
@@ -71,6 +72,18 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="culture" HelpText="Your preferred language. Note that you will only be able to choose from languages supported on this site." ResourceKey="CultureCode">Language:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="culture" class="form-select" @bind="@_culturecode">
|
||||||
|
<option value=""><@SharedLocalizer["Not Specified"]></option>
|
||||||
|
@foreach (var language in _languages)
|
||||||
|
{
|
||||||
|
<option value="@language.Code">@language.Name</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<button type="button" class="btn btn-primary" @onclick="Register">@Localizer["Register"]</button>
|
<button type="button" class="btn btn-primary" @onclick="Register">@Localizer["Register"]</button>
|
||||||
@@ -95,6 +108,8 @@
|
|||||||
@code {
|
@code {
|
||||||
private bool _initialized = false;
|
private bool _initialized = false;
|
||||||
private List<Models.TimeZone> _timezones;
|
private List<Models.TimeZone> _timezones;
|
||||||
|
private IEnumerable<Models.Language> _languages;
|
||||||
|
|
||||||
private string _passwordrequirements;
|
private string _passwordrequirements;
|
||||||
private string _username = string.Empty;
|
private string _username = string.Empty;
|
||||||
private ElementReference form;
|
private ElementReference form;
|
||||||
@@ -106,6 +121,7 @@
|
|||||||
private string _email = string.Empty;
|
private string _email = string.Empty;
|
||||||
private string _displayname = string.Empty;
|
private string _displayname = string.Empty;
|
||||||
private string _timezoneid = string.Empty;
|
private string _timezoneid = string.Empty;
|
||||||
|
private string _culturecode = string.Empty;
|
||||||
private bool _userCreated = false;
|
private bool _userCreated = false;
|
||||||
private bool _allowsitelogin = true;
|
private bool _allowsitelogin = true;
|
||||||
|
|
||||||
@@ -113,10 +129,13 @@
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
|
_timezones = TimeZoneService.GetTimeZones();
|
||||||
|
_languages = await LanguageService.GetLanguagesAsync(PageState.Site.SiteId);
|
||||||
|
|
||||||
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
|
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
|
||||||
_allowsitelogin = bool.Parse(SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:AllowSiteLogin", "true"));
|
_allowsitelogin = bool.Parse(SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:AllowSiteLogin", "true"));
|
||||||
_timezones = TimeZoneService.GetTimeZones();
|
|
||||||
_timezoneid = PageState.Site.TimeZoneId;
|
_timezoneid = PageState.Site.TimeZoneId;
|
||||||
|
_culturecode = PageState.Site.CultureCode;
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,6 +166,7 @@
|
|||||||
Email = _email,
|
Email = _email,
|
||||||
DisplayName = (_displayname == string.Empty ? _username : _displayname),
|
DisplayName = (_displayname == string.Empty ? _username : _displayname),
|
||||||
TimeZoneId = _timezoneid,
|
TimeZoneId = _timezoneid,
|
||||||
|
CultureCode = _culturecode,
|
||||||
PhotoFileId = null
|
PhotoFileId = null
|
||||||
};
|
};
|
||||||
user = await UserService.AddUserAsync(user);
|
user = await UserService.AddUserAsync(user);
|
||||||
|
|||||||
@@ -11,12 +11,15 @@
|
|||||||
@inject IThemeService ThemeService
|
@inject IThemeService ThemeService
|
||||||
@inject ISettingService SettingService
|
@inject ISettingService SettingService
|
||||||
@inject ITimeZoneService TimeZoneService
|
@inject ITimeZoneService TimeZoneService
|
||||||
|
@inject ILocalizationService LocalizationService
|
||||||
@inject IServiceProvider ServiceProvider
|
@inject IServiceProvider ServiceProvider
|
||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
@inject INotificationService NotificationService
|
@inject INotificationService NotificationService
|
||||||
@inject IJobService JobService
|
@inject IJobService JobService
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
@inject IOutputCacheService CacheService
|
@inject IOutputCacheService CacheService
|
||||||
|
@inject ISiteGroupService SiteGroupService
|
||||||
|
@inject ISiteGroupMemberService SiteGroupMemberService
|
||||||
|
|
||||||
@if (_initialized)
|
@if (_initialized)
|
||||||
{
|
{
|
||||||
@@ -29,22 +32,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="homepage" HelpText="Select the home page for the site (to be used if there is no page with a path of '/')" ResourceKey="HomePage">Home Page: </Label>
|
<Label Class="col-sm-3" For="timezone" HelpText="The default time zone for the site" ResourceKey="TimeZone">Time Zone:</Label>
|
||||||
<div class="col-sm-9">
|
|
||||||
<select id="homepage" class="form-select" @bind="@_homepageid" required>
|
|
||||||
<option value="-"><@SharedLocalizer["Not Specified"]></option>
|
|
||||||
@foreach (Page page in _pages)
|
|
||||||
{
|
|
||||||
if (UserSecurity.ContainsRole(page.PermissionList, PermissionNames.View, RoleNames.Everyone))
|
|
||||||
{
|
|
||||||
<option value="@(page.PageId)">@(new string('-', page.Level * 2))@(page.Name)</option>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="timezone" HelpText="Your time zone" ResourceKey="TimeZone">Time Zone:</Label>
|
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="timezone" class="form-select" @bind="@_timezoneid">
|
<select id="timezone" class="form-select" @bind="@_timezoneid">
|
||||||
<option value=""><@SharedLocalizer["Not Specified"]></option>
|
<option value=""><@SharedLocalizer["Not Specified"]></option>
|
||||||
@@ -55,6 +43,18 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="culture" HelpText="The default language of the site's content" ResourceKey="Culture">Language:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="culture" class="form-select" @bind="@_culturecode">
|
||||||
|
<option value=""><@SharedLocalizer["Not Specified"]></option>
|
||||||
|
@foreach (var culture in _cultures)
|
||||||
|
{
|
||||||
|
<option value="@culture.Name">@culture.DisplayName</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
{
|
{
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@@ -333,57 +333,6 @@
|
|||||||
</Section>
|
</Section>
|
||||||
@if (_aliases != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
@if (_aliases != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
{
|
{
|
||||||
<Section Name="Aliases" Heading="Aliases" ResourceKey="Aliases">
|
|
||||||
<div class="container">
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="aliases" HelpText="The urls for the site. This can include domain names (ie. domain.com), subdomains (ie. sub.domain.com) or virtual folders (ie. domain.com/folder)." ResourceKey="Aliases">Aliases: </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<button type="button" class="btn btn-primary" @onclick="AddAlias">@SharedLocalizer["Add"]</button>
|
|
||||||
<Pager Items="@_aliases">
|
|
||||||
<Header>
|
|
||||||
<th style="width: 1px;"> </th>
|
|
||||||
<th style="width: 1px;"> </th>
|
|
||||||
<th>@Localizer["AliasName"]</th>
|
|
||||||
<th>@Localizer["AliasDefault"]</th>
|
|
||||||
</Header>
|
|
||||||
<Row>
|
|
||||||
@if (context.AliasId != _aliasid)
|
|
||||||
{
|
|
||||||
<td>
|
|
||||||
@if (_aliasid == -1)
|
|
||||||
{
|
|
||||||
<button type="button" class="btn btn-primary" @onclick="@(() => EditAlias(context))">@SharedLocalizer["Edit"]</button>
|
|
||||||
}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
@if (_aliasid == -1)
|
|
||||||
{
|
|
||||||
<ActionDialog Action="Delete" OnClick="@(async () => await DeleteAlias(context))" ResourceKey="DeleteAlias" Class="btn btn-danger" Header="Delete Alias" Message="@string.Format(Localizer["Confirm.Alias.Delete", context.Name])" />
|
|
||||||
}
|
|
||||||
</td>
|
|
||||||
<td>@context.Name</td>
|
|
||||||
<td>@((context.IsDefault) ? SharedLocalizer["Yes"] : SharedLocalizer["No"])</td>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<td><button type="button" class="btn btn-success" @onclick="@(async () => await SaveAlias())">@SharedLocalizer["Save"]</button></td>
|
|
||||||
<td><button type="button" class="btn btn-secondary" @onclick="@(async () => await CancelAlias())">@SharedLocalizer["Cancel"]</button></td>
|
|
||||||
<td>
|
|
||||||
<input id="aliasname" class="form-control" @bind="@_aliasname" />
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<select id="defaultalias" class="form-select" @bind="@_defaultalias" required>
|
|
||||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
|
||||||
<option value="False">@SharedLocalizer["No"]</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
}
|
|
||||||
</Row>
|
|
||||||
</Pager>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Section>
|
|
||||||
<Section Name="Hosting" Heading="Hosting Model" ResourceKey="Hosting">
|
<Section Name="Hosting" Heading="Hosting Model" ResourceKey="Hosting">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@@ -409,7 +358,7 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="runtime" HelpText="The render mode for UI components which require interactivity" ResourceKey="Runtime">Interactivity: </Label>
|
<Label Class="col-sm-3" For="runtime" HelpText="The hosting model for UI components which require interactivity" ResourceKey="Runtime">Interactivity: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="runtime" class="form-select" @bind="@_runtime" required>
|
<select id="runtime" class="form-select" @bind="@_runtime" required>
|
||||||
<option value="@Runtimes.Server">@(SharedLocalizer["Runtime" + @Runtimes.Server])</option>
|
<option value="@Runtimes.Server">@(SharedLocalizer["Runtime" + @Runtimes.Server])</option>
|
||||||
@@ -438,6 +387,180 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
|
<Section Name="Aliases" Heading="Urls" ResourceKey="Aliases">
|
||||||
|
<div class="container">
|
||||||
|
@if (!_addAlias)
|
||||||
|
{
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="aliases" HelpText="The urls for this site. This can include domain names (ie. domain.com), subdomains (ie. sub.domain.com) or virtual folders (ie. domain.com/folder)." ResourceKey="Aliases">Urls: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<div class="input-group">
|
||||||
|
<select id="aliases" class="form-select" value="@_aliasid" @onchange="(e => AliasChanged(e))">
|
||||||
|
<option value="-1"><@SharedLocalizer["Not Specified"]></option>
|
||||||
|
@foreach (var alias in _aliases)
|
||||||
|
{
|
||||||
|
<option value="@alias.AliasId">@alias.Name @((alias.IsDefault) ? "(" + Localizer["Default"] + ")" : "")</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
@if (!_addAlias)
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-primary" @onclick="AddAlias">@SharedLocalizer["Add"]</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (_aliasid != -1 || _addAlias)
|
||||||
|
{
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="aliasname" HelpText="A url for this site. This can include domain names (ie. domain.com), subdomains (ie. sub.domain.com) or virtual folders (ie. domain.com/folder)." ResourceKey="AliasName">Url: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="aliasname" class="form-control" @bind="@_aliasname" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="defaultalias" HelpText="The default alias for the site. Requests for non-default aliases will be redirected to the default alias." ResourceKey="DefaultAlias">Default? </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="defaultalias" class="form-select" @bind="@_defaultalias">
|
||||||
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
}
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<div class="col-sm-3"></div>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
@if (_aliasid != -1 || _addAlias)
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-success me-2" @onclick="SaveAlias">@SharedLocalizer["Save"]</button>
|
||||||
|
}
|
||||||
|
@if (_aliasid != -1 && !_addAlias)
|
||||||
|
{
|
||||||
|
<ActionDialog Action="Delete" OnClick="@(async () => await DeleteAlias())" ResourceKey="DeleteAlias" Class="btn btn-danger" Header="Delete Alias" Message="@string.Format(Localizer["Confirm.Alias.Delete", _aliasname])" />
|
||||||
|
}
|
||||||
|
@if (_addAlias)
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="CancelAlias">@SharedLocalizer["Cancel"]</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
<Section Name="SiteGroupMembers" Heading="Site Groups" ResourceKey="SiteGroupMembers">
|
||||||
|
<div class="container">
|
||||||
|
@if (!_addSiteGroup)
|
||||||
|
{
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="group" HelpText="The site groups in this tenant (database)" ResourceKey="SiteGroupMembers">Group: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<div class="input-group">
|
||||||
|
<select id="group" class="form-select" value="@_siteGroupId" @onchange="(e => SiteGroupChanged(e))">
|
||||||
|
<option value="-1"><@SharedLocalizer["Not Specified"]></option>
|
||||||
|
@foreach (var siteGroup in _siteGroups)
|
||||||
|
{
|
||||||
|
<option value="@siteGroup.SiteGroupId">@siteGroup.Name</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
@if (!_addSiteGroup)
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-primary" @onclick="AddSiteGroup">@SharedLocalizer["Add"]</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (_siteGroupId != -1 || _addSiteGroup)
|
||||||
|
{
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="groupname" HelpText="Name of the site group" ResourceKey="GroupName">Name: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="groupname" class="form-control" @bind="@_groupName" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="grouptype" HelpText="Defines the specific behavior of the site group" ResourceKey="GroupType">Type: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="grouptype" class="form-select" @bind="@_groupType">
|
||||||
|
<option value="@SiteGroupTypes.Synchronization">@Localizer[@SiteGroupTypes.Synchronization]</option>
|
||||||
|
<option value="@SiteGroupTypes.ChangeDetection">@Localizer[@SiteGroupTypes.ChangeDetection]</option>
|
||||||
|
<option value="@SiteGroupTypes.Localization">@Localizer[SiteGroupTypes.Localization]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (_siteGroupId != -1)
|
||||||
|
{
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="site" HelpText="The sites which are members of this site group" ResourceKey="Site">Members: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<div class="input-group">
|
||||||
|
<select id="site" class="form-select" value="@_siteId" @onchange="(e => SiteChanged(e))">
|
||||||
|
<option value="-1"><@SharedLocalizer["Not Specified"]></option>
|
||||||
|
@foreach (var site in _sites)
|
||||||
|
{
|
||||||
|
<option value="@site.SiteId">@site.Name</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
@if (!_addSiteGroupMember)
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-primary" @onclick="AddSiteGroupMember">@SharedLocalizer["Add"]</button>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-primary" @onclick="AddSiteGroupMember">@SharedLocalizer["Select"]</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (_siteGroupId != -1 && _siteId != -1)
|
||||||
|
{
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="primary" HelpText="Indicates if the selected member is the primary site of the site group" ResourceKey="Primary">Primary? </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="primary" class="form-select" @bind="@_primary">
|
||||||
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if (_primary == "False" && !string.IsNullOrEmpty(_synchronized) && (_groupType == SiteGroupTypes.Synchronization || _groupType == SiteGroupTypes.ChangeDetection))
|
||||||
|
{
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="synchronized" HelpText="The date/time when the site was last synchronized" ResourceKey="Synchronized">Synchronized: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<div class="input-group">
|
||||||
|
<input id="synchronized" class="form-control" @bind="@_synchronized" disabled />
|
||||||
|
@if (!string.IsNullOrEmpty(_synchronized))
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-primary" @onclick="ResetSiteGroupMember">@SharedLocalizer["Reset"]</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<div class="col-sm-3"></div>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
@if ((_siteGroupId != -1 || _addSiteGroup))
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-success me-2" @onclick="SaveSiteGroupMember">@SharedLocalizer["Save"]</button>
|
||||||
|
}
|
||||||
|
@if (_siteGroupId != -1 && !_addSiteGroup && _siteId != -1 && !_addSiteGroupMember)
|
||||||
|
{
|
||||||
|
<ActionDialog Action="Delete" OnClick="@(async () => await DeleteSiteGroupMember())" ResourceKey="DeleteSiteGroupMember" Class="btn btn-danger" Header="Delete Site Group" Message="@Localizer["Confirm.SiteGroupMember.Delete"]" />
|
||||||
|
}
|
||||||
|
@if (_addSiteGroup)
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="CancelSiteGroupMember">@SharedLocalizer["Cancel"]</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
<Section Name="TenantInformation" Heading="Database" ResourceKey="TenantInformation">
|
<Section Name="TenantInformation" Heading="Database" ResourceKey="TenantInformation">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@@ -478,10 +601,11 @@
|
|||||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||||
private List<Page> _pages;
|
private List<Page> _pages;
|
||||||
private List<Models.TimeZone> _timezones;
|
private List<Models.TimeZone> _timezones;
|
||||||
|
private IEnumerable<Models.Culture> _cultures;
|
||||||
|
|
||||||
private string _name = string.Empty;
|
private string _name = string.Empty;
|
||||||
private string _homepageid = "-";
|
|
||||||
private string _timezoneid = string.Empty;
|
private string _timezoneid = string.Empty;
|
||||||
|
private string _culturecode = string.Empty;
|
||||||
private string _isdeleted;
|
private string _isdeleted;
|
||||||
private string _sitemap = "";
|
private string _sitemap = "";
|
||||||
private string _siteguid = "";
|
private string _siteguid = "";
|
||||||
@@ -527,17 +651,29 @@
|
|||||||
private int _pwasplashiconfileid = -1;
|
private int _pwasplashiconfileid = -1;
|
||||||
private FileManager _pwasplashiconfilemanager;
|
private FileManager _pwasplashiconfilemanager;
|
||||||
|
|
||||||
private List<Alias> _aliases;
|
|
||||||
private int _aliasid = -1;
|
|
||||||
private string _aliasname;
|
|
||||||
private string _defaultalias;
|
|
||||||
|
|
||||||
private string _rendermode = RenderModes.Interactive;
|
private string _rendermode = RenderModes.Interactive;
|
||||||
private string _enhancednavigation = "True";
|
private string _enhancednavigation = "True";
|
||||||
private string _runtime = Runtimes.Server;
|
private string _runtime = Runtimes.Server;
|
||||||
private string _prerender = "True";
|
private string _prerender = "True";
|
||||||
private string _hybrid = "False";
|
private string _hybrid = "False";
|
||||||
|
|
||||||
|
private List<Alias> _aliases;
|
||||||
|
private int _aliasid = -1;
|
||||||
|
private string _aliasname;
|
||||||
|
private string _defaultalias;
|
||||||
|
private bool _addAlias = false;
|
||||||
|
|
||||||
|
private List<SiteGroup> _siteGroups = new List<SiteGroup>();
|
||||||
|
private List<Site> _sites = new List<Site>();
|
||||||
|
private int _siteGroupId = -1;
|
||||||
|
private int _siteId;
|
||||||
|
private string _groupName = string.Empty;
|
||||||
|
private string _groupType = SiteGroupTypes.Synchronization;
|
||||||
|
private string _primary = "True";
|
||||||
|
private string _synchronized = string.Empty;
|
||||||
|
private bool _addSiteGroup = false;
|
||||||
|
private bool _addSiteGroupMember = false;
|
||||||
|
|
||||||
private string _tenant = string.Empty;
|
private string _tenant = string.Empty;
|
||||||
private string _database = string.Empty;
|
private string _database = string.Empty;
|
||||||
private string _connectionstring = string.Empty;
|
private string _connectionstring = string.Empty;
|
||||||
@@ -564,16 +700,14 @@
|
|||||||
if (site != null)
|
if (site != null)
|
||||||
{
|
{
|
||||||
_timezones = TimeZoneService.GetTimeZones();
|
_timezones = TimeZoneService.GetTimeZones();
|
||||||
|
_cultures = await LocalizationService.GetNeutralCulturesAsync();
|
||||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||||
|
|
||||||
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
|
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
|
||||||
|
|
||||||
_name = site.Name;
|
_name = site.Name;
|
||||||
_timezoneid = site.TimeZoneId;
|
_timezoneid = site.TimeZoneId;
|
||||||
if (site.HomePageId != null)
|
_culturecode = site.CultureCode;
|
||||||
{
|
|
||||||
_homepageid = site.HomePageId.Value.ToString();
|
|
||||||
}
|
|
||||||
_isdeleted = site.IsDeleted.ToString();
|
_isdeleted = site.IsDeleted.ToString();
|
||||||
_sitemap = PageState.Alias.Protocol + PageState.Alias.Name + "/sitemap.xml";
|
_sitemap = PageState.Alias.Protocol + PageState.Alias.Name + "/sitemap.xml";
|
||||||
_siteguid = site.SiteGuid;
|
_siteguid = site.SiteGuid;
|
||||||
@@ -652,7 +786,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// aliases
|
// aliases
|
||||||
await GetAliases();
|
await LoadAliases();
|
||||||
|
|
||||||
// hosting model
|
// hosting model
|
||||||
_rendermode = site.RenderMode;
|
_rendermode = site.RenderMode;
|
||||||
@@ -676,6 +810,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// site groups
|
||||||
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
|
{
|
||||||
|
await LoadSiteGroups();
|
||||||
|
}
|
||||||
|
|
||||||
// audit
|
// audit
|
||||||
_createdby = site.CreatedBy;
|
_createdby = site.CreatedBy;
|
||||||
_createdon = site.CreatedOn;
|
_createdon = site.CreatedOn;
|
||||||
@@ -743,7 +883,7 @@
|
|||||||
{
|
{
|
||||||
site.Name = _name;
|
site.Name = _name;
|
||||||
site.TimeZoneId = _timezoneid;
|
site.TimeZoneId = _timezoneid;
|
||||||
site.HomePageId = (_homepageid != "-" ? int.Parse(_homepageid) : null);
|
site.CultureCode = _culturecode;
|
||||||
site.IsDeleted = (_isdeleted == null ? true : Boolean.Parse(_isdeleted));
|
site.IsDeleted = (_isdeleted == null ? true : Boolean.Parse(_isdeleted));
|
||||||
|
|
||||||
// appearance
|
// appearance
|
||||||
@@ -992,45 +1132,51 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task GetAliases()
|
private async Task LoadAliases()
|
||||||
{
|
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
|
||||||
{
|
{
|
||||||
_aliases = await AliasService.GetAliasesAsync();
|
_aliases = await AliasService.GetAliasesAsync();
|
||||||
_aliases = _aliases.Where(item => item.SiteId == PageState.Site.SiteId && item.TenantId == PageState.Alias.TenantId).OrderBy(item => item.AliasId).ToList();
|
_aliases = _aliases.Where(item => item.SiteId == PageState.Site.SiteId && item.TenantId == PageState.Alias.TenantId).OrderBy(item => item.AliasId).ToList();
|
||||||
|
_aliasid = -1;
|
||||||
|
_addAlias = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void AliasChanged(ChangeEventArgs e)
|
||||||
|
{
|
||||||
|
_aliasid = int.Parse(e.Value.ToString());
|
||||||
|
if (_aliasid != -1)
|
||||||
|
{
|
||||||
|
var alias = _aliases.FirstOrDefault(item => item.AliasId == _aliasid);
|
||||||
|
if (alias != null)
|
||||||
|
{
|
||||||
|
_aliasname = alias.Name;
|
||||||
|
_defaultalias = alias.IsDefault.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_aliasname = "";
|
||||||
|
_defaultalias = "False";
|
||||||
|
}
|
||||||
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddAlias()
|
private void AddAlias()
|
||||||
{
|
{
|
||||||
_aliases.Add(new Alias { AliasId = 0, Name = "", IsDefault = false });
|
_aliasid = -1;
|
||||||
_aliasid = 0;
|
|
||||||
_aliasname = "";
|
_aliasname = "";
|
||||||
_defaultalias = "False";
|
_defaultalias = "False";
|
||||||
|
_addAlias = true;
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EditAlias(Alias alias)
|
private async Task DeleteAlias()
|
||||||
{
|
{
|
||||||
_aliasid = alias.AliasId;
|
await AliasService.DeleteAliasAsync(_aliasid);
|
||||||
_aliasname = alias.Name;
|
await LoadAliases();
|
||||||
_defaultalias = alias.IsDefault.ToString();
|
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DeleteAlias(Alias alias)
|
|
||||||
{
|
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
|
||||||
{
|
|
||||||
await AliasService.DeleteAliasAsync(alias.AliasId);
|
|
||||||
await GetAliases();
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SaveAlias()
|
private async Task SaveAlias()
|
||||||
{
|
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(_aliasname))
|
if (!string.IsNullOrEmpty(_aliasname))
|
||||||
{
|
{
|
||||||
@@ -1064,7 +1210,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await GetAliases();
|
await LoadAliases();
|
||||||
_aliasid = -1;
|
_aliasid = -1;
|
||||||
_aliasname = "";
|
_aliasname = "";
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
@@ -1076,11 +1222,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private async Task CancelAlias()
|
private async Task CancelAlias()
|
||||||
{
|
{
|
||||||
await GetAliases();
|
await LoadAliases();
|
||||||
_aliasid = -1;
|
_aliasid = -1;
|
||||||
_aliasname = "";
|
_aliasname = "";
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
@@ -1090,4 +1235,202 @@
|
|||||||
await CacheService.EvictByTag(Constants.SitemapOutputCacheTag);
|
await CacheService.EvictByTag(Constants.SitemapOutputCacheTag);
|
||||||
AddModuleMessage(Localizer["Success.SiteMap.CacheEvicted"], MessageType.Success);
|
AddModuleMessage(Localizer["Success.SiteMap.CacheEvicted"], MessageType.Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task LoadSiteGroups()
|
||||||
|
{
|
||||||
|
_siteGroups = await SiteGroupService.GetSiteGroupsAsync();
|
||||||
|
_siteGroupId = -1;
|
||||||
|
_addSiteGroup = false;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SiteGroupChanged(ChangeEventArgs e)
|
||||||
|
{
|
||||||
|
_siteGroupId = int.Parse(e.Value.ToString());
|
||||||
|
if (_siteGroupId != -1)
|
||||||
|
{
|
||||||
|
var group = _siteGroups.FirstOrDefault(item => item.SiteGroupId == _siteGroupId);
|
||||||
|
if (group != null)
|
||||||
|
{
|
||||||
|
_groupName = group.Name;
|
||||||
|
_groupType = group.Type;
|
||||||
|
_siteId = -1;
|
||||||
|
_primary = "False";
|
||||||
|
_addSiteGroupMember = false;
|
||||||
|
|
||||||
|
await LoadSites();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadSites()
|
||||||
|
{
|
||||||
|
var siteGroupMembers = await SiteGroupMemberService.GetSiteGroupMembersAsync(-1, _siteGroupId);
|
||||||
|
|
||||||
|
_sites = await SiteService.GetSitesAsync();
|
||||||
|
if (_addSiteGroupMember)
|
||||||
|
{
|
||||||
|
// include sites which are not members
|
||||||
|
_sites = _sites.ExceptBy(siteGroupMembers.Select(item => item.SiteId), item => item.SiteId).ToList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// include sites which are members
|
||||||
|
_sites = _sites.Where(item => siteGroupMembers.Any(item2 => item2.SiteId == item.SiteId)).ToList();
|
||||||
|
var group = _siteGroups.FirstOrDefault(item => item.SiteGroupId == _siteGroupId);
|
||||||
|
foreach (var site in _sites)
|
||||||
|
{
|
||||||
|
if (group.PrimarySiteId == site.SiteId)
|
||||||
|
{
|
||||||
|
site.Name += $" ({Localizer["Primary"]})";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
site.Name += $" ({Localizer["Secondary"]})";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var siteGroupMember = siteGroupMembers.FirstOrDefault(item => item.SiteId == _siteId);
|
||||||
|
if (siteGroupMember != null)
|
||||||
|
{
|
||||||
|
_primary = (siteGroupMember.SiteGroup.PrimarySiteId == _siteId) ? "True" : "False";
|
||||||
|
_synchronized = UtcToLocal(siteGroupMember.SynchronizedOn).ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SiteChanged(ChangeEventArgs e)
|
||||||
|
{
|
||||||
|
_siteId = int.Parse(e.Value.ToString());
|
||||||
|
var siteGroupMember = await SiteGroupMemberService.GetSiteGroupMemberAsync(_siteId, _siteGroupId);
|
||||||
|
if (siteGroupMember != null)
|
||||||
|
{
|
||||||
|
_primary = (siteGroupMember.SiteGroup.PrimarySiteId == _siteId) ? "True" : "False";
|
||||||
|
_synchronized = UtcToLocal(siteGroupMember.SynchronizedOn).ToString();
|
||||||
|
}
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task AddSiteGroup()
|
||||||
|
{
|
||||||
|
_groupName = "";
|
||||||
|
_siteId = PageState.Site.SiteId;
|
||||||
|
_primary = "True";
|
||||||
|
_synchronized = "";
|
||||||
|
_addSiteGroup = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task AddSiteGroupMember()
|
||||||
|
{
|
||||||
|
_addSiteGroupMember = !_addSiteGroupMember;
|
||||||
|
_siteId = -1;
|
||||||
|
await LoadSites();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SaveSiteGroupMember()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_groupName))
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.Required.GroupName"], MessageType.Warning);
|
||||||
|
await ScrollToPageTop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SiteGroup siteGroup = null;
|
||||||
|
|
||||||
|
if (_siteGroupId == -1)
|
||||||
|
{
|
||||||
|
siteGroup = new SiteGroup
|
||||||
|
{
|
||||||
|
Name = _groupName,
|
||||||
|
Type = _groupType,
|
||||||
|
PrimarySiteId = _siteId,
|
||||||
|
Synchronize = false
|
||||||
|
};
|
||||||
|
siteGroup = await SiteGroupService.AddSiteGroupAsync(siteGroup);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
siteGroup = _siteGroups.FirstOrDefault(item => item.SiteGroupId == _siteGroupId);
|
||||||
|
if (siteGroup != null)
|
||||||
|
{
|
||||||
|
siteGroup.Name = _groupName;
|
||||||
|
siteGroup.Type = _groupType;
|
||||||
|
siteGroup.PrimarySiteId = (_primary == "True") ? _siteId : siteGroup.PrimarySiteId;
|
||||||
|
siteGroup = await SiteGroupService.UpdateSiteGroupAsync(siteGroup);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
siteGroup = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (siteGroup != null)
|
||||||
|
{
|
||||||
|
if (_siteId != -1)
|
||||||
|
{
|
||||||
|
var siteGroupMember = await SiteGroupMemberService.GetSiteGroupMemberAsync(_siteId, siteGroup.SiteGroupId);
|
||||||
|
if (siteGroupMember == null)
|
||||||
|
{
|
||||||
|
siteGroupMember = new SiteGroupMember
|
||||||
|
{
|
||||||
|
SiteGroupId = siteGroup.SiteGroupId,
|
||||||
|
SiteId = _siteId
|
||||||
|
};
|
||||||
|
await SiteGroupMemberService.AddSiteGroupMemberAsync(siteGroupMember);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
siteGroupMember.SynchronizedOn = string.IsNullOrEmpty(_synchronized) ? null : siteGroupMember.SynchronizedOn;
|
||||||
|
await SiteGroupMemberService.UpdateSiteGroupMemberAsync(siteGroupMember);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (siteGroup.Type == SiteGroupTypes.Synchronization)
|
||||||
|
{
|
||||||
|
// enable synchronization job if it is not enabled already
|
||||||
|
var jobs = await JobService.GetJobsAsync();
|
||||||
|
var job = jobs.FirstOrDefault(item => item.JobType == "Oqtane.Infrastructure.SynchronizationJob, Oqtane.Server");
|
||||||
|
if (job != null && !job.IsEnabled)
|
||||||
|
{
|
||||||
|
job.IsEnabled = true;
|
||||||
|
await JobService.UpdateJobAsync(job);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await LoadSiteGroups();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CancelSiteGroupMember()
|
||||||
|
{
|
||||||
|
_groupName = "";
|
||||||
|
await LoadSiteGroups();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DeleteSiteGroupMember()
|
||||||
|
{
|
||||||
|
if (_siteGroupId != -1)
|
||||||
|
{
|
||||||
|
var siteGroupMember = await SiteGroupMemberService.GetSiteGroupMemberAsync(PageState.Site.SiteId, _siteGroupId);
|
||||||
|
if (siteGroupMember != null)
|
||||||
|
{
|
||||||
|
await SiteGroupMemberService.DeleteSiteGroupMemberAsync(siteGroupMember.SiteGroupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
var siteGroupMembers = await SiteGroupMemberService.GetSiteGroupMembersAsync(-1, _siteGroupId);
|
||||||
|
if (!siteGroupMembers.Any())
|
||||||
|
{
|
||||||
|
await SiteGroupService.DeleteSiteGroupAsync(_siteGroupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
await LoadSiteGroups();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ResetSiteGroupMember()
|
||||||
|
{
|
||||||
|
_synchronized = "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
@inject ITenantService TenantService
|
@inject ITenantService TenantService
|
||||||
@inject IAliasService AliasService
|
@inject IAliasService AliasService
|
||||||
@inject ISiteService SiteService
|
@inject ISiteService SiteService
|
||||||
@inject IThemeService ThemeService
|
|
||||||
@inject ISiteTemplateService SiteTemplateService
|
@inject ISiteTemplateService SiteTemplateService
|
||||||
@inject IUserService UserService
|
@inject IUserService UserService
|
||||||
@inject IInstallationService InstallationService
|
@inject IInstallationService InstallationService
|
||||||
@@ -29,33 +28,9 @@ else
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="alias" HelpText="The urls for the site (comman delimited). This can include domain names (ie. domain.com), subdomains (ie. sub.domain.com) or virtual folders (ie. domain.com/folder)." ResourceKey="Aliases">Urls: </Label>
|
<Label Class="col-sm-3" For="alias" HelpText="The primary url for the site. This can be a domain name (ie. domain.com), subdomain (ie. sub.domain.com) or a virtual folder (ie. domain.com/folder)." ResourceKey="Aliases">Url: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<textarea id="alias" class="form-control" @bind="@_urls" rows="3" required></textarea>
|
<input id="alias" class="form-control" @bind="@_urls" required></input>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="defaultTheme" HelpText="Select the default theme for the website" ResourceKey="DefaultTheme">Default Theme: </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<select id="defaultTheme" class="form-select" value="@_themetype" @onchange="(e => ThemeChanged(e))" required>
|
|
||||||
<option value="-"><@Localizer["Theme.Select"]></option>
|
|
||||||
@foreach (var theme in _themes)
|
|
||||||
{
|
|
||||||
<option value="@theme.TypeName">@theme.Name</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="defaultContainer" HelpText="Select the default container for the site" ResourceKey="DefaultContainer">Default Container: </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<select id="defaultContainer" class="form-select" @bind="@_containertype" required>
|
|
||||||
<option value="-"><@Localizer["Container.Select"]></option>
|
|
||||||
@foreach (var container in _containers)
|
|
||||||
{
|
|
||||||
<option value="@container.TypeName">@container.Name</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@@ -70,26 +45,6 @@ else
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="rendermode" HelpText="The default render mode for the site" ResourceKey="Rendermode">Render Mode: </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<select id="rendermode" class="form-select" @bind="@_rendermode" required>
|
|
||||||
<option value="@RenderModes.Interactive">@(SharedLocalizer["RenderMode" + @RenderModes.Interactive])</option>
|
|
||||||
<option value="@RenderModes.Static">@(SharedLocalizer["RenderMode" + @RenderModes.Static])</option>
|
|
||||||
<option value="@RenderModes.Headless">@(SharedLocalizer["RenderMode" + @RenderModes.Headless])</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="runtime" HelpText="The render mode for UI components which require interactivity" ResourceKey="Runtime">Interactivity: </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<select id="runtime" class="form-select" @bind="@_runtime" required>
|
|
||||||
<option value="@Runtimes.Server">@(SharedLocalizer["Runtime" + @Runtimes.Server])</option>
|
|
||||||
<option value="@Runtimes.WebAssembly">@(SharedLocalizer["Runtime" + @Runtimes.WebAssembly])</option>
|
|
||||||
<option value="@Runtimes.Auto">@(SharedLocalizer["Runtime" + @Runtimes.Auto])</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="tenant" HelpText="Select the database for the site" ResourceKey="Tenant">Database: </Label>
|
<Label Class="col-sm-3" For="tenant" HelpText="Select the database for the site" ResourceKey="Tenant">Database: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@@ -186,9 +141,6 @@ else
|
|||||||
private bool _showConnectionString = false;
|
private bool _showConnectionString = false;
|
||||||
private string _connectionString = string.Empty;
|
private string _connectionString = string.Empty;
|
||||||
|
|
||||||
private List<Theme> _themeList;
|
|
||||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
|
||||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
|
||||||
private List<SiteTemplate> _siteTemplates;
|
private List<SiteTemplate> _siteTemplates;
|
||||||
private List<Tenant> _tenants;
|
private List<Tenant> _tenants;
|
||||||
private string _tenantid = "-";
|
private string _tenantid = "-";
|
||||||
@@ -200,11 +152,7 @@ else
|
|||||||
|
|
||||||
private string _name = string.Empty;
|
private string _name = string.Empty;
|
||||||
private string _urls = string.Empty;
|
private string _urls = string.Empty;
|
||||||
private string _themetype = "-";
|
|
||||||
private string _containertype = "-";
|
|
||||||
private string _sitetemplatetype = "-";
|
private string _sitetemplatetype = "-";
|
||||||
private string _rendermode = RenderModes.Static;
|
|
||||||
private string _runtime = Runtimes.Server;
|
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||||
|
|
||||||
@@ -215,19 +163,11 @@ else
|
|||||||
{
|
{
|
||||||
_tenantid = _tenants.First(item => item.Name == TenantNames.Master).TenantId.ToString();
|
_tenantid = _tenants.First(item => item.Name == TenantNames.Master).TenantId.ToString();
|
||||||
}
|
}
|
||||||
_urls = PageState.Alias.Name;
|
_urls = PageState.Alias.Name + "/sitename";
|
||||||
_themeList = await ThemeService.GetThemesAsync(PageState.Site.SiteId);
|
|
||||||
_themes = ThemeService.GetThemeControls(_themeList);
|
|
||||||
if (_themes.Any(item => item.TypeName == Constants.DefaultTheme))
|
|
||||||
{
|
|
||||||
_themetype = Constants.DefaultTheme;
|
|
||||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
|
||||||
_containertype = _containers.First().TypeName;
|
|
||||||
}
|
|
||||||
_siteTemplates = await SiteTemplateService.GetSiteTemplatesAsync();
|
_siteTemplates = await SiteTemplateService.GetSiteTemplatesAsync();
|
||||||
if (_siteTemplates.Any(item => item.TypeName == Constants.DefaultSiteTemplate))
|
if (_siteTemplates.Any(item => item.TypeName == Constants.EmptySiteTemplate))
|
||||||
{
|
{
|
||||||
_sitetemplatetype = Constants.DefaultSiteTemplate;
|
_sitetemplatetype = Constants.EmptySiteTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
_databases = await DatabaseService.GetDatabasesAsync();
|
_databases = await DatabaseService.GetDatabasesAsync();
|
||||||
@@ -281,37 +221,13 @@ else
|
|||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void ThemeChanged(ChangeEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_themetype = (string)e.Value;
|
|
||||||
if (_themetype != "-")
|
|
||||||
{
|
|
||||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
|
||||||
_containertype = _containers.First().TypeName;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_containers = new List<ThemeControl>();
|
|
||||||
_containertype = "-";
|
|
||||||
}
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Loading Containers For Theme {ThemeType} {Error}", _themetype, ex.Message);
|
|
||||||
AddModuleMessage(Localizer["Error.Theme.LoadContainers"], MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SaveSite()
|
private async Task SaveSite()
|
||||||
{
|
{
|
||||||
validated = true;
|
validated = true;
|
||||||
var interop = new Interop(JSRuntime);
|
var interop = new Interop(JSRuntime);
|
||||||
if (await interop.FormValid(form))
|
if (await interop.FormValid(form))
|
||||||
{
|
{
|
||||||
if (_tenantid != "-" && _name != string.Empty && _urls != string.Empty && _themetype != "-" && _containertype != "-" && _sitetemplatetype != "-")
|
if (_tenantid != "-" && _name != string.Empty && _urls != string.Empty && _sitetemplatetype != "-")
|
||||||
{
|
{
|
||||||
_urls = Regex.Replace(_urls, @"\r\n?|\n", ",");
|
_urls = Regex.Replace(_urls, @"\r\n?|\n", ",");
|
||||||
var duplicates = new List<string>();
|
var duplicates = new List<string>();
|
||||||
@@ -399,12 +315,12 @@ else
|
|||||||
{
|
{
|
||||||
config.SiteName = _name;
|
config.SiteName = _name;
|
||||||
config.Aliases = _urls;
|
config.Aliases = _urls;
|
||||||
config.DefaultTheme = _themetype;
|
config.DefaultTheme = Constants.DefaultTheme;
|
||||||
config.DefaultContainer = _containertype;
|
config.DefaultContainer = Constants.DefaultContainer;
|
||||||
config.DefaultAdminContainer = "";
|
config.DefaultAdminContainer = "";
|
||||||
config.SiteTemplate = _sitetemplatetype;
|
config.SiteTemplate = _sitetemplatetype;
|
||||||
config.RenderMode = _rendermode;
|
config.RenderMode = RenderModes.Static;
|
||||||
config.Runtime = _runtime;
|
config.Runtime = Runtimes.Server;
|
||||||
config.Register = false;
|
config.Register = false;
|
||||||
|
|
||||||
ShowProgressIndicator();
|
ShowProgressIndicator();
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
<br />
|
||||||
<Section Name="Information" ResourceKey="Information" Heading="Information">
|
<Section Name="Information" ResourceKey="Information" Heading="Information">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@@ -81,6 +82,12 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="fingerprint" HelpText="A unique identifier for the theme's static resources. This value can be changed by clicking the Save option below (ie. cache busting)." ResourceKey="Fingerprint">Fingerprint: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="fingerprint" class="form-control" @bind="@_fingerprint" disabled />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
<br />
|
<br />
|
||||||
@@ -117,6 +124,7 @@
|
|||||||
private string _url = "";
|
private string _url = "";
|
||||||
private string _contact = "";
|
private string _contact = "";
|
||||||
private string _license = "";
|
private string _license = "";
|
||||||
|
private string _fingerprint = "";
|
||||||
private List<Permission> _permissions = null;
|
private List<Permission> _permissions = null;
|
||||||
private string _createdby;
|
private string _createdby;
|
||||||
private DateTime _createdon;
|
private DateTime _createdon;
|
||||||
@@ -143,6 +151,7 @@
|
|||||||
_url = theme.Url;
|
_url = theme.Url;
|
||||||
_contact = theme.Contact;
|
_contact = theme.Contact;
|
||||||
_license = theme.License;
|
_license = theme.License;
|
||||||
|
_fingerprint = theme.Fingerprint;
|
||||||
_permissions = theme.PermissionList;
|
_permissions = theme.PermissionList;
|
||||||
_createdby = theme.CreatedBy;
|
_createdby = theme.CreatedBy;
|
||||||
_createdon = theme.CreatedOn;
|
_createdon = theme.CreatedOn;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
@inject IFileService FileService
|
@inject IFileService FileService
|
||||||
@inject IFolderService FolderService
|
@inject IFolderService FolderService
|
||||||
@inject ITimeZoneService TimeZoneService
|
@inject ITimeZoneService TimeZoneService
|
||||||
|
@inject ILanguageService LanguageService
|
||||||
@inject IJSRuntime jsRuntime
|
@inject IJSRuntime jsRuntime
|
||||||
@inject IServiceProvider ServiceProvider
|
@inject IServiceProvider ServiceProvider
|
||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
@@ -58,6 +59,18 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="culture" HelpText="Your preferred language. Note that you will only be able to choose from languages supported on this site." ResourceKey="CultureCode">Language:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="culture" class="form-select" @bind="@_culturecode">
|
||||||
|
<option value=""><@SharedLocalizer["Not Specified"]></option>
|
||||||
|
@foreach (var language in _languages)
|
||||||
|
{
|
||||||
|
<option value="@language.Code">@language.Name</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="@_photofileid.ToString()" HelpText="A photo of yourself" ResourceKey="Photo"></Label>
|
<Label Class="col-sm-3" For="@_photofileid.ToString()" HelpText="A photo of yourself" ResourceKey="Photo"></Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@@ -448,6 +461,9 @@
|
|||||||
@code {
|
@code {
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
|
||||||
|
|
||||||
|
private List<Models.TimeZone> _timezones;
|
||||||
|
private IEnumerable<Language> _languages;
|
||||||
|
|
||||||
private bool _initialized = false;
|
private bool _initialized = false;
|
||||||
private bool _allowtwofactor = false;
|
private bool _allowtwofactor = false;
|
||||||
private bool _allowpasskeys = false;
|
private bool _allowpasskeys = false;
|
||||||
@@ -458,8 +474,8 @@
|
|||||||
private string _displayname = string.Empty;
|
private string _displayname = string.Empty;
|
||||||
private FileManager _filemanager;
|
private FileManager _filemanager;
|
||||||
private int _folderid = -1;
|
private int _folderid = -1;
|
||||||
private List<Models.TimeZone> _timezones;
|
|
||||||
private string _timezoneid = string.Empty;
|
private string _timezoneid = string.Empty;
|
||||||
|
private string _culturecode = string.Empty;
|
||||||
private int _photofileid = -1;
|
private int _photofileid = -1;
|
||||||
private File _photo = null;
|
private File _photo = null;
|
||||||
private string _imagefiles = string.Empty;
|
private string _imagefiles = string.Empty;
|
||||||
@@ -493,12 +509,15 @@
|
|||||||
|
|
||||||
if (PageState.User != null)
|
if (PageState.User != null)
|
||||||
{
|
{
|
||||||
|
_timezones = TimeZoneService.GetTimeZones();
|
||||||
|
_languages = await LanguageService.GetLanguagesAsync(PageState.Site.SiteId);
|
||||||
|
|
||||||
// identity section
|
// identity section
|
||||||
_username = PageState.User.Username;
|
_username = PageState.User.Username;
|
||||||
_email = PageState.User.Email;
|
_email = PageState.User.Email;
|
||||||
_displayname = PageState.User.DisplayName;
|
_displayname = PageState.User.DisplayName;
|
||||||
_timezones = TimeZoneService.GetTimeZones();
|
|
||||||
_timezoneid = PageState.User.TimeZoneId;
|
_timezoneid = PageState.User.TimeZoneId;
|
||||||
|
_culturecode = PageState.User.CultureCode;
|
||||||
var folder = await FolderService.GetFolderAsync(ModuleState.SiteId, PageState.User.FolderPath);
|
var folder = await FolderService.GetFolderAsync(ModuleState.SiteId, PageState.User.FolderPath);
|
||||||
if (folder != null)
|
if (folder != null)
|
||||||
{
|
{
|
||||||
@@ -572,6 +591,7 @@
|
|||||||
user.Email = _email;
|
user.Email = _email;
|
||||||
user.DisplayName = (_displayname == string.Empty ? _username : _displayname);
|
user.DisplayName = (_displayname == string.Empty ? _username : _displayname);
|
||||||
user.TimeZoneId = _timezoneid;
|
user.TimeZoneId = _timezoneid;
|
||||||
|
user.CultureCode = _culturecode;
|
||||||
user.PhotoFileId = _filemanager.GetFileId();
|
user.PhotoFileId = _filemanager.GetFileId();
|
||||||
if (user.PhotoFileId == -1)
|
if (user.PhotoFileId == -1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
@inject IProfileService ProfileService
|
@inject IProfileService ProfileService
|
||||||
@inject ISettingService SettingService
|
@inject ISettingService SettingService
|
||||||
@inject ITimeZoneService TimeZoneService
|
@inject ITimeZoneService TimeZoneService
|
||||||
|
@inject ILanguageService LanguageService
|
||||||
@inject IStringLocalizer<Add> Localizer
|
@inject IStringLocalizer<Add> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
@@ -55,6 +56,18 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="culture" HelpText="The user's preferred language. Note that you will only be able to choose from languages supported on this site." ResourceKey="CultureCode">Language:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="culture" class="form-select" @bind="@_culturecode">
|
||||||
|
<option value=""><@SharedLocalizer["Not Specified"]></option>
|
||||||
|
@foreach (var language in _languages)
|
||||||
|
{
|
||||||
|
<option value="@language.Code">@language.Name</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="notify" HelpText="Indicate if new users should receive an email notification" ResourceKey="Notify">Notify? </Label>
|
<Label Class="col-sm-3" For="notify" HelpText="Indicate if new users should receive an email notification" ResourceKey="Notify">Notify? </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@@ -129,12 +142,15 @@
|
|||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<Models.TimeZone> _timezones;
|
private List<Models.TimeZone> _timezones;
|
||||||
|
private IEnumerable<Models.Language> _languages;
|
||||||
|
|
||||||
private bool _initialized = false;
|
private bool _initialized = false;
|
||||||
private string _username = string.Empty;
|
private string _username = string.Empty;
|
||||||
private string _email = string.Empty;
|
private string _email = string.Empty;
|
||||||
private string _confirmed = "True";
|
private string _confirmed = "True";
|
||||||
private string _displayname = string.Empty;
|
private string _displayname = string.Empty;
|
||||||
private string _timezoneid = string.Empty;
|
private string _timezoneid = string.Empty;
|
||||||
|
private string _culturecode = string.Empty;
|
||||||
private string _notify = "True";
|
private string _notify = "True";
|
||||||
private List<Profile> _profiles;
|
private List<Profile> _profiles;
|
||||||
private Dictionary<string, string> _settings;
|
private Dictionary<string, string> _settings;
|
||||||
@@ -147,6 +163,11 @@
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
_timezones = TimeZoneService.GetTimeZones();
|
_timezones = TimeZoneService.GetTimeZones();
|
||||||
|
_languages = await LanguageService.GetLanguagesAsync(PageState.Site.SiteId);
|
||||||
|
|
||||||
|
_timezoneid = PageState.Site.TimeZoneId;
|
||||||
|
_culturecode = PageState.Site.CultureCode;
|
||||||
|
|
||||||
_profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
_profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
||||||
foreach (var profile in _profiles)
|
foreach (var profile in _profiles)
|
||||||
{
|
{
|
||||||
@@ -157,8 +178,9 @@
|
|||||||
profile.Options = string.Join(",", options.OrderBy(item => item.Value).Select(kvp => $"{kvp.Key}:{kvp.Value}"));
|
profile.Options = string.Join(",", options.OrderBy(item => item.Value).Select(kvp => $"{kvp.Key}:{kvp.Value}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_settings = new Dictionary<string, string>();
|
_settings = new Dictionary<string, string>();
|
||||||
_timezoneid = PageState.Site.TimeZoneId;
|
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -194,6 +216,7 @@
|
|||||||
user.EmailConfirmed = bool.Parse(_confirmed);
|
user.EmailConfirmed = bool.Parse(_confirmed);
|
||||||
user.DisplayName = string.IsNullOrWhiteSpace(_displayname) ? _username : _displayname;
|
user.DisplayName = string.IsNullOrWhiteSpace(_displayname) ? _username : _displayname;
|
||||||
user.TimeZoneId = _timezoneid;
|
user.TimeZoneId = _timezoneid;
|
||||||
|
user.CultureCode = _culturecode;
|
||||||
user.PhotoFileId = null;
|
user.PhotoFileId = null;
|
||||||
user.SuppressNotification = !bool.Parse(_notify);
|
user.SuppressNotification = !bool.Parse(_notify);
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
@inject ISettingService SettingService
|
@inject ISettingService SettingService
|
||||||
@inject IFileService FileService
|
@inject IFileService FileService
|
||||||
@inject ITimeZoneService TimeZoneService
|
@inject ITimeZoneService TimeZoneService
|
||||||
|
@inject ILanguageService LanguageService
|
||||||
@inject IServiceProvider ServiceProvider
|
@inject IServiceProvider ServiceProvider
|
||||||
@inject IStringLocalizer<Edit> Localizer
|
@inject IStringLocalizer<Edit> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
@@ -55,6 +56,18 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="culture" HelpText="The user's preferred language. Note that you will only be able to choose from languages supported on this site." ResourceKey="CultureCode">Language:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="culture" class="form-select" @bind="@_culturecode">
|
||||||
|
<option value=""><@SharedLocalizer["Not Specified"]></option>
|
||||||
|
@foreach (var language in _languages)
|
||||||
|
{
|
||||||
|
<option value="@language.Code">@language.Name</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
{
|
{
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@@ -211,7 +224,7 @@
|
|||||||
{
|
{
|
||||||
<button type="button" class="btn btn-primary ms-1" @onclick="ImpersonateUser">@Localizer["Impersonate"]</button>
|
<button type="button" class="btn btn-primary ms-1" @onclick="ImpersonateUser">@Localizer["Impersonate"]</button>
|
||||||
}
|
}
|
||||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host) && _isdeleted == "True")
|
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host) && _candelete)
|
||||||
{
|
{
|
||||||
<ActionDialog Header="Delete User" Message="Are You Sure You Wish To Permanently Delete This User?" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger ms-1" OnClick="@(async () => await DeleteUser())" ResourceKey="DeleteUser" />
|
<ActionDialog Header="Delete User" Message="Are You Sure You Wish To Permanently Delete This User?" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger ms-1" OnClick="@(async () => await DeleteUser())" ResourceKey="DeleteUser" />
|
||||||
}
|
}
|
||||||
@@ -224,17 +237,21 @@
|
|||||||
private bool _allowpasskeys = false;
|
private bool _allowpasskeys = false;
|
||||||
private bool _allowexternallogin = false;
|
private bool _allowexternallogin = false;
|
||||||
|
|
||||||
|
private List<Models.TimeZone> _timezones;
|
||||||
|
private IEnumerable<Language> _languages;
|
||||||
|
|
||||||
private int _userid;
|
private int _userid;
|
||||||
private string _username = string.Empty;
|
private string _username = string.Empty;
|
||||||
private string _email = string.Empty;
|
private string _email = string.Empty;
|
||||||
private string _confirmed = string.Empty;
|
private string _confirmed = string.Empty;
|
||||||
private string _displayname = string.Empty;
|
private string _displayname = string.Empty;
|
||||||
private List<Models.TimeZone> _timezones;
|
|
||||||
private string _timezoneid = string.Empty;
|
private string _timezoneid = string.Empty;
|
||||||
|
private string _culturecode = string.Empty;
|
||||||
private string _isdeleted;
|
private string _isdeleted;
|
||||||
private string _lastlogin;
|
private string _lastlogin;
|
||||||
private string _lastipaddress;
|
private string _lastipaddress;
|
||||||
private bool _ishost = false;
|
private bool _ishost = false;
|
||||||
|
private bool _candelete = false;
|
||||||
|
|
||||||
private string _passwordrequirements;
|
private string _passwordrequirements;
|
||||||
private string _password = string.Empty;
|
private string _password = string.Empty;
|
||||||
@@ -270,13 +287,17 @@
|
|||||||
var user = await UserService.GetUserAsync(_userid, PageState.Site.SiteId);
|
var user = await UserService.GetUserAsync(_userid, PageState.Site.SiteId);
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
|
_timezones = TimeZoneService.GetTimeZones();
|
||||||
|
_languages = await LanguageService.GetLanguagesAsync(PageState.Site.SiteId);
|
||||||
|
|
||||||
_username = user.Username;
|
_username = user.Username;
|
||||||
_email = user.Email;
|
_email = user.Email;
|
||||||
_confirmed = user.EmailConfirmed.ToString();
|
_confirmed = user.EmailConfirmed.ToString();
|
||||||
_displayname = user.DisplayName;
|
_displayname = user.DisplayName;
|
||||||
_timezones = TimeZoneService.GetTimeZones();
|
|
||||||
_timezoneid = PageState.User.TimeZoneId;
|
_timezoneid = PageState.User.TimeZoneId;
|
||||||
|
_culturecode = PageState.User.CultureCode;
|
||||||
_isdeleted = user.IsDeleted.ToString();
|
_isdeleted = user.IsDeleted.ToString();
|
||||||
|
_candelete = user.IsDeleted;
|
||||||
_lastlogin = string.Format("{0:MMM dd yyyy HH:mm:ss}", UtcToLocal(user.LastLoginOn));
|
_lastlogin = string.Format("{0:MMM dd yyyy HH:mm:ss}", UtcToLocal(user.LastLoginOn));
|
||||||
_lastipaddress = user.LastIPAddress;
|
_lastipaddress = user.LastIPAddress;
|
||||||
_ishost = UserSecurity.ContainsRole(user.Roles, RoleNames.Host);
|
_ishost = UserSecurity.ContainsRole(user.Roles, RoleNames.Host);
|
||||||
@@ -344,6 +365,7 @@
|
|||||||
user.EmailConfirmed = bool.Parse(_confirmed);
|
user.EmailConfirmed = bool.Parse(_confirmed);
|
||||||
user.DisplayName = string.IsNullOrWhiteSpace(_displayname) ? _username : _displayname;
|
user.DisplayName = string.IsNullOrWhiteSpace(_displayname) ? _username : _displayname;
|
||||||
user.TimeZoneId = _timezoneid;
|
user.TimeZoneId = _timezoneid;
|
||||||
|
user.CultureCode = _culturecode;
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
{
|
{
|
||||||
user.IsDeleted = (_isdeleted == null ? true : Boolean.Parse(_isdeleted));
|
user.IsDeleted = (_isdeleted == null ? true : Boolean.Parse(_isdeleted));
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@namespace Oqtane.Modules.Admin.Users
|
@namespace Oqtane.Modules.Admin.Users
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject IUserService UserService
|
@inject ISiteTaskService SiteTaskService
|
||||||
@inject IStringLocalizer<Users> Localizer
|
@inject IStringLocalizer<Users> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
@@ -43,17 +43,9 @@
|
|||||||
var fileid = _filemanager.GetFileId();
|
var fileid = _filemanager.GetFileId();
|
||||||
if (fileid != -1)
|
if (fileid != -1)
|
||||||
{
|
{
|
||||||
ShowProgressIndicator();
|
var siteTask = new SiteTask(PageState.Site.SiteId, "Import Users", "Oqtane.Infrastructure.ImportUsersTask, Oqtane.Server", $"{fileid}:{_notify}");
|
||||||
var results = await UserService.ImportUsersAsync(PageState.Site.SiteId, fileid, bool.Parse(_notify));
|
await SiteTaskService.AddSiteTaskAsync(siteTask);
|
||||||
if (bool.Parse(results["Success"]))
|
AddModuleMessage(Localizer["Message.Import.Success"], MessageType.Success);
|
||||||
{
|
|
||||||
AddModuleMessage(string.Format(Localizer["Message.Import.Success"], results["Users"]), MessageType.Success);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddModuleMessage(Localizer["Message.Import.Failure"], MessageType.Error);
|
|
||||||
}
|
|
||||||
HideProgressIndicator();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -61,6 +61,12 @@
|
|||||||
{
|
{
|
||||||
<input type="file" id="@_fileinputid" name="file" accept="@_filter" />
|
<input type="file" id="@_fileinputid" name="file" accept="@_filter" />
|
||||||
}
|
}
|
||||||
|
@if (MaxUploadFileSize > 0)
|
||||||
|
{
|
||||||
|
<div class="row my-1">
|
||||||
|
<small class="fw-light">@string.Format(Localizer["File.MaxSize"], MaxUploadFileSize)</small>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<button type="button" class="btn btn-success" @onclick="UploadFiles">@SharedLocalizer["Upload"]</button>
|
<button type="button" class="btn btn-success" @onclick="UploadFiles">@SharedLocalizer["Upload"]</button>
|
||||||
@@ -163,6 +169,9 @@
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public int ChunkSize { get; set; } = 1; // optional - size of file chunks to upload in MB
|
public int ChunkSize { get; set; } = 1; // optional - size of file chunks to upload in MB
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public int MaxUploadFileSize { get; set; } = -1; // optional - maximum upload file size in MB
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public EventCallback<int> OnUpload { get; set; } // optional - executes a method in the calling component when a file is uploaded
|
public EventCallback<int> OnUpload { get; set; } // optional - executes a method in the calling component when a file is uploaded
|
||||||
|
|
||||||
@@ -381,16 +390,39 @@
|
|||||||
if (uploads.Length > 0)
|
if (uploads.Length > 0)
|
||||||
{
|
{
|
||||||
string restricted = "";
|
string restricted = "";
|
||||||
|
string tooLarge = "";
|
||||||
foreach (var upload in uploads)
|
foreach (var upload in uploads)
|
||||||
{
|
{
|
||||||
var filename = upload.Split(':')[0];
|
var fileparts = upload.Split(':');
|
||||||
|
var filename = fileparts[0];
|
||||||
|
|
||||||
|
if (MaxUploadFileSize > 0)
|
||||||
|
{
|
||||||
|
var filesizeBytes = long.Parse(fileparts[1]);
|
||||||
|
var filesizeMB = (double)filesizeBytes / (1024 * 1024);
|
||||||
|
if (filesizeMB > MaxUploadFileSize)
|
||||||
|
{
|
||||||
|
tooLarge += (tooLarge == "" ? "" : ",") + filename;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var extension = (filename.LastIndexOf(".") != -1) ? filename.Substring(filename.LastIndexOf(".") + 1) : "";
|
var extension = (filename.LastIndexOf(".") != -1) ? filename.Substring(filename.LastIndexOf(".") + 1) : "";
|
||||||
if (!PageState.Site.UploadableFiles.Split(',').Contains(extension.ToLower()))
|
if (!PageState.Site.UploadableFiles.Split(',').Contains(extension.ToLower()))
|
||||||
{
|
{
|
||||||
restricted += (restricted == "" ? "" : ",") + extension;
|
restricted += (restricted == "" ? "" : ",") + extension;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (restricted == "")
|
if (restricted != "")
|
||||||
|
{
|
||||||
|
_message = string.Format(Localizer["Message.File.Restricted"], restricted);
|
||||||
|
_messagetype = MessageType.Warning;
|
||||||
|
}
|
||||||
|
else if (tooLarge != "")
|
||||||
|
{
|
||||||
|
_message = string.Format(Localizer["Message.File.TooLarge"], tooLarge, MaxUploadFileSize);
|
||||||
|
_messagetype = MessageType.Warning;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
CancellationTokenSource tokenSource = new CancellationTokenSource();
|
CancellationTokenSource tokenSource = new CancellationTokenSource();
|
||||||
|
|
||||||
@@ -490,11 +522,6 @@
|
|||||||
tokenSource.Dispose();
|
tokenSource.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
_message = string.Format(Localizer["Message.File.Restricted"], restricted);
|
|
||||||
_messagetype = MessageType.Warning;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -31,8 +31,8 @@
|
|||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th>@SharedLocalizer["CreatedOn"]</th>
|
<th>@Localizer["CreatedOn"]</th>
|
||||||
<th>@SharedLocalizer["CreatedBy"]</th>
|
<th>@Localizer["CreatedBy"]</th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><ActionLink Action="View" Security="SecurityAccessLevel.Edit" OnClick="@(async () => await View(context))" ResourceKey="View" /></td>
|
<td><ActionLink Action="View" Security="SecurityAccessLevel.Edit" OnClick="@(async () => await View(context))" ResourceKey="View" /></td>
|
||||||
@@ -121,15 +121,11 @@
|
|||||||
private async Task View(Models.HtmlText htmltext)
|
private async Task View(Models.HtmlText htmltext)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
|
||||||
htmltext = await HtmlTextService.GetHtmlTextAsync(htmltext.HtmlTextId, htmltext.ModuleId);
|
|
||||||
if (htmltext != null)
|
|
||||||
{
|
{
|
||||||
_view = htmltext.Content;
|
_view = htmltext.Content;
|
||||||
_view = Utilities.FormatContent(_view, PageState.Alias, "render");
|
_view = Utilities.FormatContent(_view, PageState.Alias, "render");
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Viewing Content {Error}", ex.Message);
|
await logger.LogError(ex, "Error Viewing Content {Error}", ex.Message);
|
||||||
@@ -140,9 +136,6 @@
|
|||||||
private async Task Restore(Models.HtmlText htmltext)
|
private async Task Restore(Models.HtmlText htmltext)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
|
||||||
htmltext = await HtmlTextService.GetHtmlTextAsync(htmltext.HtmlTextId, ModuleState.ModuleId);
|
|
||||||
if (htmltext != null)
|
|
||||||
{
|
{
|
||||||
var content = htmltext.Content;
|
var content = htmltext.Content;
|
||||||
htmltext = new HtmlText();
|
htmltext = new HtmlText();
|
||||||
@@ -154,7 +147,6 @@
|
|||||||
await LoadContent();
|
await LoadContent();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Restoring Content {Error}", ex.Message);
|
await logger.LogError(ex, "Error Restoring Content {Error}", ex.Message);
|
||||||
@@ -165,9 +157,6 @@
|
|||||||
private async Task Delete(Models.HtmlText htmltext)
|
private async Task Delete(Models.HtmlText htmltext)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
|
||||||
htmltext = await HtmlTextService.GetHtmlTextAsync(htmltext.HtmlTextId, ModuleState.ModuleId);
|
|
||||||
if (htmltext != null)
|
|
||||||
{
|
{
|
||||||
await HtmlTextService.DeleteHtmlTextAsync(htmltext.HtmlTextId, htmltext.ModuleId);
|
await HtmlTextService.DeleteHtmlTextAsync(htmltext.HtmlTextId, htmltext.ModuleId);
|
||||||
await logger.LogInformation("Content Deleted {HtmlText}", htmltext);
|
await logger.LogInformation("Content Deleted {HtmlText}", htmltext);
|
||||||
@@ -175,7 +164,6 @@
|
|||||||
await LoadContent();
|
await LoadContent();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Deleting Content {Error}", ex.Message);
|
await logger.LogError(ex, "Error Deleting Content {Error}", ex.Message);
|
||||||
|
|||||||
@@ -7,6 +7,18 @@ using Oqtane.Shared;
|
|||||||
|
|
||||||
namespace Oqtane.Modules.HtmlText.Services
|
namespace Oqtane.Modules.HtmlText.Services
|
||||||
{
|
{
|
||||||
|
[PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")]
|
||||||
|
public interface IHtmlTextService
|
||||||
|
{
|
||||||
|
Task<List<Models.HtmlText>> GetHtmlTextsAsync(int moduleId);
|
||||||
|
|
||||||
|
Task<Models.HtmlText> GetHtmlTextAsync(int moduleId);
|
||||||
|
|
||||||
|
Task<Models.HtmlText> AddHtmlTextAsync(Models.HtmlText htmltext);
|
||||||
|
|
||||||
|
Task DeleteHtmlTextAsync(int htmlTextId, int moduleId);
|
||||||
|
}
|
||||||
|
|
||||||
[PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")]
|
[PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")]
|
||||||
public class HtmlTextService : ServiceBase, IHtmlTextService, IClientService
|
public class HtmlTextService : ServiceBase, IHtmlTextService, IClientService
|
||||||
{
|
{
|
||||||
@@ -24,11 +36,6 @@ namespace Oqtane.Modules.HtmlText.Services
|
|||||||
return await GetJsonAsync<Models.HtmlText>(CreateAuthorizationPolicyUrl($"{ApiUrl}/{moduleId}", EntityNames.Module, moduleId));
|
return await GetJsonAsync<Models.HtmlText>(CreateAuthorizationPolicyUrl($"{ApiUrl}/{moduleId}", EntityNames.Module, moduleId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Models.HtmlText> GetHtmlTextAsync(int htmlTextId, int moduleId)
|
|
||||||
{
|
|
||||||
return await GetJsonAsync<Models.HtmlText>(CreateAuthorizationPolicyUrl($"{ApiUrl}/{htmlTextId}/{moduleId}", EntityNames.Module, moduleId));
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Models.HtmlText> AddHtmlTextAsync(Models.HtmlText htmlText)
|
public async Task<Models.HtmlText> AddHtmlTextAsync(Models.HtmlText htmlText)
|
||||||
{
|
{
|
||||||
return await PostJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}", EntityNames.Module, htmlText.ModuleId), htmlText);
|
return await PostJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}", EntityNames.Module, htmlText.ModuleId), htmlText);
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Oqtane.Documentation;
|
|
||||||
|
|
||||||
namespace Oqtane.Modules.HtmlText.Services
|
|
||||||
{
|
|
||||||
[PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")]
|
|
||||||
public interface IHtmlTextService
|
|
||||||
{
|
|
||||||
Task<List<Models.HtmlText>> GetHtmlTextsAsync(int moduleId);
|
|
||||||
|
|
||||||
Task<Models.HtmlText> GetHtmlTextAsync(int moduleId);
|
|
||||||
|
|
||||||
Task<Models.HtmlText> GetHtmlTextAsync(int htmlTextId, int moduleId);
|
|
||||||
|
|
||||||
Task<Models.HtmlText> AddHtmlTextAsync(Models.HtmlText htmltext);
|
|
||||||
|
|
||||||
Task DeleteHtmlTextAsync(int htmlTextId, int moduleId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,6 +16,12 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="versions" ResourceKey="Versions" ResourceType="@resourceType" HelpText="The number of content versions to preserve (note that zero means unlimited)">Versions: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="versions" type="number" min="0" max="9" step="1" class="form-control" @bind="@_versions" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
@@ -26,12 +32,14 @@
|
|||||||
private bool validated = false;
|
private bool validated = false;
|
||||||
|
|
||||||
private string _dynamictokens;
|
private string _dynamictokens;
|
||||||
|
private string _versions = "5";
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_dynamictokens = SettingService.GetSetting(ModuleState.Settings, "DynamicTokens", "false");
|
_dynamictokens = SettingService.GetSetting(ModuleState.Settings, "DynamicTokens", "false");
|
||||||
|
_versions = SettingService.GetSetting(ModuleState.Settings, "Versions", "5");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -45,6 +53,10 @@
|
|||||||
{
|
{
|
||||||
var settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId);
|
var settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId);
|
||||||
settings = SettingService.SetSetting(settings, "DynamicTokens", _dynamictokens);
|
settings = SettingService.SetSetting(settings, "DynamicTokens", _dynamictokens);
|
||||||
|
if (int.TryParse(_versions, out int versions) && versions >= 0 && versions <= 9)
|
||||||
|
{
|
||||||
|
settings = SettingService.SetSetting(settings, "Versions", versions.ToString());
|
||||||
|
}
|
||||||
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
|
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
@@ -8,11 +8,11 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.2" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.3" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="10.0.2" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="10.0.3" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="10.0.2" />
|
<PackageReference Include="Microsoft.Extensions.Localization" Version="10.0.3" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.2" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.3" />
|
||||||
<PackageReference Include="Radzen.Blazor" Version="8.6.0" />
|
<PackageReference Include="Radzen.Blazor" Version="9.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
174
Oqtane.Client/Resources/Modules/Admin/GlobalReplace/Index.resx
Normal file
174
Oqtane.Client/Resources/Modules/Admin/GlobalReplace/Index.resx
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<data name="CaseSensitive.Text" xml:space="preserve">
|
||||||
|
<value>Match Case?</value>
|
||||||
|
</data>
|
||||||
|
<data name="CaseSensitive.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify if the replacement operation should be case sensitive</value>
|
||||||
|
</data>
|
||||||
|
<data name="Content.Text" xml:space="preserve">
|
||||||
|
<value>Module Content?</value>
|
||||||
|
</data>
|
||||||
|
<data name="Content.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify if module content should be updated</value>
|
||||||
|
</data>
|
||||||
|
<data name="Pages.Text" xml:space="preserve">
|
||||||
|
<value>Page Properties?</value>
|
||||||
|
</data>
|
||||||
|
<data name="Pages.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify if page properties should be updated (ie. name, title, headcontent, bodycontent)</value>
|
||||||
|
</data>
|
||||||
|
<data name="Site.Text" xml:space="preserve">
|
||||||
|
<value>Site Properties?</value>
|
||||||
|
</data>
|
||||||
|
<data name="Site.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify if site properties should be updated (ie. name, headcontent, bodycontent)</value>
|
||||||
|
</data>
|
||||||
|
<data name="Replace.Text" xml:space="preserve">
|
||||||
|
<value>Replace With:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Replace.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify the replacement content</value>
|
||||||
|
</data>
|
||||||
|
<data name="Modules.Text" xml:space="preserve">
|
||||||
|
<value>Module Properties?</value>
|
||||||
|
</data>
|
||||||
|
<data name="Modules.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify if module properties should be updated (ie. title, header, footer)</value>
|
||||||
|
</data>
|
||||||
|
<data name="Success.Save" xml:space="preserve">
|
||||||
|
<value>Your Global Replace Request Has Been Submitted And Will Be Executed Shortly. Please Be Patient.</value>
|
||||||
|
</data>
|
||||||
|
<data name="Error.Save" xml:space="preserve">
|
||||||
|
<value>Error Saving Global Replace</value>
|
||||||
|
</data>
|
||||||
|
<data name="Find.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify the content which needs to be replaced</value>
|
||||||
|
</data>
|
||||||
|
<data name="Find.Text" xml:space="preserve">
|
||||||
|
<value>Find What:</value>
|
||||||
|
</data>
|
||||||
|
<data name="GlobalReplace.Header" xml:space="preserve">
|
||||||
|
<value>Global Replace</value>
|
||||||
|
</data>
|
||||||
|
<data name="GlobalReplace.Message" xml:space="preserve">
|
||||||
|
<value>This Operation is Permanent. Are You Sure You Wish To Proceed?</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
@@ -234,4 +234,10 @@
|
|||||||
<data name="Pages.Heading" xml:space="preserve">
|
<data name="Pages.Heading" xml:space="preserve">
|
||||||
<value>Pages</value>
|
<value>Pages</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Fingerprint.Text" xml:space="preserve">
|
||||||
|
<value>Fingerprint:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Fingerprint.HelpText" xml:space="preserve">
|
||||||
|
<value>A unique identifier for the module's static resources. This value can be changed by clicking the Save option below (ie. cache busting).</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -130,7 +130,7 @@
|
|||||||
<value>Indicate if this module should be displayed on all pages</value>
|
<value>Indicate if this module should be displayed on all pages</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Page.HelpText" xml:space="preserve">
|
<data name="Page.HelpText" xml:space="preserve">
|
||||||
<value>The page that the module is located on</value>
|
<value>The page that the module is located on. Please note that shared modules cannot be moved to other pages.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Title.Text" xml:space="preserve">
|
<data name="Title.Text" xml:space="preserve">
|
||||||
<value>Title: </value>
|
<value>Title: </value>
|
||||||
|
|||||||
@@ -186,4 +186,10 @@
|
|||||||
<data name="TimeZone.HelpText" xml:space="preserve">
|
<data name="TimeZone.HelpText" xml:space="preserve">
|
||||||
<value>Your time zone</value>
|
<value>Your time zone</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="CultureCode.Text" xml:space="preserve">
|
||||||
|
<value>Language:</value>
|
||||||
|
</data>
|
||||||
|
<data name="CultureCode.HelpText" xml:space="preserve">
|
||||||
|
<value>Your preferred language. Note that you will only be able to choose from languages supported on this site.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -319,16 +319,16 @@
|
|||||||
<value>The default alias for the site. Requests for non-default aliases will be redirected to the default alias.</value>
|
<value>The default alias for the site. Requests for non-default aliases will be redirected to the default alias.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DefaultAlias.Text" xml:space="preserve">
|
<data name="DefaultAlias.Text" xml:space="preserve">
|
||||||
<value>Default Alias: </value>
|
<value>Default?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Aliases.Heading" xml:space="preserve">
|
<data name="Aliases.Heading" xml:space="preserve">
|
||||||
<value>Site Urls</value>
|
<value>Site Urls</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AliasName" xml:space="preserve">
|
<data name="AliasName.Text" xml:space="preserve">
|
||||||
<value>Url</value>
|
<value>Url:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AliasDefault" xml:space="preserve">
|
<data name="Default" xml:space="preserve">
|
||||||
<value>Default?</value>
|
<value>Default</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Confirm.Alias.Delete" xml:space="preserve">
|
<data name="Confirm.Alias.Delete" xml:space="preserve">
|
||||||
<value>Are You Sure You Wish To Delete {0}?</value>
|
<value>Are You Sure You Wish To Delete {0}?</value>
|
||||||
@@ -400,7 +400,7 @@
|
|||||||
<value>Hybrid Enabled?</value>
|
<value>Hybrid Enabled?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Runtime.HelpText" xml:space="preserve">
|
<data name="Runtime.HelpText" xml:space="preserve">
|
||||||
<value>The render mode for UI components which require interactivity</value>
|
<value>The hosting model for UI components which require interactivity</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Runtime.Text" xml:space="preserve">
|
<data name="Runtime.Text" xml:space="preserve">
|
||||||
<value>Interactivity:</value>
|
<value>Interactivity:</value>
|
||||||
@@ -495,4 +495,76 @@
|
|||||||
<data name="StartTlsWhenAvailable" xml:space="preserve">
|
<data name="StartTlsWhenAvailable" xml:space="preserve">
|
||||||
<value>Use TLS When Available</value>
|
<value>Use TLS When Available</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="AliasName.HelpText" xml:space="preserve">
|
||||||
|
<value>A url for this site. This can include domain names (ie. domain.com), subdomains (ie. sub.domain.com) or virtual folders (ie. domain.com/folder).</value>
|
||||||
|
</data>
|
||||||
|
<data name="SiteGroupMembers.Text" xml:space="preserve">
|
||||||
|
<value>Group:</value>
|
||||||
|
</data>
|
||||||
|
<data name="SiteGroupMembers.HelpText" xml:space="preserve">
|
||||||
|
<value>The site groups in this tenant (database)</value>
|
||||||
|
</data>
|
||||||
|
<data name="Primary.Text" xml:space="preserve">
|
||||||
|
<value>Primary?</value>
|
||||||
|
</data>
|
||||||
|
<data name="Primary.HelpText" xml:space="preserve">
|
||||||
|
<value>Indicates if the selected member is the primary site of the site group</value>
|
||||||
|
</data>
|
||||||
|
<data name="GroupName.Text" xml:space="preserve">
|
||||||
|
<value>Name:</value>
|
||||||
|
</data>
|
||||||
|
<data name="GroupName.HelpText" xml:space="preserve">
|
||||||
|
<value>Name of the site group</value>
|
||||||
|
</data>
|
||||||
|
<data name="Primary" xml:space="preserve">
|
||||||
|
<value>Primary</value>
|
||||||
|
</data>
|
||||||
|
<data name="Secondary" xml:space="preserve">
|
||||||
|
<value>Secondary</value>
|
||||||
|
</data>
|
||||||
|
<data name="Compare" xml:space="preserve">
|
||||||
|
<value>Compare</value>
|
||||||
|
</data>
|
||||||
|
<data name="Update" xml:space="preserve">
|
||||||
|
<value>Update</value>
|
||||||
|
</data>
|
||||||
|
<data name="DeleteSiteGroupMember.Header" xml:space="preserve">
|
||||||
|
<value>Delete Site Group Member</value>
|
||||||
|
</data>
|
||||||
|
<data name="Confirm.SiteGroupMember.Delete" xml:space="preserve">
|
||||||
|
<value>Are You Sure You Wish To Delete This Member From The Site Group?</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.Required.GroupName" xml:space="preserve">
|
||||||
|
<value>Site Group Name Is Required</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.Site.Synchronize" xml:space="preserve">
|
||||||
|
<value>Site Submitted For Synchronization</value>
|
||||||
|
</data>
|
||||||
|
<data name="Site.Text" xml:space="preserve">
|
||||||
|
<value>Members:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Site.HelpText" xml:space="preserve">
|
||||||
|
<value>The sites which are members of this site group</value>
|
||||||
|
</data>
|
||||||
|
<data name="Synchronized.Text" xml:space="preserve">
|
||||||
|
<value>Synchronized:</value>
|
||||||
|
</data>
|
||||||
|
<data name="GroupType.Text" xml:space="preserve">
|
||||||
|
<value>Type:</value>
|
||||||
|
</data>
|
||||||
|
<data name="GroupType.HelpText" xml:space="preserve">
|
||||||
|
<value>Defines the specific behavior of the site group</value>
|
||||||
|
</data>
|
||||||
|
<data name="Synchronized.HelpText" xml:space="preserve">
|
||||||
|
<value>The date/time when the site was last synchronized</value>
|
||||||
|
</data>
|
||||||
|
<data name="Synchronization" xml:space="preserve">
|
||||||
|
<value>Synchronization</value>
|
||||||
|
</data>
|
||||||
|
<data name="Localization" xml:space="preserve">
|
||||||
|
<value>Localization</value>
|
||||||
|
</data>
|
||||||
|
<data name="ChangeDetection" xml:space="preserve">
|
||||||
|
<value>Change Detection</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -123,29 +123,14 @@
|
|||||||
<data name="SqlServer" xml:space="preserve">
|
<data name="SqlServer" xml:space="preserve">
|
||||||
<value>SQL Server</value>
|
<value>SQL Server</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Container.Select" xml:space="preserve">
|
|
||||||
<value>Select Container</value>
|
|
||||||
</data>
|
|
||||||
<data name="DefaultContainer.Text" xml:space="preserve">
|
|
||||||
<value>Default Container: </value>
|
|
||||||
</data>
|
|
||||||
<data name="Theme.Select" xml:space="preserve">
|
|
||||||
<value>Select Theme</value>
|
|
||||||
</data>
|
|
||||||
<data name="Aliases.HelpText" xml:space="preserve">
|
<data name="Aliases.HelpText" xml:space="preserve">
|
||||||
<value>The urls for the site (comman delimited). This can include domain names (ie. domain.com), subdomains (ie. sub.domain.com) or a virtual folder (ie. domain.com/folder).</value>
|
<value>The primary url for the site. This can be a domain name (ie. domain.com), subdomain (ie. sub.domain.com) or a virtual folder (ie. domain.com/folder).</value>
|
||||||
</data>
|
|
||||||
<data name="DefaultContainer.HelpText" xml:space="preserve">
|
|
||||||
<value>Select the default container for the site</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="Tenant.Text" xml:space="preserve">
|
<data name="Tenant.Text" xml:space="preserve">
|
||||||
<value>Database: </value>
|
<value>Database: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Aliases.Text" xml:space="preserve">
|
<data name="Aliases.Text" xml:space="preserve">
|
||||||
<value>Urls: </value>
|
<value>Url: </value>
|
||||||
</data>
|
|
||||||
<data name="DefaultTheme.Text" xml:space="preserve">
|
|
||||||
<value>Default Theme: </value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="SiteTemplate.Select" xml:space="preserve">
|
<data name="SiteTemplate.Select" xml:space="preserve">
|
||||||
<value>Select Site Template</value>
|
<value>Select Site Template</value>
|
||||||
@@ -177,9 +162,6 @@
|
|||||||
<data name="Name.HelpText" xml:space="preserve">
|
<data name="Name.HelpText" xml:space="preserve">
|
||||||
<value>Enter the name of the site</value>
|
<value>Enter the name of the site</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DefaultTheme.HelpText" xml:space="preserve">
|
|
||||||
<value>Select the default theme for the site</value>
|
|
||||||
</data>
|
|
||||||
<data name="SiteTemplate.HelpText" xml:space="preserve">
|
<data name="SiteTemplate.HelpText" xml:space="preserve">
|
||||||
<value>Select the site template</value>
|
<value>Select the site template</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -222,12 +204,6 @@
|
|||||||
<data name="Error.Database.LoadConfig" xml:space="preserve">
|
<data name="Error.Database.LoadConfig" xml:space="preserve">
|
||||||
<value>Error loading Database Configuration Control</value>
|
<value>Error loading Database Configuration Control</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RenderMode.HelpText" xml:space="preserve">
|
|
||||||
<value>The default render mode for the site</value>
|
|
||||||
</data>
|
|
||||||
<data name="RenderMode.Text" xml:space="preserve">
|
|
||||||
<value>Render Mode: </value>
|
|
||||||
</data>
|
|
||||||
<data name="ConnectionString.HelpText" xml:space="preserve">
|
<data name="ConnectionString.HelpText" xml:space="preserve">
|
||||||
<value>Enter a complete connection string including all parameters and delimiters</value>
|
<value>Enter a complete connection string including all parameters and delimiters</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -240,10 +216,4 @@
|
|||||||
<data name="EnterConnectionString" xml:space="preserve">
|
<data name="EnterConnectionString" xml:space="preserve">
|
||||||
<value>Enter Connection String</value>
|
<value>Enter Connection String</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Runtime.HelpText" xml:space="preserve">
|
|
||||||
<value>The render mode for UI components which require interactivity</value>
|
|
||||||
</data>
|
|
||||||
<data name="Runtime.Text" xml:space="preserve">
|
|
||||||
<value>Interactivity:</value>
|
|
||||||
</data>
|
|
||||||
</root>
|
</root>
|
||||||
@@ -186,4 +186,10 @@
|
|||||||
<data name="Permissions.Heading" xml:space="preserve">
|
<data name="Permissions.Heading" xml:space="preserve">
|
||||||
<value>Permissions</value>
|
<value>Permissions</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Fingerprint.Text" xml:space="preserve">
|
||||||
|
<value>Fingerprint:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Fingerprint.HelpText" xml:space="preserve">
|
||||||
|
<value>A unique identifier for the theme's static resources. This value can be changed by clicking the Save option below (ie. cache busting).</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -288,4 +288,10 @@
|
|||||||
<data name="Error.Passkey.Fail" xml:space="preserve">
|
<data name="Error.Passkey.Fail" xml:space="preserve">
|
||||||
<value>Passkey Could Not Be Created</value>
|
<value>Passkey Could Not Be Created</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="CultureCode.Text" xml:space="preserve">
|
||||||
|
<value>Language:</value>
|
||||||
|
</data>
|
||||||
|
<data name="CultureCode.HelpText" xml:space="preserve">
|
||||||
|
<value>Your preferred language. Note that you will only be able to choose from languages supported on this site.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -168,4 +168,10 @@
|
|||||||
<data name="Confirmed.HelpText" xml:space="preserve">
|
<data name="Confirmed.HelpText" xml:space="preserve">
|
||||||
<value>Indicates if the user's email is verified</value>
|
<value>Indicates if the user's email is verified</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="CultureCode.Text" xml:space="preserve">
|
||||||
|
<value>Language:</value>
|
||||||
|
</data>
|
||||||
|
<data name="CultureCode.HelpText" xml:space="preserve">
|
||||||
|
<value />
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -252,4 +252,10 @@
|
|||||||
<data name="Message.Logins.None" xml:space="preserve">
|
<data name="Message.Logins.None" xml:space="preserve">
|
||||||
<value>You Do Not Have Any External Logins For This Site</value>
|
<value>You Do Not Have Any External Logins For This Site</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="CultureCode.Text" xml:space="preserve">
|
||||||
|
<value>Language:</value>
|
||||||
|
</data>
|
||||||
|
<data name="CultureCode.HelpText" xml:space="preserve">
|
||||||
|
<value>The user's preferred language. Note that you will only be able to choose from languages supported on this site.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -129,11 +129,8 @@
|
|||||||
<data name="Import" xml:space="preserve">
|
<data name="Import" xml:space="preserve">
|
||||||
<value>Import</value>
|
<value>Import</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.Import.Failure" xml:space="preserve">
|
|
||||||
<value>User Import Failed. Please Review Your Event Log For More Detailed Information.</value>
|
|
||||||
</data>
|
|
||||||
<data name="Message.Import.Success" xml:space="preserve">
|
<data name="Message.Import.Success" xml:space="preserve">
|
||||||
<value>User Import Successful. {0} Users Imported.</value>
|
<value>Your User Import Request Has Been Submitted And Will Be Executed Shortly. Please Be Patient.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.Import.Validation" xml:space="preserve">
|
<data name="Message.Import.Validation" xml:space="preserve">
|
||||||
<value>You Must Specify A User File For Import</value>
|
<value>You Must Specify A User File For Import</value>
|
||||||
|
|||||||
@@ -144,4 +144,10 @@
|
|||||||
<data name="Message.File.Restricted" xml:space="preserve">
|
<data name="Message.File.Restricted" xml:space="preserve">
|
||||||
<value>Files With Extension Of {0} Are Restricted From Upload. Please Contact Your Administrator For More Information.</value>
|
<value>Files With Extension Of {0} Are Restricted From Upload. Please Contact Your Administrator For More Information.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="File.MaxSize" xml:space="preserve">
|
||||||
|
<value>Maximum upload file size: {0} MB</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.File.TooLarge" xml:space="preserve">
|
||||||
|
<value>File(s) {0} exceed(s) the maximum upload size of {1} MB</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -123,4 +123,10 @@
|
|||||||
<data name="DynamicTokens.Text" xml:space="preserve">
|
<data name="DynamicTokens.Text" xml:space="preserve">
|
||||||
<value>Dynamic Tokens?</value>
|
<value>Dynamic Tokens?</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Versions.HelpText" xml:space="preserve">
|
||||||
|
<value>The number of content versions to preserve (note that zero means unlimited)</value>
|
||||||
|
</data>
|
||||||
|
<data name="Versions.Text" xml:space="preserve">
|
||||||
|
<value>Versions:</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -204,6 +204,9 @@
|
|||||||
<data name="System Update" xml:space="preserve">
|
<data name="System Update" xml:space="preserve">
|
||||||
<value>System Update</value>
|
<value>System Update</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Setting Management" xml:space="preserve">
|
||||||
|
<value>Setting Management</value>
|
||||||
|
</data>
|
||||||
<data name="Download" xml:space="preserve">
|
<data name="Download" xml:space="preserve">
|
||||||
<value>Download</value>
|
<value>Download</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -480,4 +483,7 @@
|
|||||||
<data name="Installed" xml:space="preserve">
|
<data name="Installed" xml:space="preserve">
|
||||||
<value>Installed</value>
|
<value>Installed</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Global Replace" xml:space="preserve">
|
||||||
|
<value>Global Replace</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -174,9 +174,6 @@
|
|||||||
<data name="Title" xml:space="preserve">
|
<data name="Title" xml:space="preserve">
|
||||||
<value>Title:</value>
|
<value>Title:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="System.Update" xml:space="preserve">
|
|
||||||
<value>Check For System Updates</value>
|
|
||||||
</data>
|
|
||||||
<data name="Visibility" xml:space="preserve">
|
<data name="Visibility" xml:space="preserve">
|
||||||
<value>Visibility:</value>
|
<value>Visibility:</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -201,4 +198,10 @@
|
|||||||
<data name="Module.CopyExisting" xml:space="preserve">
|
<data name="Module.CopyExisting" xml:space="preserve">
|
||||||
<value>Copy Existing Module</value>
|
<value>Copy Existing Module</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Synchronize" xml:space="preserve">
|
||||||
|
<value>Synchronize Site</value>
|
||||||
|
</data>
|
||||||
|
<data name="Copy" xml:space="preserve">
|
||||||
|
<value>Copy Page</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -14,8 +14,9 @@ namespace Oqtane.Services
|
|||||||
/// Set the localization cookie
|
/// Set the localization cookie
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="culture"></param>
|
/// <param name="culture"></param>
|
||||||
|
/// <param name="uiCulture"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task SetLocalizationCookieAsync(string culture);
|
Task SetLocalizationCookieAsync(string culture, string uiCulture);
|
||||||
}
|
}
|
||||||
|
|
||||||
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
||||||
@@ -23,7 +24,7 @@ namespace Oqtane.Services
|
|||||||
{
|
{
|
||||||
public LocalizationCookieService(HttpClient http, SiteState siteState) : base(http, siteState) { }
|
public LocalizationCookieService(HttpClient http, SiteState siteState) : base(http, siteState) { }
|
||||||
|
|
||||||
public Task SetLocalizationCookieAsync(string culture)
|
public Task SetLocalizationCookieAsync(string culture, string uiCulture)
|
||||||
{
|
{
|
||||||
return Task.CompletedTask; // only used in server side rendering
|
return Task.CompletedTask; // only used in server side rendering
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,10 +13,16 @@ namespace Oqtane.Services
|
|||||||
public interface ILocalizationService
|
public interface ILocalizationService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a collection of supported cultures
|
/// Returns a collection of supported or installed cultures
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<IEnumerable<Culture>> GetCulturesAsync(bool installed);
|
Task<IEnumerable<Culture>> GetCulturesAsync(bool installed);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a collection of neutral cultures
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<IEnumerable<Culture>> GetNeutralCulturesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
||||||
@@ -26,6 +32,14 @@ namespace Oqtane.Services
|
|||||||
|
|
||||||
private string Apiurl => CreateApiUrl("Localization");
|
private string Apiurl => CreateApiUrl("Localization");
|
||||||
|
|
||||||
public async Task<IEnumerable<Culture>> GetCulturesAsync(bool installed) => await GetJsonAsync<IEnumerable<Culture>>($"{Apiurl}?installed={installed}");
|
public async Task<IEnumerable<Culture>> GetCulturesAsync(bool installed)
|
||||||
|
{
|
||||||
|
return await GetJsonAsync<IEnumerable<Culture>>($"{Apiurl}?installed={installed}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Culture>> GetNeutralCulturesAsync()
|
||||||
|
{
|
||||||
|
return await GetJsonAsync<IEnumerable<Culture>>($"{Apiurl}/neutral");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,15 @@ namespace Oqtane.Services
|
|||||||
/// <param name="pageId"></param>
|
/// <param name="pageId"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task DeletePageAsync(int pageId);
|
Task DeletePageAsync(int pageId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies the modules from one page to another
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fromPageId"></param>
|
||||||
|
/// <param name="toPageId"></param>
|
||||||
|
/// <param name="usePagePermissions"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task CopyPageAsync(int fromPageId, int toPageId, bool usePagePermissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
||||||
@@ -129,5 +138,10 @@ namespace Oqtane.Services
|
|||||||
{
|
{
|
||||||
await DeleteAsync($"{Apiurl}/{pageId}");
|
await DeleteAsync($"{Apiurl}/{pageId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task CopyPageAsync(int fromPageId, int toPageId, bool usePagePermissions)
|
||||||
|
{
|
||||||
|
await PostAsync($"{Apiurl}/{fromPageId}/{toPageId}/{usePagePermissions}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
104
Oqtane.Client/Services/SiteGroupMemberService.cs
Normal file
104
Oqtane.Client/Services/SiteGroupMemberService.cs
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
using Oqtane.Models;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Oqtane.Documentation;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Oqtane.Services
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Service to manage <see cref="Role"/>s on a <see cref="Site"/>
|
||||||
|
/// </summary>
|
||||||
|
public interface ISiteGroupMemberService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get all <see cref="SiteGroupMember"/>s
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<List<SiteGroupMember>> GetSiteGroupMembersAsync(int siteId, int siteGroupId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get one specific <see cref="SiteGroupMember"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="siteGroupMemberId">ID-reference of a <see cref="SiteGroupMember"/></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<SiteGroupMember> GetSiteGroupMemberAsync(int siteGroupMemberId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get one specific <see cref="SiteGroupMember"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="siteId">ID-reference of a <see cref="Site"/></param>
|
||||||
|
/// <param name="siteGroupId">ID-reference of a <see cref="SiteGroup"/></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<SiteGroupMember> GetSiteGroupMemberAsync(int siteId, int siteGroupId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add / save a new <see cref="SiteGroupMember"/> to the database.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="siteGroupMember"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<SiteGroupMember> AddSiteGroupMemberAsync(SiteGroupMember siteGroupMember);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update a <see cref="SiteGroupMember"/> in the database.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="siteGroupMember"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<SiteGroupMember> UpdateSiteGroupMemberAsync(SiteGroupMember siteGroupMember);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delete a <see cref="SiteGroupMember"/> in the database.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="siteGroupMemberId">ID-reference of a <see cref="SiteGroupMember"/></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task DeleteSiteGroupMemberAsync(int siteGroupMemberId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
||||||
|
public class SiteGroupMemberService : ServiceBase, ISiteGroupMemberService
|
||||||
|
{
|
||||||
|
public SiteGroupMemberService(HttpClient http, SiteState siteState) : base(http, siteState) { }
|
||||||
|
|
||||||
|
private string Apiurl => CreateApiUrl("SiteGroupMember");
|
||||||
|
|
||||||
|
public async Task<List<SiteGroupMember>> GetSiteGroupMembersAsync(int siteId, int siteGroupId)
|
||||||
|
{
|
||||||
|
return await GetJsonAsync<List<SiteGroupMember>>($"{Apiurl}?siteid={siteId}&groupid={siteGroupId}", Enumerable.Empty<SiteGroupMember>().ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SiteGroupMember> GetSiteGroupMemberAsync(int siteGroupMemberId)
|
||||||
|
{
|
||||||
|
return await GetJsonAsync<SiteGroupMember>($"{Apiurl}/{siteGroupMemberId}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SiteGroupMember> GetSiteGroupMemberAsync(int siteId, int siteGroupId)
|
||||||
|
{
|
||||||
|
var siteGroupMembers = await GetSiteGroupMembersAsync(siteId, siteGroupId);
|
||||||
|
if (siteGroupMembers != null && siteGroupMembers.Count > 0)
|
||||||
|
{
|
||||||
|
return siteGroupMembers[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SiteGroupMember> AddSiteGroupMemberAsync(SiteGroupMember siteGroupMember)
|
||||||
|
{
|
||||||
|
return await PostJsonAsync<SiteGroupMember>(Apiurl, siteGroupMember);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SiteGroupMember> UpdateSiteGroupMemberAsync(SiteGroupMember siteGroupMember)
|
||||||
|
{
|
||||||
|
return await PutJsonAsync<SiteGroupMember>($"{Apiurl}/{siteGroupMember.SiteGroupId}", siteGroupMember);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteSiteGroupMemberAsync(int siteGroupMemberId)
|
||||||
|
{
|
||||||
|
await DeleteAsync($"{Apiurl}/{siteGroupMemberId}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
94
Oqtane.Client/Services/SiteGroupService.cs
Normal file
94
Oqtane.Client/Services/SiteGroupService.cs
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
using Oqtane.Models;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Oqtane.Documentation;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Oqtane.Services
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Service to manage <see cref="Role"/>s on a <see cref="Site"/>
|
||||||
|
/// </summary>
|
||||||
|
public interface ISiteGroupService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get all <see cref="SiteGroup"/>s
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<List<SiteGroup>> GetSiteGroupsAsync();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get all <see cref="SiteGroup"/>s
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<List<SiteGroup>> GetSiteGroupsAsync(int primarySiteId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get one specific <see cref="SiteGroup"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="siteGroupId">ID-reference of a <see cref="SiteGroup"/></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<SiteGroup> GetSiteGroupAsync(int siteGroupId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add / save a new <see cref="SiteGroup"/> to the database.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="group"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<SiteGroup> AddSiteGroupAsync(SiteGroup siteGroup);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update a <see cref="SiteGroup"/> in the database.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="group"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<SiteGroup> UpdateSiteGroupAsync(SiteGroup siteGroup);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delete a <see cref="SiteGroup"/> in the database.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="siteGroupId">ID-reference of a <see cref="SiteGroup"/></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task DeleteSiteGroupAsync(int siteGroupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
||||||
|
public class SiteGroupService : ServiceBase, ISiteGroupService
|
||||||
|
{
|
||||||
|
public SiteGroupService(HttpClient http, SiteState siteState) : base(http, siteState) { }
|
||||||
|
|
||||||
|
private string Apiurl => CreateApiUrl("SiteGroup");
|
||||||
|
|
||||||
|
public async Task<List<SiteGroup>> GetSiteGroupsAsync()
|
||||||
|
{
|
||||||
|
return await GetSiteGroupsAsync(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<SiteGroup>> GetSiteGroupsAsync(int primarySiteId)
|
||||||
|
{
|
||||||
|
return await GetJsonAsync<List<SiteGroup>>($"{Apiurl}?siteid={primarySiteId}", Enumerable.Empty<SiteGroup>().ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SiteGroup> GetSiteGroupAsync(int siteGroupId)
|
||||||
|
{
|
||||||
|
return await GetJsonAsync<SiteGroup>($"{Apiurl}/{siteGroupId}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SiteGroup> AddSiteGroupAsync(SiteGroup siteGroup)
|
||||||
|
{
|
||||||
|
return await PostJsonAsync<SiteGroup>(Apiurl, siteGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SiteGroup> UpdateSiteGroupAsync(SiteGroup siteGroup)
|
||||||
|
{
|
||||||
|
return await PutJsonAsync<SiteGroup>($"{Apiurl}/{siteGroup.SiteGroupId}", siteGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteSiteGroupAsync(int siteGroupId)
|
||||||
|
{
|
||||||
|
await DeleteAsync($"{Apiurl}/{siteGroupId}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
Oqtane.Client/Services/SiteTaskService.cs
Normal file
46
Oqtane.Client/Services/SiteTaskService.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using Oqtane.Models;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Net.Http;
|
||||||
|
using Oqtane.Documentation;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
|
namespace Oqtane.Services
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Service to manage tasks (<see cref="SiteTask"/>)
|
||||||
|
/// </summary>
|
||||||
|
public interface ISiteTaskService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Return a specific task
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="siteTaskId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<SiteTask> GetSiteTaskAsync(int siteTaskId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a new task
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="siteTask"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<SiteTask> AddSiteTaskAsync(SiteTask siteTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
||||||
|
public class SiteTaskService : ServiceBase, ISiteTaskService
|
||||||
|
{
|
||||||
|
public SiteTaskService(HttpClient http, SiteState siteState) : base(http, siteState) { }
|
||||||
|
|
||||||
|
private string Apiurl => CreateApiUrl("SiteTask");
|
||||||
|
|
||||||
|
public async Task<SiteTask> GetSiteTaskAsync(int siteTaskId)
|
||||||
|
{
|
||||||
|
return await GetJsonAsync<SiteTask>($"{Apiurl}/{siteTaskId}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SiteTask> AddSiteTaskAsync(SiteTask siteTask)
|
||||||
|
{
|
||||||
|
return await PostJsonAsync<SiteTask>(Apiurl, siteTask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -161,15 +161,6 @@ namespace Oqtane.Services
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<string> GetPasswordRequirementsAsync(int siteId);
|
Task<string> GetPasswordRequirementsAsync(int siteId);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Bulk import of users
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="siteId">ID of a <see cref="Site"/></param>
|
|
||||||
/// <param name="fileId">ID of a <see cref="File"/></param>
|
|
||||||
/// <param name="notify">Indicates if new users should be notified by email</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<Dictionary<string, string>> ImportUsersAsync(int siteId, int fileId, bool notify);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get passkeys for a user
|
/// Get passkeys for a user
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -351,11 +342,6 @@ namespace Oqtane.Services
|
|||||||
return string.Format(passwordValidationCriteriaTemplate, minimumlength, uniquecharacters, digitRequirement, uppercaseRequirement, lowercaseRequirement, punctuationRequirement);
|
return string.Format(passwordValidationCriteriaTemplate, minimumlength, uniquecharacters, digitRequirement, uppercaseRequirement, lowercaseRequirement, punctuationRequirement);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Dictionary<string, string>> ImportUsersAsync(int siteId, int fileId, bool notify)
|
|
||||||
{
|
|
||||||
return await PostJsonAsync<Dictionary<string, string>>($"{Apiurl}/import?siteid={siteId}&fileid={fileId}¬ify={notify}", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<List<UserPasskey>> GetPasskeysAsync(int userId)
|
public async Task<List<UserPasskey>> GetPasskeysAsync(int userId)
|
||||||
{
|
{
|
||||||
return await GetJsonAsync<List<UserPasskey>>($"{Apiurl}/passkey?id={userId}");
|
return await GetJsonAsync<List<UserPasskey>>($"{Apiurl}/passkey?id={userId}");
|
||||||
|
|||||||
@@ -97,6 +97,7 @@
|
|||||||
Alias = PageState.Alias,
|
Alias = PageState.Alias,
|
||||||
Site = new Site
|
Site = new Site
|
||||||
{
|
{
|
||||||
|
SiteId = PageState.Site.SiteId,
|
||||||
DefaultContainerType = PageState.Site.DefaultContainerType,
|
DefaultContainerType = PageState.Site.DefaultContainerType,
|
||||||
Settings = PageState.Site.Settings,
|
Settings = PageState.Site.Settings,
|
||||||
Themes = PageState.Site.Themes
|
Themes = PageState.Site.Themes
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
@inject ILogService logger
|
@inject ILogService logger
|
||||||
@inject ISettingService SettingService
|
@inject ISettingService SettingService
|
||||||
@inject IJSRuntime jsRuntime
|
@inject IJSRuntime jsRuntime
|
||||||
|
@inject ISiteGroupService SiteGroupService
|
||||||
@inject IServiceProvider ServiceProvider
|
@inject IServiceProvider ServiceProvider
|
||||||
@inject ILogService LoggingService
|
@inject ILogService LoggingService
|
||||||
@inject IStringLocalizer<ControlPanelInteractive> Localizer
|
@inject IStringLocalizer<ControlPanelInteractive> Localizer
|
||||||
@@ -34,6 +35,11 @@
|
|||||||
<button type="button" data-bs-dismiss="offcanvas" class="btn btn-primary col-12" @onclick=@(async () => Navigate("Admin"))>@Localizer["AdminDash"]</button>
|
<button type="button" data-bs-dismiss="offcanvas" class="btn btn-primary col-12" @onclick=@(async () => Navigate("Admin"))>@Localizer["AdminDash"]</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@if (_siteGroups.Any(item => (item.Type == SiteGroupTypes.Synchronization || item.Type == SiteGroupTypes.ChangeDetection) && item.PrimarySiteId == PageState.Site.SiteId))
|
||||||
|
{
|
||||||
|
<hr class="app-rule" />
|
||||||
|
<button type="button" class="btn btn-secondary col-12 mt-1" @onclick="SynchronizeSite">@Localizer["Synchronize"]</button>
|
||||||
|
}
|
||||||
<hr class="app-rule" />
|
<hr class="app-rule" />
|
||||||
}
|
}
|
||||||
@if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
@if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
||||||
@@ -53,6 +59,16 @@
|
|||||||
<button type="button" class="btn btn-danger col ms-1" @onclick="ConfirmDelete">@SharedLocalizer["Delete"]</button>
|
<button type="button" class="btn btn-danger col ms-1" @onclick="ConfirmDelete">@SharedLocalizer["Delete"]</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@if (PageState.Page.UserId == null)
|
||||||
|
{
|
||||||
|
<div class="row d-flex mb-2">
|
||||||
|
<div class="col">
|
||||||
|
<button type="button" class="btn btn-secondary col-12" data-bs-dismiss="offcanvas" @onclick=@(async () => Navigate("Copy"))>@Localizer["Copy"]</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (!PageState.Page.Path.StartsWith("admin/"))
|
||||||
|
{
|
||||||
<div class="row d-flex">
|
<div class="row d-flex">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
@if (UserSecurity.ContainsRole(PageState.Page.PermissionList, PermissionNames.View, RoleNames.Everyone))
|
@if (UserSecurity.ContainsRole(PageState.Page.PermissionList, PermissionNames.View, RoleNames.Everyone))
|
||||||
@@ -65,6 +81,7 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
<hr class="app-rule" />
|
<hr class="app-rule" />
|
||||||
|
|
||||||
@if (_deleteConfirmation)
|
@if (_deleteConfirmation)
|
||||||
@@ -149,7 +166,7 @@
|
|||||||
<option value="@p.PageId">@p.Name</option>
|
<option value="@p.PageId">@p.Name</option>
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
<select class="form-select mt-1" @bind="@_moduleId">
|
<select class="form-select mt-1" value="@_moduleId" @onchange="(e => PageModuleChanged(e))">
|
||||||
<option value="-"><@Localizer["Module.Select"]></option>
|
<option value="-"><@Localizer["Module.Select"]></option>
|
||||||
@foreach (Module module in _modules)
|
@foreach (Module module in _modules)
|
||||||
{
|
{
|
||||||
@@ -257,6 +274,7 @@
|
|||||||
private List<Page> _pages = new List<Page>();
|
private List<Page> _pages = new List<Page>();
|
||||||
private List<Module> _modules = new List<Module>();
|
private List<Module> _modules = new List<Module>();
|
||||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||||
|
private List<SiteGroup> _siteGroups = new List<SiteGroup>();
|
||||||
|
|
||||||
private string _category = "Common";
|
private string _category = "Common";
|
||||||
private string _pane = "";
|
private string _pane = "";
|
||||||
@@ -287,6 +305,7 @@
|
|||||||
_allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Page.SiteId);
|
_allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Page.SiteId);
|
||||||
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(_category)).ToList();
|
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(_category)).ToList();
|
||||||
_categories = _allModuleDefinitions.SelectMany(m => m.Categories.Split(',', StringSplitOptions.RemoveEmptyEntries)).Distinct().Where(item => item != "Headless").ToList();
|
_categories = _allModuleDefinitions.SelectMany(m => m.Categories.Split(',', StringSplitOptions.RemoveEmptyEntries)).Distinct().Where(item => item != "Headless").ToList();
|
||||||
|
_siteGroups = await SiteGroupService.GetSiteGroupsAsync(PageState.Site.SiteId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,6 +358,20 @@
|
|||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task PageModuleChanged(ChangeEventArgs e)
|
||||||
|
{
|
||||||
|
_moduleId = (string)e.Value;
|
||||||
|
if (_moduleId != "-")
|
||||||
|
{
|
||||||
|
_title = _modules.First(item => item.ModuleId == int.Parse(_moduleId)).Title;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_title = "";
|
||||||
|
}
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
private async Task AddModule()
|
private async Task AddModule()
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
||||||
@@ -488,7 +521,12 @@
|
|||||||
case "Edit":
|
case "Edit":
|
||||||
// get page management moduleid
|
// get page management moduleid
|
||||||
moduleId = int.Parse(PageState.Site.Settings[Constants.PageManagementModule]);
|
moduleId = int.Parse(PageState.Site.Settings[Constants.PageManagementModule]);
|
||||||
NavigationManager.NavigateTo(Utilities.EditUrl(PageState.Alias.Path, "admin/pages", moduleId, location, $"id={PageState.Page.PageId}&returnurl={WebUtility.UrlEncode(PageState.Route.PathAndQuery)}"));
|
NavigationManager.NavigateTo(Utilities.EditUrl(PageState.Alias.Path, "admin/pages", moduleId, "Edit", $"id={PageState.Page.PageId}&returnurl={WebUtility.UrlEncode(PageState.Route.PathAndQuery)}"));
|
||||||
|
break;
|
||||||
|
case "Copy":
|
||||||
|
// get page management moduleid
|
||||||
|
moduleId = int.Parse(PageState.Site.Settings[Constants.PageManagementModule]);
|
||||||
|
NavigationManager.NavigateTo(Utilities.EditUrl(PageState.Alias.Path, "admin/pages", moduleId, "Edit", $"id={PageState.Page.PageId}©=true&returnurl={WebUtility.UrlEncode(PageState.Route.PathAndQuery)}"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -631,4 +669,14 @@
|
|||||||
{
|
{
|
||||||
_message = "";
|
_message = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task SynchronizeSite()
|
||||||
|
{
|
||||||
|
foreach (var group in _siteGroups.Where(item => (item.Type == SiteGroupTypes.Synchronization || item.Type == SiteGroupTypes.ChangeDetection) && item.PrimarySiteId == PageState.Site.SiteId))
|
||||||
|
{
|
||||||
|
group.Synchronize = true;
|
||||||
|
await SiteGroupService.UpdateSiteGroupAsync(group);
|
||||||
|
}
|
||||||
|
NavigationManager.NavigateTo(Utilities.NavigateUrl(PageState.Alias.Path, PageState.Page.Path, ""), true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,22 +6,29 @@
|
|||||||
@inject ILocalizationCookieService LocalizationCookieService
|
@inject ILocalizationCookieService LocalizationCookieService
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
|
|
||||||
@if (_supportedCultures?.Count() > 1)
|
@if (PageState.Site.Languages.Count() > 1)
|
||||||
{
|
{
|
||||||
<div class="app-languages btn-group pe-1" role="group">
|
<div class="app-languages btn-group pe-1" role="group">
|
||||||
<button id="btnCultures" type="button" class="btn @ButtonClass dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<button id="btnCultures" type="button" class="btn @ButtonClass dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
<span class="oi oi-globe"></span>
|
<span class="oi oi-globe"></span>
|
||||||
</button>
|
</button>
|
||||||
<div class="dropdown-menu @MenuAlignment" aria-labelledby="btnCultures">
|
<div class="dropdown-menu @MenuAlignment" aria-labelledby="btnCultures">
|
||||||
@foreach (var culture in _supportedCultures)
|
@foreach (var language in PageState.Site.Languages)
|
||||||
{
|
{
|
||||||
@if (PageState.RenderMode == RenderModes.Interactive)
|
@if (_contentLocalization)
|
||||||
{
|
{
|
||||||
<a class="dropdown-item @(CultureInfo.CurrentUICulture.Name == culture.Name ? "active" : String.Empty)" href="#" @onclick="@(async e => await SetCultureAsync(culture.Name))" @onclick:preventDefault="true">@culture.DisplayName</a>
|
<a class="dropdown-item @(PageState.Site.CultureCode == language.Code ? "active" : String.Empty)" href="@(PageState.Alias.Protocol + language.AliasName)" data-enhance-nav="false">@language.Name</a>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<a class="dropdown-item @(CultureInfo.CurrentUICulture.Name == culture.Name ? "active" : String.Empty)" href="@NavigateUrl(PageState.Page.Path, "culture=" + culture.Name)" data-enhance-nav="false">@culture.DisplayName</a>
|
@if (PageState.RenderMode == RenderModes.Interactive)
|
||||||
|
{
|
||||||
|
<a class="dropdown-item @(CultureInfo.CurrentUICulture.Name == language.Code ? "active" : String.Empty)" href="#" @onclick="@(async e => await SetCultureAsync(language.Code))" @onclick:preventDefault="true">@language.Name</a>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<a class="dropdown-item @(CultureInfo.CurrentUICulture.Name == language.Code ? "active" : String.Empty)" href="@NavigateUrl(PageState.Page.Path, "culture=" + language.Code)" data-enhance-nav="false">@language.Name</a>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@@ -29,7 +36,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@code{
|
@code{
|
||||||
private IEnumerable<Culture> _supportedCultures;
|
private bool _contentLocalization;
|
||||||
private string MenuAlignment = string.Empty;
|
private string MenuAlignment = string.Empty;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
@@ -41,14 +48,15 @@
|
|||||||
{
|
{
|
||||||
MenuAlignment = DropdownAlignment.ToLower() == "right" ? "dropdown-menu-end" : string.Empty;
|
MenuAlignment = DropdownAlignment.ToLower() == "right" ? "dropdown-menu-end" : string.Empty;
|
||||||
|
|
||||||
_supportedCultures = PageState.Languages.Select(l => new Culture { Name = l.Code, DisplayName = l.Name });
|
// if AliasName is populated it means the site is using content localization
|
||||||
|
_contentLocalization = PageState.Languages.Any(item => !string.IsNullOrEmpty(item.AliasName));
|
||||||
|
|
||||||
if (PageState.QueryString.ContainsKey("culture"))
|
if (PageState.QueryString.ContainsKey("culture"))
|
||||||
{
|
{
|
||||||
var culture = PageState.QueryString["culture"];
|
var culture = PageState.QueryString["culture"];
|
||||||
if (_supportedCultures.Any(item => item.Name == culture))
|
if (PageState.Site.Languages.Any(item => item.Code == culture))
|
||||||
{
|
{
|
||||||
await LocalizationCookieService.SetLocalizationCookieAsync(culture);
|
await LocalizationCookieService.SetLocalizationCookieAsync(PageState.Site.CultureCode, culture);
|
||||||
}
|
}
|
||||||
NavigationManager.NavigateTo(NavigationManager.Uri.Replace($"?culture={culture}", ""));
|
NavigationManager.NavigateTo(NavigationManager.Uri.Replace($"?culture={culture}", ""));
|
||||||
}
|
}
|
||||||
@@ -58,7 +66,7 @@
|
|||||||
{
|
{
|
||||||
if (culture != CultureInfo.CurrentUICulture.Name)
|
if (culture != CultureInfo.CurrentUICulture.Name)
|
||||||
{
|
{
|
||||||
var localizationCookieValue = CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture));
|
var localizationCookieValue = CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(PageState.Site.CultureCode, culture));
|
||||||
var interop = new Interop(JSRuntime);
|
var interop = new Interop(JSRuntime);
|
||||||
await interop.SetCookie(CookieRequestCultureProvider.DefaultCookieName, localizationCookieValue, 360, true, "Lax");
|
await interop.SetCookie(CookieRequestCultureProvider.DefaultCookieName, localizationCookieValue, 360, true, "Lax");
|
||||||
NavigationManager.NavigateTo(NavigationManager.Uri, true);
|
NavigationManager.NavigateTo(NavigationManager.Uri, true);
|
||||||
|
|||||||
@@ -232,17 +232,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (page == null && route.PagePath == "") // naked path refers to site home page
|
if (page == null && route.PagePath == "") // naked path refers to site home page
|
||||||
{
|
|
||||||
if (site.HomePageId != null)
|
|
||||||
{
|
|
||||||
page = site.Pages.FirstOrDefault(item => item.PageId == site.HomePageId);
|
|
||||||
}
|
|
||||||
if (page == null)
|
|
||||||
{
|
{
|
||||||
// fallback to use the first page in the collection
|
// fallback to use the first page in the collection
|
||||||
page = site.Pages.FirstOrDefault();
|
page = site.Pages.FirstOrDefault();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (page == null)
|
if (page == null)
|
||||||
{
|
{
|
||||||
page = await PageService.GetPageAsync(route.PagePath, site.SiteId);
|
page = await PageService.GetPageAsync(route.PagePath, site.SiteId);
|
||||||
@@ -632,11 +625,11 @@
|
|||||||
{
|
{
|
||||||
if (resource.ResourceType == ResourceType.Stylesheet || resource.Level != ResourceLevel.Site)
|
if (resource.ResourceType == ResourceType.Stylesheet || resource.Level != ResourceLevel.Site)
|
||||||
{
|
{
|
||||||
if (resource.Url.StartsWith("~"))
|
if (!string.IsNullOrEmpty(resource.Url) && resource.Url.StartsWith("~"))
|
||||||
{
|
{
|
||||||
resource.Url = resource.Url.Replace("~", "/" + type + "/" + name + "/").Replace("//", "/");
|
resource.Url = resource.Url.Replace("~", "/" + type + "/" + name + "/").Replace("//", "/");
|
||||||
}
|
}
|
||||||
if (!resource.Url.Contains("://") && alias.BaseUrl != "" && !resource.Url.StartsWith(alias.BaseUrl))
|
if (!string.IsNullOrEmpty(resource.Url) && !resource.Url.Contains("://") && alias.BaseUrl != "" && !resource.Url.StartsWith(alias.BaseUrl))
|
||||||
{
|
{
|
||||||
resource.Url = alias.BaseUrl + resource.Url;
|
resource.Url = alias.BaseUrl + resource.Url;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -227,38 +227,4 @@
|
|||||||
}
|
}
|
||||||
return stylesheets;
|
return stylesheets;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ManageScripts(List<Resource> resources, Alias alias)
|
|
||||||
{
|
|
||||||
var scripts = "";
|
|
||||||
if (resources != null)
|
|
||||||
{
|
|
||||||
foreach (var resource in resources.Where(item => item.ResourceType == ResourceType.Script && item.Location == ResourceLocation.Head))
|
|
||||||
{
|
|
||||||
var script = CreateScript(resource, alias);
|
|
||||||
if (!scripts.Contains(script, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
scripts += script + Environment.NewLine;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return scripts;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string CreateScript(Resource resource, Alias alias)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(resource.Url))
|
|
||||||
{
|
|
||||||
var url = (resource.Url.Contains("://")) ? resource.Url : alias.BaseUrl + resource.Url;
|
|
||||||
return "<script src=\"" + url + "\"" +
|
|
||||||
((!string.IsNullOrEmpty(resource.Integrity)) ? " integrity=\"" + resource.Integrity + "\"" : "") +
|
|
||||||
((!string.IsNullOrEmpty(resource.CrossOrigin)) ? " crossorigin=\"" + resource.CrossOrigin + "\"" : "") +
|
|
||||||
"></script>";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// inline script
|
|
||||||
return "<script>" + resource.Content + "</script>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||||
@using Microsoft.Extensions.Localization
|
@using Microsoft.Extensions.Localization
|
||||||
@using Microsoft.JSInterop
|
@using Microsoft.JSInterop
|
||||||
|
@using Microsoft.AspNetCore.Authorization
|
||||||
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
||||||
|
|
||||||
@using Oqtane.Client
|
@using Oqtane.Client
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<ApplicationId>com.oqtane.maui</ApplicationId>
|
<ApplicationId>com.oqtane.maui</ApplicationId>
|
||||||
|
|
||||||
<!-- Versions -->
|
<!-- Versions -->
|
||||||
<ApplicationDisplayVersion>10.0.4</ApplicationDisplayVersion>
|
<ApplicationDisplayVersion>10.1.0</ApplicationDisplayVersion>
|
||||||
<ApplicationVersion>1</ApplicationVersion>
|
<ApplicationVersion>1</ApplicationVersion>
|
||||||
|
|
||||||
<!-- To develop, package, and publish an app to the Microsoft Store, see: https://aka.ms/MauiTemplateUnpackaged -->
|
<!-- To develop, package, and publish an app to the Microsoft Store, see: https://aka.ms/MauiTemplateUnpackaged -->
|
||||||
@@ -54,11 +54,11 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="10.0.2" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="10.0.3" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.2" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.3" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.2" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.3" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="10.0.2" />
|
<PackageReference Include="Microsoft.Extensions.Localization" Version="10.0.3" />
|
||||||
<PackageReference Include="System.Net.Http.Json" Version="10.0.2" />
|
<PackageReference Include="System.Net.Http.Json" Version="10.0.3" />
|
||||||
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
|
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
|
||||||
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
|
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="$(MauiVersion)" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="$(MauiVersion)" />
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<package>
|
<package>
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Client</id>
|
<id>Oqtane.Client</id>
|
||||||
<version>10.0.4</version>
|
<version>10.1.0</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
@@ -12,18 +12,18 @@
|
|||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.4</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.1.0</releaseNotes>
|
||||||
<readme>readme.md</readme>
|
<readme>readme.md</readme>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<group targetFramework="net10.0">
|
<group targetFramework="net10.0">
|
||||||
<dependency id="Oqtane.Shared" version="10.0.4" exclude="Build,Analyzers" />
|
<dependency id="Oqtane.Shared" version="10.1.0" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.AspNetCore.Components.WebAssembly" version="10.0.2" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.AspNetCore.Components.WebAssembly" version="10.0.3" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.AspNetCore.Components.WebAssembly.Authentication" version="10.0.2" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.AspNetCore.Components.WebAssembly.Authentication" version="10.0.3" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.Extensions.Localization" version="10.0.2" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.Extensions.Localization" version="10.0.3" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.Extensions.Http" version="10.0.2" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.Extensions.Http" version="10.0.3" exclude="Build,Analyzers" />
|
||||||
<dependency id="Radzen.Blazor" version="8.6.0" exclude="Build,Analyzers" />
|
<dependency id="Radzen.Blazor" version="9.0.0" exclude="Build,Analyzers" />
|
||||||
</group>
|
</group>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<package>
|
<package>
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Framework</id>
|
<id>Oqtane.Framework</id>
|
||||||
<version>10.0.4</version>
|
<version>10.1.0</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
@@ -11,8 +11,8 @@
|
|||||||
<copyright>.NET Foundation</copyright>
|
<copyright>.NET Foundation</copyright>
|
||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v10.0.4/Oqtane.Framework.10.0.4.Upgrade.zip</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v10.1.0/Oqtane.Framework.10.1.0.Upgrade.zip</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.4</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.1.0</releaseNotes>
|
||||||
<readme>readme.md</readme>
|
<readme>readme.md</readme>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane framework</tags>
|
<tags>oqtane framework</tags>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<package>
|
<package>
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Server</id>
|
<id>Oqtane.Server</id>
|
||||||
<version>10.0.4</version>
|
<version>10.1.0</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
@@ -12,29 +12,29 @@
|
|||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.4</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.1.0</releaseNotes>
|
||||||
<readme>readme.md</readme>
|
<readme>readme.md</readme>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<group targetFramework="net10.0">
|
<group targetFramework="net10.0">
|
||||||
<dependency id="Oqtane.Client" version="10.0.4" exclude="Build,Analyzers" />
|
<dependency id="Oqtane.Client" version="10.1.0" exclude="Build,Analyzers" />
|
||||||
<dependency id="Oqtane.Shared" version="10.0.4" exclude="Build,Analyzers" />
|
<dependency id="Oqtane.Shared" version="10.1.0" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.AspNetCore.Components.WebAssembly.Server" version="10.0.2" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.AspNetCore.Components.WebAssembly.Server" version="10.0.3" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.AspNetCore.Identity.EntityFrameworkCore" version="10.0.2" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.AspNetCore.Identity.EntityFrameworkCore" version="10.0.3" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.AspNetCore.Authentication.OpenIdConnect" version="10.0.2" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.AspNetCore.Authentication.OpenIdConnect" version="10.0.3" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.EntityFrameworkCore.Relational" version="10.0.2" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.EntityFrameworkCore.Relational" version="10.0.3" exclude="Build,Analyzers" />
|
||||||
<dependency id="SixLabors.ImageSharp" version="3.1.12" exclude="Build,Analyzers" />
|
<dependency id="SixLabors.ImageSharp" version="3.1.12" exclude="Build,Analyzers" />
|
||||||
<dependency id="HtmlAgilityPack" version="1.12.4" exclude="Build,Analyzers" />
|
<dependency id="HtmlAgilityPack" version="1.12.4" exclude="Build,Analyzers" />
|
||||||
<dependency id="Swashbuckle.AspNetCore" version="10.1.0" exclude="Build,Analyzers" />
|
<dependency id="Swashbuckle.AspNetCore" version="10.1.2" exclude="Build,Analyzers" />
|
||||||
<dependency id="MailKit" version="4.14.1" exclude="Build,Analyzers" />
|
<dependency id="MailKit" version="4.14.1" exclude="Build,Analyzers" />
|
||||||
<dependency id="MySql.Data" version="9.5.0" exclude="Build,Analyzers" />
|
<dependency id="MySql.Data" version="9.6.0" exclude="Build,Analyzers" />
|
||||||
<dependency id="MySql.EntityFrameworkCore" version="10.0.0-rc" exclude="Build,Analyzers" />
|
<dependency id="MySql.EntityFrameworkCore" version="10.0.1" exclude="Build,Analyzers" />
|
||||||
<dependency id="EFCore.NamingConventions" version="10.0.0" exclude="Build,Analyzers" />
|
<dependency id="EFCore.NamingConventions" version="10.0.1" exclude="Build,Analyzers" />
|
||||||
<dependency id="Npgsql.EntityFrameworkCore.PostgreSQL" version="10.0.0" exclude="Build,Analyzers" />
|
<dependency id="Npgsql.EntityFrameworkCore.PostgreSQL" version="10.0.0" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.EntityFrameworkCore.Sqlite" version="10.0.2" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.EntityFrameworkCore.Sqlite" version="10.0.3" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.Data.Sqlite.Core" version="10.0.2" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.Data.Sqlite.Core" version="10.0.3" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.EntityFrameworkCore.SqlServer" version="10.0.2" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.EntityFrameworkCore.SqlServer" version="10.0.3" exclude="Build,Analyzers" />
|
||||||
</group>
|
</group>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<frameworkReferences>
|
<frameworkReferences>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<package>
|
<package>
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Shared</id>
|
<id>Oqtane.Shared</id>
|
||||||
<version>10.0.4</version>
|
<version>10.1.0</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
@@ -12,14 +12,14 @@
|
|||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.4</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.1.0</releaseNotes>
|
||||||
<readme>readme.md</readme>
|
<readme>readme.md</readme>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<group targetFramework="net10.0">
|
<group targetFramework="net10.0">
|
||||||
<dependency id="Microsoft.EntityFrameworkCore" version="10.0.2" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.EntityFrameworkCore" version="10.0.3" exclude="Build,Analyzers" />
|
||||||
<dependency id="Microsoft.Extensions.DependencyInjection.Abstractions" version="10.0.2" exclude="Build,Analyzers" />
|
<dependency id="Microsoft.Extensions.DependencyInjection.Abstractions" version="10.0.3" exclude="Build,Analyzers" />
|
||||||
<dependency id="NodaTime" version="3.3.0" exclude="Build,Analyzers" />
|
<dependency id="NodaTime" version="3.3.0" exclude="Build,Analyzers" />
|
||||||
</group>
|
</group>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<package>
|
<package>
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Updater</id>
|
<id>Oqtane.Updater</id>
|
||||||
<version>10.0.4</version>
|
<version>10.1.0</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.0.4</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v10.1.0</releaseNotes>
|
||||||
<readme>readme.md</readme>
|
<readme>readme.md</readme>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net10.0\publish\*" -DestinationPath "Oqtane.Framework.10.0.4.Install.zip" -Force
|
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net10.0\publish\*" -DestinationPath "Oqtane.Framework.10.1.0.Install.zip" -Force
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net10.0\publish\*" -DestinationPath "Oqtane.Framework.10.0.4.Upgrade.zip" -Force
|
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net10.0\publish\*" -DestinationPath "Oqtane.Framework.10.1.0.Upgrade.zip" -Force
|
||||||
|
|||||||
@@ -79,6 +79,7 @@
|
|||||||
|
|
||||||
@((MarkupString)_scripts)
|
@((MarkupString)_scripts)
|
||||||
@((MarkupString)_bodyResources)
|
@((MarkupString)_bodyResources)
|
||||||
|
@((MarkupString)_bodyContent)
|
||||||
@if (_renderMode == RenderModes.Static)
|
@if (_renderMode == RenderModes.Static)
|
||||||
{
|
{
|
||||||
<page-script src="./js/reload.js?v=@_fingerprint"></page-script>
|
<page-script src="./js/reload.js?v=@_fingerprint"></page-script>
|
||||||
@@ -107,6 +108,7 @@
|
|||||||
private string _language = "en";
|
private string _language = "en";
|
||||||
private string _headResources = "";
|
private string _headResources = "";
|
||||||
private string _bodyResources = "";
|
private string _bodyResources = "";
|
||||||
|
private string _bodyContent = "";
|
||||||
private string _styleSheets = "";
|
private string _styleSheets = "";
|
||||||
private string _scripts = "";
|
private string _scripts = "";
|
||||||
private string _message = "";
|
private string _message = "";
|
||||||
@@ -156,17 +158,10 @@
|
|||||||
Route route = new Route(url, alias.Path);
|
Route route = new Route(url, alias.Path);
|
||||||
var page = site.Pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase));
|
var page = site.Pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase));
|
||||||
if (page == null && route.PagePath == "") // naked path refers to site home page
|
if (page == null && route.PagePath == "") // naked path refers to site home page
|
||||||
{
|
|
||||||
if (site.HomePageId != null)
|
|
||||||
{
|
|
||||||
page = site.Pages.FirstOrDefault(item => item.PageId == site.HomePageId);
|
|
||||||
}
|
|
||||||
if (page == null)
|
|
||||||
{
|
{
|
||||||
// fallback to use the first page in the collection
|
// fallback to use the first page in the collection
|
||||||
page = site.Pages.FirstOrDefault();
|
page = site.Pages.FirstOrDefault();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (page == null)
|
if (page == null)
|
||||||
{
|
{
|
||||||
// personalized pages need to be retrieved using path
|
// personalized pages need to be retrieved using path
|
||||||
@@ -193,43 +188,20 @@
|
|||||||
await GetJwtToken(alias);
|
await GetJwtToken(alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
// includes resources
|
// include resources
|
||||||
var resources = await GetPageResources(alias, site, page, modules, int.Parse(route.ModuleId, CultureInfo.InvariantCulture), route.Action);
|
var resources = await GetPageResources(alias, site, page, modules, int.Parse(route.ModuleId, CultureInfo.InvariantCulture), route.Action);
|
||||||
ManageStyleSheets(resources);
|
ManageStyleSheets(resources);
|
||||||
ManageScripts(resources, alias);
|
ManageScripts(resources, alias);
|
||||||
|
AddBodyContent(site.BodyContent);
|
||||||
|
AddBodyContent(page.BodyContent);
|
||||||
|
ManageLocalization(site);
|
||||||
|
|
||||||
// generate scripts
|
// PWA script
|
||||||
if (site.PwaIsEnabled && site.PwaAppIconFileId != null && site.PwaSplashIconFileId != null)
|
if (site.PwaIsEnabled && site.PwaAppIconFileId != null && site.PwaSplashIconFileId != null)
|
||||||
{
|
{
|
||||||
_scripts += CreatePWAScript(alias, site, route);
|
_scripts += CreatePWAScript(alias, site, route);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set culture if not specified
|
|
||||||
string cultureCookie = Context.Request.Cookies[Shared.CookieRequestCultureProvider.DefaultCookieName];
|
|
||||||
if (cultureCookie == null)
|
|
||||||
{
|
|
||||||
// get default language for site
|
|
||||||
if (site.Languages.Any())
|
|
||||||
{
|
|
||||||
// use default language if specified otherwise use first language in collection
|
|
||||||
cultureCookie = (site.Languages.Where(l => l.IsDefault).SingleOrDefault() ?? site.Languages.First()).Code;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// fallback language
|
|
||||||
cultureCookie = LocalizationManager.GetDefaultCulture();
|
|
||||||
}
|
|
||||||
// convert language code to culture cookie format (ie. "c=en|uic=en")
|
|
||||||
cultureCookie = Shared.CookieRequestCultureProvider.MakeCookieValue(new Models.RequestCulture(cultureCookie));
|
|
||||||
SetLocalizationCookie(cultureCookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
// set language for page
|
|
||||||
if (!string.IsNullOrEmpty(cultureCookie))
|
|
||||||
{
|
|
||||||
_language = Shared.CookieRequestCultureProvider.ParseCookieValue(cultureCookie).Culture.Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create initial PageState
|
// create initial PageState
|
||||||
_pageState = new PageState
|
_pageState = new PageState
|
||||||
{
|
{
|
||||||
@@ -550,8 +522,6 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var url = (resource.Url.Contains("://")) ? resource.Url : alias.BaseUrl + resource.Url;
|
|
||||||
|
|
||||||
var dataAttributes = "";
|
var dataAttributes = "";
|
||||||
if (!resource.DataAttributes.ContainsKey("data-reload"))
|
if (!resource.DataAttributes.ContainsKey("data-reload"))
|
||||||
{
|
{
|
||||||
@@ -573,6 +543,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(resource.Url))
|
||||||
|
{
|
||||||
|
var url = (string.IsNullOrEmpty(resource.Url) || resource.Url.Contains("://")) ? resource.Url : alias.BaseUrl + resource.Url;
|
||||||
|
|
||||||
return "<script src=\"" + url + "\"" +
|
return "<script src=\"" + url + "\"" +
|
||||||
((!string.IsNullOrEmpty(resource.Type)) ? " type=\"" + resource.Type + "\"" : "") +
|
((!string.IsNullOrEmpty(resource.Type)) ? " type=\"" + resource.Type + "\"" : "") +
|
||||||
((!string.IsNullOrEmpty(resource.Integrity)) ? " integrity=\"" + resource.Integrity + "\"" : "") +
|
((!string.IsNullOrEmpty(resource.Integrity)) ? " integrity=\"" + resource.Integrity + "\"" : "") +
|
||||||
@@ -580,6 +554,14 @@
|
|||||||
((!string.IsNullOrEmpty(dataAttributes)) ? dataAttributes : "") +
|
((!string.IsNullOrEmpty(dataAttributes)) ? dataAttributes : "") +
|
||||||
"></script>";
|
"></script>";
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return "<script" +
|
||||||
|
((!string.IsNullOrEmpty(resource.Type)) ? " type=\"" + resource.Type + "\"" : "") +
|
||||||
|
((!string.IsNullOrEmpty(dataAttributes)) ? dataAttributes : "") +
|
||||||
|
">" + resource.Content + "</script>";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetLocalizationCookie(string cookieValue)
|
private void SetLocalizationCookie(string cookieValue)
|
||||||
@@ -751,11 +733,11 @@
|
|||||||
{
|
{
|
||||||
if (rendermode == RenderModes.Static || resource.ResourceType == ResourceType.Stylesheet || resource.Level == ResourceLevel.Site)
|
if (rendermode == RenderModes.Static || resource.ResourceType == ResourceType.Stylesheet || resource.Level == ResourceLevel.Site)
|
||||||
{
|
{
|
||||||
if (resource.Url.StartsWith("~"))
|
if (!string.IsNullOrEmpty(resource.Url) && resource.Url.StartsWith("~"))
|
||||||
{
|
{
|
||||||
resource.Url = resource.Url.Replace("~", "/" + type + "/" + name + "/").Replace("//", "/");
|
resource.Url = resource.Url.Replace("~", "/" + type + "/" + name + "/").Replace("//", "/");
|
||||||
}
|
}
|
||||||
if (!resource.Url.Contains("://") && alias.BaseUrl != "" && !resource.Url.StartsWith(alias.BaseUrl))
|
if (!string.IsNullOrEmpty(resource.Url) && !resource.Url.Contains("://") && alias.BaseUrl != "" && !resource.Url.StartsWith(alias.BaseUrl))
|
||||||
{
|
{
|
||||||
resource.Url = alias.BaseUrl + resource.Url;
|
resource.Url = alias.BaseUrl + resource.Url;
|
||||||
}
|
}
|
||||||
@@ -803,4 +785,71 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void AddBodyContent(string content)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(content))
|
||||||
|
{
|
||||||
|
var elements = content.Split('<', StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
foreach (var element in elements)
|
||||||
|
{
|
||||||
|
if (_renderMode == RenderModes.Static || (!element.ToLower().StartsWith("script") && !element.ToLower().StartsWith("/script")))
|
||||||
|
{
|
||||||
|
if (!_bodyContent.Contains("<" + element) || element.StartsWith("/"))
|
||||||
|
{
|
||||||
|
_bodyContent += "<" + element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_bodyContent += "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ManageLocalization(Site site)
|
||||||
|
{
|
||||||
|
// get user culture (ui localization)
|
||||||
|
var uiCulture = site?.User?.CultureCode;
|
||||||
|
if (string.IsNullOrEmpty(uiCulture))
|
||||||
|
{
|
||||||
|
// get default language for site
|
||||||
|
if (site.Languages.Any())
|
||||||
|
{
|
||||||
|
// use default language if specified otherwise use first language in collection
|
||||||
|
uiCulture = (site.Languages.Where(l => l.IsDefault).SingleOrDefault() ?? site.Languages.First()).Code;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// fallback language
|
||||||
|
uiCulture = LocalizationManager.GetDefaultCulture();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get site culture (content localization)
|
||||||
|
var culture = site?.CultureCode;
|
||||||
|
if (string.IsNullOrEmpty(culture))
|
||||||
|
{
|
||||||
|
culture = uiCulture;
|
||||||
|
}
|
||||||
|
_language = culture; // html element language attribute
|
||||||
|
|
||||||
|
// get culture cookie
|
||||||
|
string cultureCookie = Context.Request.Cookies[Shared.CookieRequestCultureProvider.DefaultCookieName];
|
||||||
|
if (cultureCookie != null)
|
||||||
|
{
|
||||||
|
// verify culture cookie (which could be inaccurate when using subfolders ie. domain.com/fr as cookies are based on domain)
|
||||||
|
var requestCulture = Shared.CookieRequestCultureProvider.ParseCookieValue(cultureCookie);
|
||||||
|
if (culture != requestCulture.Culture.Name || uiCulture != requestCulture.UICulture.Name)
|
||||||
|
{
|
||||||
|
// convert to culture cookie format (ie. "c=en|uic=en") and save cookie
|
||||||
|
cultureCookie = Shared.CookieRequestCultureProvider.MakeCookieValue(new Models.RequestCulture(culture, uiCulture));
|
||||||
|
SetLocalizationCookie(cultureCookie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// convert to culture cookie format (ie. "c=en|uic=en") and save cookie
|
||||||
|
cultureCookie = Shared.CookieRequestCultureProvider.MakeCookieValue(new Models.RequestCulture(culture, uiCulture));
|
||||||
|
SetLocalizationCookie(cultureCookie);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ namespace Oqtane.Controllers
|
|||||||
int SiteId;
|
int SiteId;
|
||||||
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
||||||
{
|
{
|
||||||
var hierarchy = GetFoldersHierarchy(_folders.GetFolders(SiteId).ToList());
|
var hierarchy = _folders.GetFolders(SiteId).ToList();
|
||||||
foreach (Folder folder in hierarchy)
|
foreach (Folder folder in hierarchy)
|
||||||
{
|
{
|
||||||
// note that Browse permission is used for this method
|
// note that Browse permission is used for this method
|
||||||
@@ -281,47 +281,5 @@ namespace Oqtane.Controllers
|
|||||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Folder> GetFoldersHierarchy(List<Folder> folders)
|
|
||||||
{
|
|
||||||
List<Folder> hierarchy = new List<Folder>();
|
|
||||||
Action<List<Folder>, Folder> getPath = null;
|
|
||||||
getPath = (folderList, folder) =>
|
|
||||||
{
|
|
||||||
IEnumerable<Folder> children;
|
|
||||||
int level;
|
|
||||||
if (folder == null)
|
|
||||||
{
|
|
||||||
level = -1;
|
|
||||||
children = folders.Where(item => item.ParentId == null);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
level = folder.Level;
|
|
||||||
children = folders.Where(item => item.ParentId == folder.FolderId);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (Folder child in children)
|
|
||||||
{
|
|
||||||
child.Level = level + 1;
|
|
||||||
child.HasChildren = folders.Any(item => item.ParentId == child.FolderId);
|
|
||||||
hierarchy.Add(child);
|
|
||||||
getPath(folderList, child);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
folders = folders.OrderBy(item => item.Name).ToList();
|
|
||||||
getPath(folders, null);
|
|
||||||
|
|
||||||
// add any non-hierarchical items to the end of the list
|
|
||||||
foreach (Folder folder in folders)
|
|
||||||
{
|
|
||||||
if (hierarchy.Find(item => item.FolderId == folder.FolderId) == null)
|
|
||||||
{
|
|
||||||
hierarchy.Add(folder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return hierarchy;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,26 +19,54 @@ namespace Oqtane.Controllers
|
|||||||
_localizationManager = localizationManager;
|
_localizationManager = localizationManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET: api/localization
|
// GET: api/localization?installed=true/false
|
||||||
[HttpGet()]
|
[HttpGet()]
|
||||||
public IEnumerable<Culture> Get(bool installed)
|
public IEnumerable<Culture> Get(bool installed)
|
||||||
{
|
{
|
||||||
string[] culturecodes;
|
string[] cultureCodes;
|
||||||
if (installed)
|
if (installed)
|
||||||
{
|
{
|
||||||
culturecodes = _localizationManager.GetInstalledCultures();
|
cultureCodes = _localizationManager.GetInstalledCultures();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
culturecodes = _localizationManager.GetSupportedCultures();
|
cultureCodes = _localizationManager.GetSupportedCultures();
|
||||||
}
|
}
|
||||||
var cultures = culturecodes.Select(c => new Culture
|
|
||||||
|
var cultures = cultureCodes.Select(c => new Culture
|
||||||
{
|
{
|
||||||
Name = CultureInfo.GetCultureInfo(c).Name,
|
Name = CultureInfo.GetCultureInfo(c).Name,
|
||||||
DisplayName = CultureInfo.GetCultureInfo(c).DisplayName,
|
DisplayName = CultureInfo.GetCultureInfo(c).DisplayName,
|
||||||
IsDefault = _localizationManager.GetDefaultCulture()
|
IsDefault = _localizationManager.GetDefaultCulture()
|
||||||
.Equals(CultureInfo.GetCultureInfo(c).Name, StringComparison.OrdinalIgnoreCase)
|
.Equals(CultureInfo.GetCultureInfo(c).Name, StringComparison.OrdinalIgnoreCase)
|
||||||
});
|
}).ToList();
|
||||||
|
|
||||||
|
if (cultures.Count == 0)
|
||||||
|
{
|
||||||
|
cultures.Add(new Culture { Name = "en", DisplayName = "English", IsDefault = true });
|
||||||
|
}
|
||||||
|
|
||||||
|
return cultures.OrderBy(item => item.DisplayName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET: api/localization/neutral
|
||||||
|
[HttpGet("neutral")]
|
||||||
|
public IEnumerable<Culture> Get()
|
||||||
|
{
|
||||||
|
var cultureCodes = _localizationManager.GetNeutralCultures();
|
||||||
|
|
||||||
|
var cultures = cultureCodes.Select(c => new Culture
|
||||||
|
{
|
||||||
|
Name = CultureInfo.GetCultureInfo(c).Name,
|
||||||
|
DisplayName = CultureInfo.GetCultureInfo(c).DisplayName,
|
||||||
|
IsDefault = false
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
if (cultures.Count == 0)
|
||||||
|
{
|
||||||
|
cultures.Add(new Culture { Name = "en", DisplayName = "English", IsDefault = false });
|
||||||
|
}
|
||||||
|
|
||||||
return cultures.OrderBy(item => item.DisplayName);
|
return cultures.OrderBy(item => item.DisplayName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,6 +164,7 @@ namespace Oqtane.Controllers
|
|||||||
{
|
{
|
||||||
_moduleDefinitions.UpdateModuleDefinition(moduleDefinition);
|
_moduleDefinitions.UpdateModuleDefinition(moduleDefinition);
|
||||||
_syncManager.AddSyncEvent(_alias, EntityNames.ModuleDefinition, moduleDefinition.ModuleDefinitionId, SyncEventActions.Update);
|
_syncManager.AddSyncEvent(_alias, EntityNames.ModuleDefinition, moduleDefinition.ModuleDefinitionId, SyncEventActions.Update);
|
||||||
|
_syncManager.AddSyncEvent(_alias, EntityNames.Site, _alias.SiteId, SyncEventActions.Refresh); // fingerprint changed
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Module Definition Updated {ModuleDefinition}", moduleDefinition);
|
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Module Definition Updated {ModuleDefinition}", moduleDefinition);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Oqtane.Models;
|
|
||||||
using Oqtane.Shared;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Oqtane.Security;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Security;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Oqtane.Enums;
|
using Oqtane.Enums;
|
||||||
using Oqtane.Infrastructure;
|
using Oqtane.Infrastructure;
|
||||||
|
using Oqtane.Models;
|
||||||
using Oqtane.Repository;
|
using Oqtane.Repository;
|
||||||
using System.Xml.Linq;
|
using Oqtane.Security;
|
||||||
using Microsoft.AspNetCore.Diagnostics;
|
using Oqtane.Shared;
|
||||||
|
|
||||||
namespace Oqtane.Controllers
|
namespace Oqtane.Controllers
|
||||||
{
|
{
|
||||||
@@ -498,6 +497,91 @@ namespace Oqtane.Controllers
|
|||||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// POST api/<controller>/5/6
|
||||||
|
[HttpPost("{fromPageId}/{toPageId}/{usePagePermissions}")]
|
||||||
|
[Authorize(Roles = RoleNames.Registered)]
|
||||||
|
public void Post(int fromPageId, int toPageId, bool usePagePermissions)
|
||||||
|
{
|
||||||
|
var fromPage = _pages.GetPage(fromPageId);
|
||||||
|
if (fromPage != null && fromPage.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.View, fromPage.PermissionList))
|
||||||
|
{
|
||||||
|
var toPage = _pages.GetPage(toPageId);
|
||||||
|
if (toPage != null && toPage.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.View, toPage.PermissionList))
|
||||||
|
{
|
||||||
|
// copy modules
|
||||||
|
List<PageModule> pageModules = _pageModules.GetPageModules(fromPage.SiteId).ToList();
|
||||||
|
foreach (PageModule pm in pageModules.Where(item => item.PageId == fromPage.PageId && !item.Module.AllPages && !item.IsDeleted))
|
||||||
|
{
|
||||||
|
Module module;
|
||||||
|
|
||||||
|
// determine if module is a shared instance (ie. exists on other pages)
|
||||||
|
if (!pageModules.Any(item => item.ModuleId == pm.ModuleId && item.PageId != fromPage.PageId))
|
||||||
|
{
|
||||||
|
// create new module
|
||||||
|
module = new Module();
|
||||||
|
module.SiteId = fromPage.SiteId;
|
||||||
|
module.PageId = toPageId;
|
||||||
|
module.ModuleDefinitionName = pm.Module.ModuleDefinitionName;
|
||||||
|
module.AllPages = false;
|
||||||
|
if (usePagePermissions)
|
||||||
|
{
|
||||||
|
module.PermissionList = toPage.PermissionList;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
module.PermissionList = pm.Module.PermissionList;
|
||||||
|
}
|
||||||
|
module.PermissionList = module.PermissionList.Select(item => new Permission
|
||||||
|
{
|
||||||
|
SiteId = item.SiteId,
|
||||||
|
EntityName = EntityNames.Module,
|
||||||
|
EntityId = -1,
|
||||||
|
PermissionName = item.PermissionName,
|
||||||
|
RoleName = item.RoleName,
|
||||||
|
UserId = item.UserId,
|
||||||
|
IsAuthorized = item.IsAuthorized,
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
module = _modules.AddModule(module);
|
||||||
|
string content = _modules.ExportModule(pm.ModuleId);
|
||||||
|
if (content != "")
|
||||||
|
{
|
||||||
|
_modules.ImportModule(module.ModuleId, content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// use existing module
|
||||||
|
module = pm.Module;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PageModule pageModule = new PageModule();
|
||||||
|
pageModule.PageId = toPageId;
|
||||||
|
pageModule.ModuleId = module.ModuleId;
|
||||||
|
pageModule.Title = pm.Title;
|
||||||
|
pageModule.Pane = pm.Pane;
|
||||||
|
pageModule.Order = pm.Order;
|
||||||
|
pageModule.ContainerType = pm.ContainerType;
|
||||||
|
pageModule.EffectiveDate = pm.EffectiveDate;
|
||||||
|
pageModule.ExpiryDate = pm.ExpiryDate;
|
||||||
|
pageModule.Header = pm.Header;
|
||||||
|
pageModule.Footer = pm.Footer;
|
||||||
|
|
||||||
|
_pageModules.AddPageModule(pageModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
_syncManager.AddSyncEvent(_alias, EntityNames.Site, fromPage.SiteId, SyncEventActions.Refresh);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
135
Oqtane.Server/Controllers/SiteGroupController.cs
Normal file
135
Oqtane.Server/Controllers/SiteGroupController.cs
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Security.Policy;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Oqtane.Enums;
|
||||||
|
using Oqtane.Infrastructure;
|
||||||
|
using Oqtane.Models;
|
||||||
|
using Oqtane.Repository;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
|
namespace Oqtane.Controllers
|
||||||
|
{
|
||||||
|
[Route(ControllerRoutes.ApiRoute)]
|
||||||
|
public class SiteGroupController : Controller
|
||||||
|
{
|
||||||
|
private readonly ISiteGroupRepository _siteGroupRepository;
|
||||||
|
private readonly ISyncManager _syncManager;
|
||||||
|
private readonly ILogManager _logger;
|
||||||
|
private readonly Alias _alias;
|
||||||
|
|
||||||
|
public SiteGroupController(ISiteGroupRepository siteGroupRepository, ISyncManager syncManager, ILogManager logger, ITenantManager tenantManager)
|
||||||
|
{
|
||||||
|
_siteGroupRepository = siteGroupRepository;
|
||||||
|
_syncManager = syncManager;
|
||||||
|
_logger = logger;
|
||||||
|
_alias = tenantManager.GetAlias();
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET: api/<controller>?siteid=x
|
||||||
|
[HttpGet]
|
||||||
|
[Authorize(Roles = RoleNames.Admin)]
|
||||||
|
public IEnumerable<SiteGroup> Get(string siteid)
|
||||||
|
{
|
||||||
|
if (User.IsInRole(RoleNames.Host) || (int.TryParse(siteid, out int SiteId) && SiteId == _alias.SiteId))
|
||||||
|
{
|
||||||
|
var siteGroups = _siteGroupRepository.GetSiteGroups();
|
||||||
|
if (!User.IsInRole(RoleNames.Host))
|
||||||
|
{
|
||||||
|
siteGroups = siteGroups.Where(item => item.PrimarySiteId == _alias.SiteId);
|
||||||
|
}
|
||||||
|
return siteGroups.ToList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Group Get Attempt {SiteId}", siteid);
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET api/<controller>/5
|
||||||
|
[HttpGet("{id}")]
|
||||||
|
[Authorize(Roles = RoleNames.Host)]
|
||||||
|
public SiteGroup Get(int id)
|
||||||
|
{
|
||||||
|
var group = _siteGroupRepository.GetSiteGroup(id);
|
||||||
|
if (group != null)
|
||||||
|
{
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST api/<controller>
|
||||||
|
[HttpPost]
|
||||||
|
[Authorize(Roles = RoleNames.Host)]
|
||||||
|
public SiteGroup Post([FromBody] SiteGroup siteGroup)
|
||||||
|
{
|
||||||
|
if (ModelState.IsValid)
|
||||||
|
{
|
||||||
|
siteGroup = _siteGroupRepository.AddSiteGroup(siteGroup);
|
||||||
|
_syncManager.AddSyncEvent(_alias, EntityNames.SiteGroup, siteGroup.SiteGroupId, SyncEventActions.Create);
|
||||||
|
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Site Group Added {Group}", siteGroup);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Group Post Attempt {Group}", siteGroup);
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
|
siteGroup = null;
|
||||||
|
}
|
||||||
|
return siteGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PUT api/<controller>/5
|
||||||
|
[HttpPut("{id}")]
|
||||||
|
[Authorize(Roles = RoleNames.Admin)]
|
||||||
|
public SiteGroup Put(int id, [FromBody] SiteGroup siteGroup)
|
||||||
|
{
|
||||||
|
if (ModelState.IsValid && siteGroup.SiteGroupId == id)
|
||||||
|
{
|
||||||
|
if (!User.IsInRole(RoleNames.Host) && siteGroup.Synchronize)
|
||||||
|
{
|
||||||
|
// admins can only update the synchronize field
|
||||||
|
siteGroup = _siteGroupRepository.GetSiteGroup(siteGroup.SiteGroupId, false);
|
||||||
|
siteGroup.Synchronize = true;
|
||||||
|
}
|
||||||
|
siteGroup = _siteGroupRepository.UpdateSiteGroup(siteGroup);
|
||||||
|
_syncManager.AddSyncEvent(_alias, EntityNames.SiteGroup, siteGroup.SiteGroupId, SyncEventActions.Update);
|
||||||
|
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Site Group Updated {Group}", siteGroup);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Group Put Attempt {Group}", siteGroup);
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
|
siteGroup = null;
|
||||||
|
}
|
||||||
|
return siteGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DELETE api/<controller>/5
|
||||||
|
[HttpDelete("{id}")]
|
||||||
|
[Authorize(Roles = RoleNames.Host)]
|
||||||
|
public void Delete(int id)
|
||||||
|
{
|
||||||
|
var siteGroup = _siteGroupRepository.GetSiteGroup(id);
|
||||||
|
if (siteGroup != null)
|
||||||
|
{
|
||||||
|
_siteGroupRepository.DeleteSiteGroup(id);
|
||||||
|
_syncManager.AddSyncEvent(_alias, EntityNames.SiteGroup, siteGroup.SiteGroupId, SyncEventActions.Delete);
|
||||||
|
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Site Group Deleted {siteGroupId}", id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Group Delete Attempt {siteGroupId}", id);
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
126
Oqtane.Server/Controllers/SiteGroupMemberController.cs
Normal file
126
Oqtane.Server/Controllers/SiteGroupMemberController.cs
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Oqtane.Enums;
|
||||||
|
using Oqtane.Infrastructure;
|
||||||
|
using Oqtane.Models;
|
||||||
|
using Oqtane.Repository;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
|
namespace Oqtane.Controllers
|
||||||
|
{
|
||||||
|
[Route(ControllerRoutes.ApiRoute)]
|
||||||
|
public class SiteGroupMemberController : Controller
|
||||||
|
{
|
||||||
|
private readonly ISiteGroupMemberRepository _siteGroupMemberRepository;
|
||||||
|
private readonly ISyncManager _syncManager;
|
||||||
|
private readonly ILogManager _logger;
|
||||||
|
private readonly Alias _alias;
|
||||||
|
|
||||||
|
public SiteGroupMemberController(ISiteGroupMemberRepository siteGroupMemberRepository, ISyncManager syncManager, ILogManager logger, ITenantManager tenantManager)
|
||||||
|
{
|
||||||
|
_siteGroupMemberRepository = siteGroupMemberRepository;
|
||||||
|
_syncManager = syncManager;
|
||||||
|
_logger = logger;
|
||||||
|
_alias = tenantManager.GetAlias();
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET: api/<controller>?siteid=x&groupid=y
|
||||||
|
[HttpGet]
|
||||||
|
[Authorize(Roles = RoleNames.Host)]
|
||||||
|
public IEnumerable<SiteGroupMember> Get(string siteid, string groupid)
|
||||||
|
{
|
||||||
|
if (int.TryParse(siteid, out int SiteId) && int.TryParse(groupid, out int SiteGroupId))
|
||||||
|
{
|
||||||
|
return _siteGroupMemberRepository.GetSiteGroupMembers(SiteId, SiteGroupId).ToList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Group Member Get Attempt for SiteId {SiteId} And SiteGroupId {SiteGroupId}", siteid, groupid);
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET api/<controller>/5
|
||||||
|
[HttpGet("{id}")]
|
||||||
|
[Authorize(Roles = RoleNames.Host)]
|
||||||
|
public SiteGroupMember Get(int id)
|
||||||
|
{
|
||||||
|
var siteGroupMember = _siteGroupMemberRepository.GetSiteGroupMember(id);
|
||||||
|
if (siteGroupMember != null)
|
||||||
|
{
|
||||||
|
return siteGroupMember;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST api/<controller>
|
||||||
|
[HttpPost]
|
||||||
|
[Authorize(Roles = RoleNames.Host)]
|
||||||
|
public SiteGroupMember Post([FromBody] SiteGroupMember siteGroupMember)
|
||||||
|
{
|
||||||
|
if (ModelState.IsValid)
|
||||||
|
{
|
||||||
|
siteGroupMember = _siteGroupMemberRepository.AddSiteGroupMember(siteGroupMember);
|
||||||
|
_syncManager.AddSyncEvent(_alias, EntityNames.SiteGroupMember, siteGroupMember.SiteGroupId, SyncEventActions.Create);
|
||||||
|
_syncManager.AddSyncEvent(_alias, EntityNames.Site, siteGroupMember.SiteId, SyncEventActions.Refresh);
|
||||||
|
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Site Group Member Added {SiteGroupMember}", siteGroupMember);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Group Member Post Attempt {SiteGroupMember}", siteGroupMember);
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
|
siteGroupMember = null;
|
||||||
|
}
|
||||||
|
return siteGroupMember;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PUT api/<controller>/5
|
||||||
|
[HttpPut("{id}")]
|
||||||
|
[Authorize(Roles = RoleNames.Host)]
|
||||||
|
public SiteGroupMember Put(int id, [FromBody] SiteGroupMember siteGroupMember)
|
||||||
|
{
|
||||||
|
if (ModelState.IsValid && siteGroupMember.SiteGroupId == id && _siteGroupMemberRepository.GetSiteGroupMember(siteGroupMember.SiteGroupId, false) != null)
|
||||||
|
{
|
||||||
|
siteGroupMember = _siteGroupMemberRepository.UpdateSiteGroupMember(siteGroupMember);
|
||||||
|
_syncManager.AddSyncEvent(_alias, EntityNames.SiteGroupMember, siteGroupMember.SiteGroupId, SyncEventActions.Update);
|
||||||
|
_syncManager.AddSyncEvent(_alias, EntityNames.Site, siteGroupMember.SiteId, SyncEventActions.Refresh);
|
||||||
|
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Site Group Member Updated {SiteGroupMember}", siteGroupMember);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Group Member Put Attempt {SiteGroupMember}", siteGroupMember);
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
|
siteGroupMember = null;
|
||||||
|
}
|
||||||
|
return siteGroupMember;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DELETE api/<controller>/5
|
||||||
|
[HttpDelete("{id}")]
|
||||||
|
[Authorize(Roles = RoleNames.Host)]
|
||||||
|
public void Delete(int id)
|
||||||
|
{
|
||||||
|
var siteGroupMember = _siteGroupMemberRepository.GetSiteGroupMember(id);
|
||||||
|
if (siteGroupMember != null)
|
||||||
|
{
|
||||||
|
_siteGroupMemberRepository.DeleteSiteGroupMember(id);
|
||||||
|
_syncManager.AddSyncEvent(_alias, EntityNames.SiteGroupMember, siteGroupMember.SiteGroupMemberId, SyncEventActions.Delete);
|
||||||
|
_syncManager.AddSyncEvent(_alias, EntityNames.Site, siteGroupMember.SiteId, SyncEventActions.Refresh);
|
||||||
|
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Site Group Member Deleted {SiteGroupMemberId}", id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Group Member Delete Attempt {SiteGroupMemberId}", id);
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
63
Oqtane.Server/Controllers/SiteTaskController.cs
Normal file
63
Oqtane.Server/Controllers/SiteTaskController.cs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
using System.Net;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Oqtane.Enums;
|
||||||
|
using Oqtane.Infrastructure;
|
||||||
|
using Oqtane.Models;
|
||||||
|
using Oqtane.Repository;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
|
namespace Oqtane.Controllers
|
||||||
|
{
|
||||||
|
[Route(ControllerRoutes.ApiRoute)]
|
||||||
|
public class SiteTaskController : Controller
|
||||||
|
{
|
||||||
|
private readonly ISiteTaskRepository _siteTasks;
|
||||||
|
private readonly ILogManager _logger;
|
||||||
|
private readonly Alias _alias;
|
||||||
|
|
||||||
|
public SiteTaskController(ISiteTaskRepository siteTasks, ILogManager logger, ITenantManager tenantManager)
|
||||||
|
{
|
||||||
|
_siteTasks = siteTasks;
|
||||||
|
_logger = logger;
|
||||||
|
_alias = tenantManager.GetAlias();
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET api/<controller>/5
|
||||||
|
[HttpGet("{id}")]
|
||||||
|
[Authorize(Roles = RoleNames.Admin)]
|
||||||
|
public SiteTask Get(int id)
|
||||||
|
{
|
||||||
|
var siteTask = _siteTasks.GetSiteTask(id);
|
||||||
|
if (siteTask.SiteId == _alias.SiteId)
|
||||||
|
{
|
||||||
|
return siteTask;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST api/<controller>
|
||||||
|
[HttpPost]
|
||||||
|
[Authorize(Roles = RoleNames.Admin)]
|
||||||
|
public SiteTask Post([FromBody] SiteTask siteTask)
|
||||||
|
{
|
||||||
|
if (ModelState.IsValid && siteTask.SiteId == _alias.SiteId)
|
||||||
|
{
|
||||||
|
siteTask.IsCompleted = false;
|
||||||
|
siteTask = _siteTasks.AddSiteTask(siteTask);
|
||||||
|
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Site Task Added {SiteTask}", siteTask);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Site Task Post Attempt {SiteTask}", siteTask);
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
|
siteTask = null;
|
||||||
|
}
|
||||||
|
return siteTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -117,6 +117,7 @@ namespace Oqtane.Controllers
|
|||||||
{
|
{
|
||||||
_themes.UpdateTheme(theme);
|
_themes.UpdateTheme(theme);
|
||||||
_syncManager.AddSyncEvent(_alias, EntityNames.Theme, theme.ThemeId, SyncEventActions.Update);
|
_syncManager.AddSyncEvent(_alias, EntityNames.Theme, theme.ThemeId, SyncEventActions.Update);
|
||||||
|
_syncManager.AddSyncEvent(_alias, EntityNames.Site, _alias.SiteId, SyncEventActions.Refresh); // fingerprint changed
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Theme Updated {Theme}", theme);
|
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Theme Updated {Theme}", theme);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -418,42 +418,6 @@ namespace Oqtane.Controllers
|
|||||||
return requirements;
|
return requirements;
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST api/<controller>/import?siteid=x&fileid=y¬ify=z
|
|
||||||
[HttpPost("import")]
|
|
||||||
[Authorize(Roles = RoleNames.Admin)]
|
|
||||||
public async Task<Dictionary<string, string>> Import(string siteid, string fileid, string notify)
|
|
||||||
{
|
|
||||||
if (int.TryParse(siteid, out int SiteId) && SiteId == _tenantManager.GetAlias().SiteId && int.TryParse(fileid, out int FileId) && bool.TryParse(notify, out bool Notify))
|
|
||||||
{
|
|
||||||
var file = _files.GetFile(FileId);
|
|
||||||
if (file != null)
|
|
||||||
{
|
|
||||||
if (_userPermissions.IsAuthorized(User, PermissionNames.View, file.Folder.PermissionList))
|
|
||||||
{
|
|
||||||
return await _userManager.ImportUsers(SiteId, _files.GetFilePath(file), Notify);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Import Attempt {SiteId} {FileId}", siteid, fileid);
|
|
||||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Import File Does Not Exist {SiteId} {FileId}", siteid, fileid);
|
|
||||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Import Attempt {SiteId} {FileId}", siteid, fileid);
|
|
||||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GET: api/<controller>/passkey?id=x
|
// GET: api/<controller>/passkey?id=x
|
||||||
[HttpGet("passkey")]
|
[HttpGet("passkey")]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
|
|||||||
@@ -233,6 +233,9 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||||||
services.AddScoped<ICookieConsentService, ServerCookieConsentService>();
|
services.AddScoped<ICookieConsentService, ServerCookieConsentService>();
|
||||||
services.AddScoped<ITimeZoneService, TimeZoneService>();
|
services.AddScoped<ITimeZoneService, TimeZoneService>();
|
||||||
services.AddScoped<IMigrationHistoryService, MigrationHistoryService>();
|
services.AddScoped<IMigrationHistoryService, MigrationHistoryService>();
|
||||||
|
services.AddScoped<ISiteGroupService, SiteGroupService>();
|
||||||
|
services.AddScoped<ISiteGroupMemberService, SiteGroupMemberService>();
|
||||||
|
services.AddScoped<ISiteTaskService, SiteTaskService>();
|
||||||
|
|
||||||
// providers
|
// providers
|
||||||
services.AddScoped<ITextEditor, Oqtane.Modules.Controls.QuillJSTextEditor>();
|
services.AddScoped<ITextEditor, Oqtane.Modules.Controls.QuillJSTextEditor>();
|
||||||
@@ -282,6 +285,9 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||||||
services.AddTransient<IUrlMappingRepository, UrlMappingRepository>();
|
services.AddTransient<IUrlMappingRepository, UrlMappingRepository>();
|
||||||
services.AddTransient<ISearchContentRepository, SearchContentRepository>();
|
services.AddTransient<ISearchContentRepository, SearchContentRepository>();
|
||||||
services.AddTransient<IMigrationHistoryRepository, MigrationHistoryRepository>();
|
services.AddTransient<IMigrationHistoryRepository, MigrationHistoryRepository>();
|
||||||
|
services.AddTransient<ISiteGroupRepository, SiteGroupRepository>();
|
||||||
|
services.AddTransient<ISiteGroupMemberRepository, SiteGroupMemberRepository>();
|
||||||
|
services.AddTransient<ISiteTaskRepository, SiteTaskRepository>();
|
||||||
|
|
||||||
// managers
|
// managers
|
||||||
services.AddTransient<IDBContextDependencies, DBContextDependencies>();
|
services.AddTransient<IDBContextDependencies, DBContextDependencies>();
|
||||||
|
|||||||
@@ -594,7 +594,8 @@ namespace Oqtane.Infrastructure
|
|||||||
Prerender = (rendermode == RenderModes.Interactive),
|
Prerender = (rendermode == RenderModes.Interactive),
|
||||||
Hybrid = false,
|
Hybrid = false,
|
||||||
EnhancedNavigation = true,
|
EnhancedNavigation = true,
|
||||||
TenantId = tenant.TenantId
|
CultureCode = "en",
|
||||||
|
TenantId = tenant.TenantId // required for site creation
|
||||||
};
|
};
|
||||||
site = sites.AddSite(site);
|
site = sites.AddSite(site);
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ namespace Oqtane.Infrastructure
|
|||||||
{
|
{
|
||||||
void InstallPackages();
|
void InstallPackages();
|
||||||
bool UninstallPackage(string PackageName);
|
bool UninstallPackage(string PackageName);
|
||||||
int RegisterAssemblies();
|
|
||||||
Task UpgradeFramework(bool backup);
|
Task UpgradeFramework(bool backup);
|
||||||
void RestartApplication();
|
void RestartApplication();
|
||||||
}
|
}
|
||||||
@@ -61,10 +60,6 @@ namespace Oqtane.Infrastructure
|
|||||||
Directory.CreateDirectory(sourceFolder);
|
Directory.CreateDirectory(sourceFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
// read assembly log
|
|
||||||
var assemblyLogPath = Path.Combine(sourceFolder, "assemblies.log");
|
|
||||||
var assemblies = GetAssemblyLog(assemblyLogPath);
|
|
||||||
|
|
||||||
// install Nuget packages in secure Packages folder
|
// install Nuget packages in secure Packages folder
|
||||||
var packages = Directory.GetFiles(sourceFolder, "*.nupkg");
|
var packages = Directory.GetFiles(sourceFolder, "*.nupkg");
|
||||||
foreach (string packagename in packages)
|
foreach (string packagename in packages)
|
||||||
@@ -162,27 +157,6 @@ namespace Oqtane.Infrastructure
|
|||||||
{
|
{
|
||||||
manifest = true;
|
manifest = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// register assembly
|
|
||||||
if (Path.GetExtension(filename) == ".dll")
|
|
||||||
{
|
|
||||||
// do not register licensing assemblies
|
|
||||||
if (!Path.GetFileName(filename).StartsWith("Oqtane.Licensing."))
|
|
||||||
{
|
|
||||||
// if package version was not installed previously
|
|
||||||
if (!File.Exists(Path.Combine(sourceFolder, name + ".log")))
|
|
||||||
{
|
|
||||||
if (assemblies.ContainsKey(Path.GetFileName(filename)))
|
|
||||||
{
|
|
||||||
assemblies[Path.GetFileName(filename)] += 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
assemblies.Add(Path.GetFileName(filename), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,12 +186,6 @@ namespace Oqtane.Infrastructure
|
|||||||
File.Delete(packagename);
|
File.Delete(packagename);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packages.Length != 0)
|
|
||||||
{
|
|
||||||
// save assembly log
|
|
||||||
SetAssemblyLog(assemblyLogPath, assemblies);
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,10 +238,6 @@ namespace Oqtane.Infrastructure
|
|||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(PackageName))
|
if (!string.IsNullOrEmpty(PackageName))
|
||||||
{
|
{
|
||||||
// read assembly log
|
|
||||||
var assemblyLogPath = Path.Combine(Path.Combine(_environment.ContentRootPath, Constants.PackagesFolder), "assemblies.log");
|
|
||||||
var assemblies = GetAssemblyLog(assemblyLogPath);
|
|
||||||
|
|
||||||
// get manifest with highest version
|
// get manifest with highest version
|
||||||
string packagename = "";
|
string packagename = "";
|
||||||
string[] packages = Directory.GetFiles(Path.Combine(_environment.ContentRootPath, Constants.PackagesFolder), PackageName + "*.log");
|
string[] packages = Directory.GetFiles(Path.Combine(_environment.ContentRootPath, Constants.PackagesFolder), PackageName + "*.log");
|
||||||
@@ -297,24 +261,8 @@ namespace Oqtane.Infrastructure
|
|||||||
{
|
{
|
||||||
// do not remove licensing assemblies
|
// do not remove licensing assemblies
|
||||||
if (!Path.GetFileName(filepath).StartsWith("Oqtane.Licensing."))
|
if (!Path.GetFileName(filepath).StartsWith("Oqtane.Licensing."))
|
||||||
{
|
|
||||||
// use assembly log to determine if assembly is used in other packages
|
|
||||||
if (assemblies.ContainsKey(Path.GetFileName(filepath)))
|
|
||||||
{
|
|
||||||
if (assemblies[Path.GetFileName(filepath)] == 1)
|
|
||||||
{
|
{
|
||||||
DeleteFile(filepath);
|
DeleteFile(filepath);
|
||||||
assemblies.Remove(Path.GetFileName(filepath));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
assemblies[Path.GetFileName(filepath)] -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // does not exist in assembly log
|
|
||||||
{
|
|
||||||
DeleteFile(filepath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // not an assembly
|
else // not an assembly
|
||||||
@@ -329,9 +277,6 @@ namespace Oqtane.Infrastructure
|
|||||||
File.Delete(asset);
|
File.Delete(asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// save assembly log
|
|
||||||
SetAssemblyLog(assemblyLogPath, assemblies);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -351,64 +296,6 @@ namespace Oqtane.Infrastructure
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int RegisterAssemblies()
|
|
||||||
{
|
|
||||||
var assemblyLogPath = GetAssemblyLogPath();
|
|
||||||
var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
|
||||||
|
|
||||||
var assemblies = GetAssemblyLog(assemblyLogPath);
|
|
||||||
|
|
||||||
// remove assemblies that no longer exist
|
|
||||||
foreach (var dll in assemblies)
|
|
||||||
{
|
|
||||||
if (!File.Exists(Path.Combine(binFolder, dll.Key)))
|
|
||||||
{
|
|
||||||
assemblies.Remove(dll.Key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// add assemblies which are not registered
|
|
||||||
foreach (var dll in Directory.GetFiles(binFolder, "*.dll"))
|
|
||||||
{
|
|
||||||
if (!assemblies.ContainsKey(Path.GetFileName(dll)))
|
|
||||||
{
|
|
||||||
assemblies.Add(Path.GetFileName(dll), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SetAssemblyLog(assemblyLogPath, assemblies);
|
|
||||||
|
|
||||||
return assemblies.Count;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetAssemblyLogPath()
|
|
||||||
{
|
|
||||||
string packagesFolder = Path.Combine(_environment.ContentRootPath, Constants.PackagesFolder);
|
|
||||||
if (!Directory.Exists(packagesFolder))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(packagesFolder);
|
|
||||||
}
|
|
||||||
return Path.Combine(packagesFolder, "assemblies.log");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Dictionary<string, int> GetAssemblyLog(string assemblyLogPath)
|
|
||||||
{
|
|
||||||
Dictionary<string, int> assemblies = new Dictionary<string, int>();
|
|
||||||
if (File.Exists(assemblyLogPath))
|
|
||||||
{
|
|
||||||
assemblies = JsonSerializer.Deserialize<Dictionary<string, int>>(File.ReadAllText(assemblyLogPath));
|
|
||||||
}
|
|
||||||
return assemblies;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void SetAssemblyLog(string assemblyLogPath, Dictionary<string, int> assemblies)
|
|
||||||
{
|
|
||||||
if (File.Exists(assemblyLogPath))
|
|
||||||
{
|
|
||||||
File.Delete(assemblyLogPath);
|
|
||||||
}
|
|
||||||
File.WriteAllText(assemblyLogPath, JsonSerializer.Serialize(assemblies, new JsonSerializerOptions { WriteIndented = true }));
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task UpgradeFramework(bool backup)
|
public async Task UpgradeFramework(bool backup)
|
||||||
{
|
{
|
||||||
string folder = Path.Combine(_environment.ContentRootPath, Constants.PackagesFolder);
|
string folder = Path.Combine(_environment.ContentRootPath, Constants.PackagesFolder);
|
||||||
|
|||||||
13
Oqtane.Server/Infrastructure/Interfaces/ISiteTask.cs
Normal file
13
Oqtane.Server/Infrastructure/Interfaces/ISiteTask.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Oqtane.Models;
|
||||||
|
|
||||||
|
namespace Oqtane.Infrastructure
|
||||||
|
{
|
||||||
|
public interface ISiteTask
|
||||||
|
{
|
||||||
|
string ExecuteTask(IServiceProvider provider, Site site, string parameters);
|
||||||
|
|
||||||
|
Task<string> ExecuteTaskAsync(IServiceProvider provider, Site site, string parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,7 +38,7 @@ namespace Oqtane.Infrastructure
|
|||||||
|
|
||||||
// iterate through sites for current tenant
|
// iterate through sites for current tenant
|
||||||
List<Site> sites = siteRepository.GetSites().ToList();
|
List<Site> sites = siteRepository.GetSites().ToList();
|
||||||
foreach (Site site in sites)
|
foreach (Site site in sites.Where(item => !item.IsDeleted))
|
||||||
{
|
{
|
||||||
log += "Processing Notifications For Site: " + site.Name + "<br />";
|
log += "Processing Notifications For Site: " + site.Name + "<br />";
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ namespace Oqtane.Infrastructure
|
|||||||
// get site settings
|
// get site settings
|
||||||
var settings = settingRepository.GetSettings(EntityNames.Site, site.SiteId, EntityNames.Host, -1);
|
var settings = settingRepository.GetSettings(EntityNames.Site, site.SiteId, EntityNames.Host, -1);
|
||||||
|
|
||||||
if (!site.IsDeleted && settingRepository.GetSettingValue(settings, "SMTPEnabled", "True") == "True")
|
if (settingRepository.GetSettingValue(settings, "SMTPEnabled", "True") == "True")
|
||||||
{
|
{
|
||||||
bool valid = true;
|
bool valid = true;
|
||||||
if (settingRepository.GetSettingValue(settings, "SMTPAuthentication", "Basic") == "Basic")
|
if (settingRepository.GetSettingValue(settings, "SMTPAuthentication", "Basic") == "Basic")
|
||||||
@@ -121,12 +121,24 @@ namespace Oqtane.Infrastructure
|
|||||||
{
|
{
|
||||||
if (settingRepository.GetSettingValue(settings, "SMTPAuthentication", "Basic") == "Basic")
|
if (settingRepository.GetSettingValue(settings, "SMTPAuthentication", "Basic") == "Basic")
|
||||||
{
|
{
|
||||||
// it is possible to use basic without any authentication (not recommended)
|
|
||||||
if (settingRepository.GetSettingValue(settings, "SMTPUsername", "") != "" && settingRepository.GetSettingValue(settings, "SMTPPassword", "") != "")
|
if (settingRepository.GetSettingValue(settings, "SMTPUsername", "") != "" && settingRepository.GetSettingValue(settings, "SMTPPassword", "") != "")
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
await client.AuthenticateAsync(settingRepository.GetSettingValue(settings, "SMTPUsername", ""),
|
await client.AuthenticateAsync(settingRepository.GetSettingValue(settings, "SMTPUsername", ""),
|
||||||
settingRepository.GetSettingValue(settings, "SMTPPassword", ""));
|
settingRepository.GetSettingValue(settings, "SMTPPassword", ""));
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
log += "SMTP Not Configured Properly In Site Settings - Basic Authentication Failed Using Username And Password - " + ex.Message + "<br />";
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// it is possible to use basic without any authentication (not recommended)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -278,7 +290,7 @@ namespace Oqtane.Infrastructure
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log += "Site Deleted Or SMTP Disabled In Site Settings<br />";
|
log += "SMTP Disabled In Site Settings<br />";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -33,11 +33,11 @@ namespace Oqtane.Infrastructure
|
|||||||
var visitorRepository = provider.GetRequiredService<IVisitorRepository>();
|
var visitorRepository = provider.GetRequiredService<IVisitorRepository>();
|
||||||
var notificationRepository = provider.GetRequiredService<INotificationRepository>();
|
var notificationRepository = provider.GetRequiredService<INotificationRepository>();
|
||||||
var urlMappingRepository = provider.GetRequiredService<IUrlMappingRepository>();
|
var urlMappingRepository = provider.GetRequiredService<IUrlMappingRepository>();
|
||||||
var installationManager = provider.GetRequiredService<IInstallationManager>();
|
var siteTaskRepository = provider.GetRequiredService<ISiteTaskRepository>();
|
||||||
|
|
||||||
// iterate through sites for current tenant
|
// iterate through sites for current tenant
|
||||||
List<Site> sites = siteRepository.GetSites().ToList();
|
List<Site> sites = siteRepository.GetSites().ToList();
|
||||||
foreach (Site site in sites)
|
foreach (Site site in sites.Where(item => !item.IsDeleted))
|
||||||
{
|
{
|
||||||
log += "<br />Processing Site: " + site.Name + "<br />";
|
log += "<br />Processing Site: " + site.Name + "<br />";
|
||||||
int count;
|
int count;
|
||||||
@@ -95,17 +95,18 @@ namespace Oqtane.Infrastructure
|
|||||||
{
|
{
|
||||||
log += $"Error Purging Broken Urls - {ex.Message}<br />";
|
log += $"Error Purging Broken Urls - {ex.Message}<br />";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// register assemblies
|
// purge completed site tasks
|
||||||
|
retention = 30; // 30 day default
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var assemblies = installationManager.RegisterAssemblies();
|
count = siteTaskRepository.DeleteSiteTasks(site.SiteId, retention);
|
||||||
log += "<br />" + assemblies.ToString() + " Assemblies Registered<br />";
|
log += count.ToString() + " Completed Tasks Purged<br />";
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
log += $"<br />Error Registering Assemblies - {ex.Message}<br />";
|
log += $"Error Purging Completed Site Tasks - {ex.Message}<br />";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return log;
|
return log;
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ namespace Oqtane.Infrastructure
|
|||||||
var searchService = provider.GetRequiredService<ISearchService>();
|
var searchService = provider.GetRequiredService<ISearchService>();
|
||||||
|
|
||||||
var sites = siteRepository.GetSites().ToList();
|
var sites = siteRepository.GetSites().ToList();
|
||||||
foreach (var site in sites)
|
foreach (var site in sites.Where(item => !item.IsDeleted))
|
||||||
{
|
{
|
||||||
log += $"Indexing Site: {site.Name}<br />";
|
log += $"Indexing Site: {site.Name}<br />";
|
||||||
|
|
||||||
|
|||||||
84
Oqtane.Server/Infrastructure/Jobs/SiteTaskJob.cs
Normal file
84
Oqtane.Server/Infrastructure/Jobs/SiteTaskJob.cs
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Oqtane.Repository;
|
||||||
|
|
||||||
|
namespace Oqtane.Infrastructure
|
||||||
|
{
|
||||||
|
public class SiteTaskJob : HostedServiceBase
|
||||||
|
{
|
||||||
|
public SiteTaskJob(IServiceScopeFactory serviceScopeFactory) : base(serviceScopeFactory)
|
||||||
|
{
|
||||||
|
Name = "Site Task Job";
|
||||||
|
Frequency = "m"; // run every minute
|
||||||
|
Interval = 1;
|
||||||
|
IsEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// job is executed for each tenant in installation
|
||||||
|
public override async Task<string> ExecuteJobAsync(IServiceProvider provider)
|
||||||
|
{
|
||||||
|
var log = "";
|
||||||
|
|
||||||
|
// resolve services
|
||||||
|
var tenantManager = provider.GetRequiredService<ITenantManager>();
|
||||||
|
var siteRepository = provider.GetRequiredService<ISiteRepository>();
|
||||||
|
var siteTaskRepository = provider.GetRequiredService<ISiteTaskRepository>();
|
||||||
|
|
||||||
|
var tenant = tenantManager.GetTenant();
|
||||||
|
|
||||||
|
// iterate through sites for current tenant
|
||||||
|
var sites = siteRepository.GetSites().ToList();
|
||||||
|
foreach (var site in sites.Where(item => !item.IsDeleted))
|
||||||
|
{
|
||||||
|
log += $"Processing Site: {site.Name}<br />";
|
||||||
|
|
||||||
|
// get incomplete tasks for site
|
||||||
|
var tasks = siteTaskRepository.GetSiteTasks(site.SiteId).ToList();
|
||||||
|
if (tasks != null && tasks.Any())
|
||||||
|
{
|
||||||
|
foreach (var task in tasks)
|
||||||
|
{
|
||||||
|
log += $"Executing Task: {task.Name}<br />";
|
||||||
|
|
||||||
|
Type taskType = Type.GetType(task.Type);
|
||||||
|
if (taskType != null && taskType.GetInterface(nameof(ISiteTask)) != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
tenantManager.SetAlias(tenant.TenantId, site.SiteId);
|
||||||
|
|
||||||
|
var taskObject = ActivatorUtilities.CreateInstance(provider, taskType);
|
||||||
|
var taskLog = ((ISiteTask)taskObject).ExecuteTask(provider, site, task.Parameters);
|
||||||
|
taskLog += await ((ISiteTask)taskObject).ExecuteTaskAsync(provider, site, task.Parameters);
|
||||||
|
|
||||||
|
task.Status = taskLog;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
task.Status = "Error: " + ex.Message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
task.Status = $"Error: Task {task.Name} Has An Invalid Type {task.Type}<br />";
|
||||||
|
}
|
||||||
|
|
||||||
|
// update task
|
||||||
|
task.IsCompleted = true;
|
||||||
|
siteTaskRepository.UpdateSiteTask(task);
|
||||||
|
|
||||||
|
log += task.Status + "<br />";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log += "No Tasks To Execute<br />";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
895
Oqtane.Server/Infrastructure/Jobs/SynchronizationJob.cs
Normal file
895
Oqtane.Server/Infrastructure/Jobs/SynchronizationJob.cs
Normal file
@@ -0,0 +1,895 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Oqtane.Models;
|
||||||
|
using Oqtane.Modules;
|
||||||
|
using Oqtane.Repository;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
|
namespace Oqtane.Infrastructure
|
||||||
|
{
|
||||||
|
public class SynchronizationJob : HostedServiceBase
|
||||||
|
{
|
||||||
|
// JobType = "Oqtane.Infrastructure.SynchronizationJob, Oqtane.Server"
|
||||||
|
|
||||||
|
// synchronization only supports sites in the same tenant (database)
|
||||||
|
// module title is used as a key to identify module instances on a page
|
||||||
|
// modules must implement ISynchronizable interface for content synchronization
|
||||||
|
// change detection does not support deleted items as key values will usually be different due to localization
|
||||||
|
|
||||||
|
// define settings that should not be synchronized (should be extensible in the future)
|
||||||
|
List<Setting> excludedSettings = new List<Setting>() {
|
||||||
|
new Setting { EntityName = EntityNames.Site, SettingName = "Search_LastIndexedOn" }
|
||||||
|
};
|
||||||
|
|
||||||
|
public SynchronizationJob(IServiceScopeFactory serviceScopeFactory) : base(serviceScopeFactory)
|
||||||
|
{
|
||||||
|
Name = "Synchronization Job";
|
||||||
|
Frequency = "m"; // minute
|
||||||
|
Interval = 1;
|
||||||
|
IsEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// job is executed for each tenant in installation
|
||||||
|
public override string ExecuteJob(IServiceProvider provider)
|
||||||
|
{
|
||||||
|
string log = "";
|
||||||
|
|
||||||
|
var siteGroupRepository = provider.GetRequiredService<ISiteGroupRepository>();
|
||||||
|
var siteGroupMemberRepository = provider.GetRequiredService<ISiteGroupMemberRepository>();
|
||||||
|
var siteRepository = provider.GetRequiredService<ISiteRepository>();
|
||||||
|
var aliasRepository = provider.GetRequiredService<IAliasRepository>();
|
||||||
|
var tenantManager = provider.GetRequiredService<ITenantManager>();
|
||||||
|
var settingRepository = provider.GetRequiredService<ISettingRepository>();
|
||||||
|
|
||||||
|
List<SiteGroupMember> siteGroupMembers = null;
|
||||||
|
List<Site> sites = null;
|
||||||
|
List<Alias> aliases = null;
|
||||||
|
|
||||||
|
// get site groups
|
||||||
|
var siteGroups = siteGroupRepository.GetSiteGroups();
|
||||||
|
|
||||||
|
// iterate through site groups which need to be synchronized
|
||||||
|
foreach (var siteGroup in siteGroups.Where(item => item.Synchronize && (item.Type == SiteGroupTypes.Synchronization || item.Type == SiteGroupTypes.ChangeDetection)))
|
||||||
|
{
|
||||||
|
// get data
|
||||||
|
if (siteGroupMembers == null)
|
||||||
|
{
|
||||||
|
siteGroupMembers = siteGroupMemberRepository.GetSiteGroupMembers().ToList();
|
||||||
|
sites = siteRepository.GetSites().ToList();
|
||||||
|
aliases = aliasRepository.GetAliases().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
var primaryAliasName = "https://" + aliases.First(item => item.TenantId == tenantManager.GetTenant().TenantId && item.SiteId == siteGroup.PrimarySiteId && item.IsDefault).Name;
|
||||||
|
log += (siteGroup.Type == SiteGroupTypes.Synchronization) ? "Synchronizing " : "Comparing ";
|
||||||
|
log += $"Primary Site: {sites.First(item => item.SiteId == siteGroup.PrimarySiteId).Name} - {CreateLink(primaryAliasName)}<br />";
|
||||||
|
|
||||||
|
// get primary site
|
||||||
|
var primarySite = sites.FirstOrDefault(item => item.SiteId == siteGroup.PrimarySiteId);
|
||||||
|
if (primarySite != null && !primarySite.IsDeleted)
|
||||||
|
{
|
||||||
|
// update flag to prevent job from processing group again
|
||||||
|
siteGroup.Synchronize = false;
|
||||||
|
siteGroupRepository.UpdateSiteGroup(siteGroup);
|
||||||
|
|
||||||
|
// iterate through sites in site group
|
||||||
|
foreach (var siteGroupMember in siteGroupMembers.Where(item => item.SiteGroupId == siteGroup.SiteGroupId && item.SiteId != siteGroup.PrimarySiteId))
|
||||||
|
{
|
||||||
|
// get secondary site
|
||||||
|
var secondarySite = sites.FirstOrDefault(item => item.SiteId == siteGroupMember.SiteId);
|
||||||
|
if (secondarySite != null)
|
||||||
|
{
|
||||||
|
// get default alias for site
|
||||||
|
var secondaryAliasName = "https://" + aliases.First(item => item.TenantId == tenantManager.GetTenant().TenantId && item.SiteId == siteGroupMember.SiteId && item.IsDefault).Name;
|
||||||
|
siteGroupMember.AliasName = (siteGroupMember.SiteGroup.Type == SiteGroupTypes.Synchronization) ? secondaryAliasName : primaryAliasName;
|
||||||
|
|
||||||
|
// initialize SynchronizedOn
|
||||||
|
if (siteGroupMember.SynchronizedOn == null)
|
||||||
|
{
|
||||||
|
siteGroupMember.SynchronizedOn = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// synchronize site
|
||||||
|
var siteLog = SynchronizeSite(provider, tenantManager, settingRepository, siteGroupMember, primarySite, secondarySite);
|
||||||
|
if (string.IsNullOrEmpty(siteLog))
|
||||||
|
{
|
||||||
|
siteLog = (siteGroupMember.SynchronizedOn != DateTime.MinValue) ? "No Changes Identified<br />" : "Initialization Complete<br />";
|
||||||
|
}
|
||||||
|
|
||||||
|
// set synchronized date/time
|
||||||
|
siteGroupMember.SynchronizedOn = DateTime.UtcNow;
|
||||||
|
siteGroupMemberRepository.UpdateSiteGroupMember(siteGroupMember);
|
||||||
|
|
||||||
|
log += $"With Secondary Site: {secondarySite.Name} - {CreateLink(secondaryAliasName)}<br />" + siteLog;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log += $"Site Group {siteGroup.Name} Has A SiteId {siteGroupMember.SiteId} Which Does Not Exist<br />";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log += $"Site Group {siteGroup.Name} Has A PrimarySiteId {siteGroup.PrimarySiteId} Which Does Not Exist Or Is Deleted<br />";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(log))
|
||||||
|
{
|
||||||
|
log = "No Site Groups Require Synchronization<br />";
|
||||||
|
}
|
||||||
|
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string SynchronizeSite(IServiceProvider provider, ITenantManager tenantManager, ISettingRepository settingRepository, SiteGroupMember siteGroupMember, Site primarySite, Site secondarySite)
|
||||||
|
{
|
||||||
|
var log = "";
|
||||||
|
|
||||||
|
// synchronize roles
|
||||||
|
log += SynchronizeRoles(provider, settingRepository, siteGroupMember, primarySite.SiteId, secondarySite.SiteId);
|
||||||
|
|
||||||
|
// synchronize folders/files
|
||||||
|
log += SynchronizeFolders(provider, settingRepository, siteGroupMember, primarySite.SiteId, secondarySite.SiteId);
|
||||||
|
|
||||||
|
// synchronize pages/modules
|
||||||
|
log += SynchronizePages(provider, settingRepository, tenantManager, siteGroupMember, primarySite.SiteId, secondarySite.SiteId);
|
||||||
|
|
||||||
|
// synchronize site
|
||||||
|
if (primarySite.ModifiedOn > siteGroupMember.SynchronizedOn)
|
||||||
|
{
|
||||||
|
if (siteGroupMember.SiteGroup.Type == SiteGroupTypes.Synchronization)
|
||||||
|
{
|
||||||
|
secondarySite.TimeZoneId = primarySite.TimeZoneId;
|
||||||
|
secondarySite.CultureCode = primarySite.CultureCode;
|
||||||
|
if (secondarySite.LogoFileId != primarySite.LogoFileId)
|
||||||
|
{
|
||||||
|
secondarySite.LogoFileId = ResolveFileId(provider, primarySite.LogoFileId, secondarySite.SiteId);
|
||||||
|
}
|
||||||
|
if (secondarySite.FaviconFileId != primarySite.FaviconFileId)
|
||||||
|
{
|
||||||
|
secondarySite.FaviconFileId = ResolveFileId(provider, primarySite.FaviconFileId, secondarySite.SiteId); ;
|
||||||
|
}
|
||||||
|
secondarySite.DefaultThemeType = primarySite.DefaultThemeType;
|
||||||
|
secondarySite.DefaultContainerType = primarySite.DefaultContainerType;
|
||||||
|
secondarySite.AdminContainerType = primarySite.AdminContainerType;
|
||||||
|
secondarySite.PwaIsEnabled = primarySite.PwaIsEnabled;
|
||||||
|
if (secondarySite.PwaAppIconFileId != primarySite.PwaAppIconFileId)
|
||||||
|
{
|
||||||
|
secondarySite.PwaAppIconFileId = ResolveFileId(provider, primarySite.PwaAppIconFileId, secondarySite.SiteId); ;
|
||||||
|
}
|
||||||
|
if (secondarySite.PwaSplashIconFileId != primarySite.PwaSplashIconFileId)
|
||||||
|
{
|
||||||
|
secondarySite.PwaSplashIconFileId = ResolveFileId(provider, primarySite.PwaSplashIconFileId, secondarySite.SiteId); ;
|
||||||
|
}
|
||||||
|
secondarySite.AllowRegistration = primarySite.AllowRegistration;
|
||||||
|
secondarySite.VisitorTracking = primarySite.VisitorTracking;
|
||||||
|
secondarySite.CaptureBrokenUrls = primarySite.CaptureBrokenUrls;
|
||||||
|
secondarySite.SiteGuid = primarySite.SiteGuid;
|
||||||
|
secondarySite.RenderMode = primarySite.RenderMode;
|
||||||
|
secondarySite.Runtime = primarySite.Runtime;
|
||||||
|
secondarySite.Prerender = primarySite.Prerender;
|
||||||
|
secondarySite.Hybrid = primarySite.Hybrid;
|
||||||
|
secondarySite.EnhancedNavigation = primarySite.EnhancedNavigation;
|
||||||
|
secondarySite.Version = primarySite.Version;
|
||||||
|
secondarySite.HeadContent = primarySite.HeadContent;
|
||||||
|
secondarySite.BodyContent = primarySite.BodyContent;
|
||||||
|
secondarySite.CreatedBy = primarySite.CreatedBy;
|
||||||
|
secondarySite.CreatedOn = primarySite.CreatedOn;
|
||||||
|
secondarySite.ModifiedBy = primarySite.ModifiedBy;
|
||||||
|
secondarySite.ModifiedOn = primarySite.ModifiedOn;
|
||||||
|
secondarySite.IsDeleted = primarySite.IsDeleted;
|
||||||
|
secondarySite.DeletedBy = primarySite.DeletedBy;
|
||||||
|
secondarySite.DeletedOn = primarySite.DeletedOn;
|
||||||
|
|
||||||
|
var siteRepository = provider.GetRequiredService<ISiteRepository>();
|
||||||
|
siteRepository.UpdateSite(secondarySite);
|
||||||
|
log += Log(siteGroupMember, $"Site Updated: {secondarySite.Name} - {CreateLink(siteGroupMember.AliasName)}");
|
||||||
|
}
|
||||||
|
else // change detection
|
||||||
|
{
|
||||||
|
log += Log(siteGroupMember, $"Site Updated: {primarySite.Name} - {CreateLink(siteGroupMember.AliasName)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// site settings
|
||||||
|
log += SynchronizeSettings(settingRepository, siteGroupMember, EntityNames.Site, primarySite.SiteId, secondarySite.SiteId);
|
||||||
|
|
||||||
|
if (siteGroupMember.SiteGroup.Type == SiteGroupTypes.Synchronization && (siteGroupMember.SynchronizedOn == DateTime.MinValue || !string.IsNullOrEmpty(log)))
|
||||||
|
{
|
||||||
|
// clear cache for secondary site if any content was Synchronized
|
||||||
|
var syncManager = provider.GetRequiredService<ISyncManager>();
|
||||||
|
var alias = new Alias { TenantId = tenantManager.GetTenant().TenantId, SiteId = secondarySite.SiteId };
|
||||||
|
syncManager.AddSyncEvent(alias, EntityNames.Site, secondarySite.SiteId, SyncEventActions.Refresh);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (siteGroupMember.SiteGroup.Type == SiteGroupTypes.ChangeDetection && !string.IsNullOrEmpty(log))
|
||||||
|
{
|
||||||
|
// send change log to administrators
|
||||||
|
log += SendNotifications(provider, siteGroupMember, secondarySite.SiteId, secondarySite.Name, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int? ResolveFileId(IServiceProvider provider, int? fileId, int siteId)
|
||||||
|
{
|
||||||
|
if (fileId != null)
|
||||||
|
{
|
||||||
|
var fileRepository = provider.GetRequiredService<IFileRepository>();
|
||||||
|
var file = fileRepository.GetFile(fileId.Value);
|
||||||
|
fileId = fileRepository.GetFile(siteId, file.Folder.Path, file.Name).FileId;
|
||||||
|
}
|
||||||
|
return fileId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string SynchronizeRoles(IServiceProvider provider, ISettingRepository settingRepository, SiteGroupMember siteGroupMember, int primarySiteId, int secondarySiteId)
|
||||||
|
{
|
||||||
|
// get roles
|
||||||
|
var roleRepository = provider.GetRequiredService<IRoleRepository>();
|
||||||
|
var primaryRoles = roleRepository.GetRoles(primarySiteId);
|
||||||
|
var secondaryRoles = roleRepository.GetRoles(secondarySiteId).ToList();
|
||||||
|
var log = "";
|
||||||
|
|
||||||
|
foreach (var primaryRole in primaryRoles)
|
||||||
|
{
|
||||||
|
if (siteGroupMember.SiteGroup.Type == SiteGroupTypes.Synchronization)
|
||||||
|
{
|
||||||
|
var role = secondaryRoles.FirstOrDefault(item => item.Name == primaryRole.Name);
|
||||||
|
|
||||||
|
var secondaryRole = role;
|
||||||
|
if (secondaryRole == null)
|
||||||
|
{
|
||||||
|
secondaryRole = new Role();
|
||||||
|
secondaryRole.SiteId = secondarySiteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (role == null || primaryRole.ModifiedOn > siteGroupMember.SynchronizedOn)
|
||||||
|
{
|
||||||
|
// set all properties
|
||||||
|
secondaryRole.Name = primaryRole.Name;
|
||||||
|
secondaryRole.Description = primaryRole.Description;
|
||||||
|
secondaryRole.IsAutoAssigned = primaryRole.IsAutoAssigned;
|
||||||
|
secondaryRole.IsSystem = primaryRole.IsSystem;
|
||||||
|
|
||||||
|
if (role == null)
|
||||||
|
{
|
||||||
|
roleRepository.AddRole(secondaryRole);
|
||||||
|
log += Log(siteGroupMember, $"Role Added: {secondaryRole.Name}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
roleRepository.UpdateRole(secondaryRole);
|
||||||
|
log += Log(siteGroupMember, $"Role Updated: {secondaryRole.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (role != null)
|
||||||
|
{
|
||||||
|
secondaryRoles.Remove(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // change detection
|
||||||
|
{
|
||||||
|
if (primaryRole.ModifiedOn > siteGroupMember.SynchronizedOn)
|
||||||
|
{
|
||||||
|
log += Log(siteGroupMember, $"Role Updated: {primaryRole.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (siteGroupMember.SiteGroup.Type == SiteGroupTypes.Synchronization)
|
||||||
|
{
|
||||||
|
// remove roles in the secondary site which do not exist in the primary site
|
||||||
|
foreach (var secondaryRole in secondaryRoles)
|
||||||
|
{
|
||||||
|
roleRepository.DeleteRole(secondaryRole.RoleId);
|
||||||
|
log += Log(siteGroupMember, $"Role Deleted: {secondaryRole.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// settings
|
||||||
|
log += SynchronizeSettings(settingRepository, siteGroupMember, EntityNames.Role, primarySiteId, secondarySiteId);
|
||||||
|
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string SynchronizeFolders(IServiceProvider provider, ISettingRepository settingRepository, SiteGroupMember siteGroupMember, int primarySiteId, int secondarySiteId)
|
||||||
|
{
|
||||||
|
var folderRepository = provider.GetRequiredService<IFolderRepository>();
|
||||||
|
var fileRepository = provider.GetRequiredService<IFileRepository>();
|
||||||
|
var log = "";
|
||||||
|
|
||||||
|
// get folders (ignore personalized)
|
||||||
|
var primaryFolders = folderRepository.GetFolders(primarySiteId).Where(item => !item.Path.StartsWith("Users/"));
|
||||||
|
var secondaryFolders = folderRepository.GetFolders(secondarySiteId).Where(item => !item.Path.StartsWith("Users/")).ToList();
|
||||||
|
|
||||||
|
// iterate through folders
|
||||||
|
foreach (var primaryFolder in primaryFolders)
|
||||||
|
{
|
||||||
|
if (siteGroupMember.SiteGroup.Type == SiteGroupTypes.Synchronization)
|
||||||
|
{
|
||||||
|
var folder = secondaryFolders.FirstOrDefault(item => item.Path == primaryFolder.Path);
|
||||||
|
|
||||||
|
var secondaryFolder = folder;
|
||||||
|
if (secondaryFolder == null)
|
||||||
|
{
|
||||||
|
secondaryFolder = new Folder();
|
||||||
|
secondaryFolder.SiteId = secondarySiteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (folder == null || primaryFolder.ModifiedOn > siteGroupMember.SynchronizedOn)
|
||||||
|
{
|
||||||
|
// set all properties
|
||||||
|
secondaryFolder.ParentId = null;
|
||||||
|
if (primaryFolder.ParentId != null)
|
||||||
|
{
|
||||||
|
var parentFolder = folderRepository.GetFolder(secondarySiteId, primaryFolders.First(item => item.FolderId == primaryFolder.ParentId).Path);
|
||||||
|
if (parentFolder != null)
|
||||||
|
{
|
||||||
|
secondaryFolder.ParentId = parentFolder.FolderId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
secondaryFolder.Type = primaryFolder.Type;
|
||||||
|
secondaryFolder.Name = primaryFolder.Name;
|
||||||
|
secondaryFolder.Order = primaryFolder.Order;
|
||||||
|
secondaryFolder.ImageSizes = primaryFolder.ImageSizes;
|
||||||
|
secondaryFolder.Capacity = primaryFolder.Capacity;
|
||||||
|
secondaryFolder.ImageSizes = primaryFolder.ImageSizes;
|
||||||
|
secondaryFolder.IsSystem = primaryFolder.IsSystem;
|
||||||
|
secondaryFolder.PermissionList = SynchronizePermissions(primaryFolder.PermissionList, secondarySiteId);
|
||||||
|
|
||||||
|
if (folder == null)
|
||||||
|
{
|
||||||
|
folderRepository.AddFolder(secondaryFolder);
|
||||||
|
log += Log(siteGroupMember, $"Folder Added: {secondaryFolder.Path}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
folderRepository.UpdateFolder(secondaryFolder);
|
||||||
|
log += Log(siteGroupMember, $"Folder Updated: {secondaryFolder.Path}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (folder != null)
|
||||||
|
{
|
||||||
|
secondaryFolders.Remove(folder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// folder settings
|
||||||
|
log += SynchronizeSettings(settingRepository, siteGroupMember, EntityNames.Folder, primaryFolder.FolderId, secondaryFolder.FolderId);
|
||||||
|
|
||||||
|
// files
|
||||||
|
log += SynchronizeFiles(provider, folderRepository, fileRepository, siteGroupMember, primaryFolder, secondaryFolder);
|
||||||
|
}
|
||||||
|
else // change detection
|
||||||
|
{
|
||||||
|
if (primaryFolder.ModifiedOn > siteGroupMember.SynchronizedOn)
|
||||||
|
{
|
||||||
|
log += Log(siteGroupMember, $"Folder Updated: {primaryFolder.Path}");
|
||||||
|
|
||||||
|
// folder settings
|
||||||
|
log += SynchronizeSettings(settingRepository, siteGroupMember, EntityNames.Folder, primaryFolder.FolderId, -1);
|
||||||
|
|
||||||
|
// files
|
||||||
|
log += SynchronizeFiles(provider, folderRepository, fileRepository, siteGroupMember, primaryFolder, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (siteGroupMember.SiteGroup.Type == SiteGroupTypes.Synchronization)
|
||||||
|
{
|
||||||
|
// remove folders in the secondary site which do not exist in the primary site
|
||||||
|
foreach (var secondaryFolder in secondaryFolders)
|
||||||
|
{
|
||||||
|
folderRepository.DeleteFolder(secondaryFolder.FolderId);
|
||||||
|
log += Log(siteGroupMember, $"Folder Deleted: {secondaryFolder.Path}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string SynchronizeFiles(IServiceProvider provider, IFolderRepository folderRepository, IFileRepository fileRepository, SiteGroupMember siteGroupMember, Folder primaryFolder, Folder secondaryFolder)
|
||||||
|
{
|
||||||
|
var log = "";
|
||||||
|
|
||||||
|
// get files for folder
|
||||||
|
var primaryFiles = fileRepository.GetFiles(primaryFolder.FolderId);
|
||||||
|
var secondaryFiles = new List<Models.File>();
|
||||||
|
if (secondaryFolder != null)
|
||||||
|
{
|
||||||
|
secondaryFiles = fileRepository.GetFiles(secondaryFolder.FolderId).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var primaryFile in primaryFiles)
|
||||||
|
{
|
||||||
|
if (siteGroupMember.SiteGroup.Type == SiteGroupTypes.Synchronization)
|
||||||
|
{
|
||||||
|
var file = secondaryFiles.FirstOrDefault(item => item.Name == primaryFile.Name);
|
||||||
|
|
||||||
|
var secondaryFile = file;
|
||||||
|
if (secondaryFile == null)
|
||||||
|
{
|
||||||
|
secondaryFile = new Models.File();
|
||||||
|
secondaryFile.FolderId = secondaryFolder.FolderId;
|
||||||
|
secondaryFile.Name = primaryFile.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file == null || primaryFile.ModifiedOn > siteGroupMember.SynchronizedOn)
|
||||||
|
{
|
||||||
|
// set all properties
|
||||||
|
secondaryFile.Extension = primaryFile.Extension;
|
||||||
|
secondaryFile.Size = primaryFile.Size;
|
||||||
|
secondaryFile.ImageHeight = primaryFile.ImageHeight;
|
||||||
|
secondaryFile.ImageWidth = primaryFile.ImageWidth;
|
||||||
|
secondaryFile.Description = primaryFile.Description;
|
||||||
|
|
||||||
|
if (file == null)
|
||||||
|
{
|
||||||
|
fileRepository.AddFile(secondaryFile);
|
||||||
|
SynchronizeFile(folderRepository, primaryFolder, primaryFile, secondaryFolder, secondaryFile);
|
||||||
|
log += Log(siteGroupMember, $"File Added: {CreateLink(siteGroupMember.AliasName + "/" + secondaryFolder.Path + secondaryFile.Name)}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fileRepository.UpdateFile(secondaryFile);
|
||||||
|
SynchronizeFile(folderRepository, primaryFolder, primaryFile, secondaryFolder, secondaryFile);
|
||||||
|
log += Log(siteGroupMember, $"File Updated: {CreateLink(siteGroupMember.AliasName + "/" + secondaryFolder.Path + secondaryFile.Name)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file != null)
|
||||||
|
{
|
||||||
|
secondaryFiles.Remove(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // change detection
|
||||||
|
{
|
||||||
|
if (primaryFile.ModifiedOn > siteGroupMember.SynchronizedOn)
|
||||||
|
{
|
||||||
|
log += Log(siteGroupMember, $"File Updated: {CreateLink(siteGroupMember.AliasName + "/" + primaryFolder.Path + primaryFile.Name)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (siteGroupMember.SiteGroup.Type == SiteGroupTypes.Synchronization)
|
||||||
|
{
|
||||||
|
// remove files in the secondary site which do not exist in the primary site
|
||||||
|
foreach (var secondaryFile in secondaryFiles)
|
||||||
|
{
|
||||||
|
fileRepository.DeleteFile(secondaryFile.FileId);
|
||||||
|
var secondaryPath = Path.Combine(folderRepository.GetFolderPath(secondaryFolder), secondaryFile.Name);
|
||||||
|
System.IO.File.Delete(secondaryPath);
|
||||||
|
log += Log(siteGroupMember, $"File Deleted: {CreateLink(siteGroupMember.AliasName + "/" + secondaryFolder.Path + secondaryFile.Name)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SynchronizeFile(IFolderRepository folderRepository, Folder primaryFolder, Models.File primaryFile, Folder secondaryFolder, Models.File secondaryFile)
|
||||||
|
{
|
||||||
|
var primaryPath = Path.Combine(folderRepository.GetFolderPath(primaryFolder), primaryFile.Name);
|
||||||
|
if (System.IO.File.Exists(primaryPath))
|
||||||
|
{
|
||||||
|
var secondaryPath = Path.Combine(folderRepository.GetFolderPath(secondaryFolder), secondaryFile.Name);
|
||||||
|
if (!Directory.Exists(Path.GetDirectoryName(secondaryPath)))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(Path.GetDirectoryName(secondaryPath));
|
||||||
|
}
|
||||||
|
System.IO.File.Copy(primaryPath, secondaryPath, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string SynchronizePages(IServiceProvider provider, ISettingRepository settingRepository, ITenantManager tenantManager, SiteGroupMember siteGroupMember, int primarySiteId, int secondarySiteId)
|
||||||
|
{
|
||||||
|
var pageRepository = provider.GetRequiredService<IPageRepository>();
|
||||||
|
var pageModuleRepository = provider.GetRequiredService<IPageModuleRepository>();
|
||||||
|
var moduleRepository = provider.GetRequiredService<IModuleRepository>();
|
||||||
|
var log = "";
|
||||||
|
|
||||||
|
int tenantId = tenantManager.GetTenant().TenantId;
|
||||||
|
tenantManager.SetAlias(tenantId, primarySiteId); // required by ModuleDefinitionRepository.LoadModuleDefinitions()
|
||||||
|
var primaryPageModules = pageModuleRepository.GetPageModules(primarySiteId).ToList();
|
||||||
|
tenantManager.SetAlias(tenantId, secondarySiteId); // required by ModuleDefinitionRepository.LoadModuleDefinitions()
|
||||||
|
var secondaryPageModules = pageModuleRepository.GetPageModules(secondarySiteId).ToList();
|
||||||
|
|
||||||
|
// get pages (ignore personalized)
|
||||||
|
var primaryPages = pageRepository.GetPages(primarySiteId).Where(item => item.UserId == null);
|
||||||
|
var secondaryPages = pageRepository.GetPages(secondarySiteId).Where(item => item.UserId == null).ToList();
|
||||||
|
|
||||||
|
// iterate through primary pages
|
||||||
|
foreach (var primaryPage in primaryPages)
|
||||||
|
{
|
||||||
|
if (siteGroupMember.SiteGroup.Type == SiteGroupTypes.Synchronization)
|
||||||
|
{
|
||||||
|
var page = secondaryPages.FirstOrDefault(item => item.Path == primaryPage.Path);
|
||||||
|
|
||||||
|
var secondaryPage = page;
|
||||||
|
if (secondaryPage == null)
|
||||||
|
{
|
||||||
|
secondaryPage = new Page();
|
||||||
|
secondaryPage.SiteId = secondarySiteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (page == null || primaryPage.ModifiedOn > siteGroupMember.SynchronizedOn)
|
||||||
|
{
|
||||||
|
// set all properties
|
||||||
|
secondaryPage.Path = primaryPage.Path;
|
||||||
|
secondaryPage.Name = primaryPage.Name;
|
||||||
|
secondaryPage.ParentId = null;
|
||||||
|
if (primaryPage.ParentId != null)
|
||||||
|
{
|
||||||
|
var parentPage = pageRepository.GetPage(primaryPages.First(item => item.PageId == primaryPage.ParentId).Path, secondarySiteId);
|
||||||
|
if (parentPage != null)
|
||||||
|
{
|
||||||
|
secondaryPage.ParentId = parentPage.PageId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
secondaryPage.Title = primaryPage.Title;
|
||||||
|
secondaryPage.Order = primaryPage.Order;
|
||||||
|
secondaryPage.Url = primaryPage.Url;
|
||||||
|
secondaryPage.ThemeType = primaryPage.ThemeType;
|
||||||
|
secondaryPage.DefaultContainerType = primaryPage.DefaultContainerType;
|
||||||
|
secondaryPage.HeadContent = primaryPage.HeadContent;
|
||||||
|
secondaryPage.BodyContent = primaryPage.BodyContent;
|
||||||
|
secondaryPage.Icon = primaryPage.Icon;
|
||||||
|
secondaryPage.IsNavigation = primaryPage.IsNavigation;
|
||||||
|
secondaryPage.IsClickable = primaryPage.IsClickable;
|
||||||
|
secondaryPage.UserId = null;
|
||||||
|
secondaryPage.IsPersonalizable = primaryPage.IsPersonalizable;
|
||||||
|
secondaryPage.EffectiveDate = primaryPage.EffectiveDate;
|
||||||
|
secondaryPage.ExpiryDate = primaryPage.ExpiryDate;
|
||||||
|
secondaryPage.CreatedBy = primaryPage.CreatedBy;
|
||||||
|
secondaryPage.CreatedOn = primaryPage.CreatedOn;
|
||||||
|
secondaryPage.ModifiedBy = primaryPage.ModifiedBy;
|
||||||
|
secondaryPage.ModifiedOn = primaryPage.ModifiedOn;
|
||||||
|
secondaryPage.DeletedBy = primaryPage.DeletedBy;
|
||||||
|
secondaryPage.DeletedOn = primaryPage.DeletedOn;
|
||||||
|
secondaryPage.IsDeleted = primaryPage.IsDeleted;
|
||||||
|
secondaryPage.PermissionList = SynchronizePermissions(primaryPage.PermissionList, secondarySiteId);
|
||||||
|
|
||||||
|
if (page == null)
|
||||||
|
{
|
||||||
|
secondaryPage = pageRepository.AddPage(secondaryPage);
|
||||||
|
log += Log(siteGroupMember, $"Page Added: {CreateLink(siteGroupMember.AliasName + "/" + secondaryPage.Path)}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
secondaryPage = pageRepository.UpdatePage(secondaryPage);
|
||||||
|
log += Log(siteGroupMember, $"Page Updated: {CreateLink(siteGroupMember.AliasName + "/" + secondaryPage.Path)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (page != null)
|
||||||
|
{
|
||||||
|
secondaryPages.Remove(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
// page settings
|
||||||
|
log += SynchronizeSettings(settingRepository, siteGroupMember, EntityNames.Page, primaryPage.PageId, secondaryPage.PageId);
|
||||||
|
|
||||||
|
// modules
|
||||||
|
log += SynchronizeModules(provider, settingRepository, pageModuleRepository, moduleRepository, siteGroupMember, primaryPageModules, secondaryPageModules, primaryPage, secondaryPage, secondarySiteId);
|
||||||
|
}
|
||||||
|
else // change detection
|
||||||
|
{
|
||||||
|
if (primaryPage.ModifiedOn > siteGroupMember.SynchronizedOn)
|
||||||
|
{
|
||||||
|
log += Log(siteGroupMember, $"Page Updated: {CreateLink(siteGroupMember.AliasName + "/" + primaryPage.Path)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// page settings
|
||||||
|
log += SynchronizeSettings(settingRepository, siteGroupMember, EntityNames.Page, primaryPage.PageId, -1);
|
||||||
|
|
||||||
|
// modules
|
||||||
|
log += SynchronizeModules(provider, settingRepository, pageModuleRepository, moduleRepository, siteGroupMember, primaryPageModules, secondaryPageModules, primaryPage, null, secondarySiteId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (siteGroupMember.SiteGroup.Type == SiteGroupTypes.Synchronization)
|
||||||
|
{
|
||||||
|
// remove pages in the secondary site which do not exist in the primary site
|
||||||
|
foreach (var secondaryPage in secondaryPages)
|
||||||
|
{
|
||||||
|
pageRepository.DeletePage(secondaryPage.PageId);
|
||||||
|
log += Log(siteGroupMember, $"Page Deleted: {CreateLink(siteGroupMember.AliasName + "/" + secondaryPage.Path)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (siteGroupMember.SiteGroup.Type == SiteGroupTypes.Synchronization && (siteGroupMember.SynchronizedOn == DateTime.MinValue || !string.IsNullOrEmpty(log)))
|
||||||
|
{
|
||||||
|
// clear cache for secondary site if any content was Synchronized
|
||||||
|
var syncManager = provider.GetRequiredService<ISyncManager>();
|
||||||
|
var alias = new Alias { TenantId = tenantManager.GetTenant().TenantId, SiteId = secondarySiteId };
|
||||||
|
syncManager.AddSyncEvent(alias, EntityNames.Site, secondarySiteId, SyncEventActions.Refresh);
|
||||||
|
}
|
||||||
|
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string SynchronizeModules(IServiceProvider provider, ISettingRepository settingRepository, IPageModuleRepository pageModuleRepository, IModuleRepository moduleRepository, SiteGroupMember siteGroupMember, List<PageModule> primaryPageModules, List<PageModule> secondaryPageModules, Page primaryPage, Page secondaryPage, int secondarySiteId)
|
||||||
|
{
|
||||||
|
var log = "";
|
||||||
|
var removePageModules = secondaryPageModules.Where(item => item.PageId == secondaryPage.PageId).ToList();
|
||||||
|
|
||||||
|
// iterate through primary modules on primary page
|
||||||
|
foreach (var primaryPageModule in primaryPageModules.Where(item => item.PageId == primaryPage.PageId))
|
||||||
|
{
|
||||||
|
if (siteGroupMember.SiteGroup.Type == SiteGroupTypes.Synchronization)
|
||||||
|
{
|
||||||
|
var pageModule = secondaryPageModules.FirstOrDefault(item => item.PageId == secondaryPage.PageId && item.Module.ModuleDefinitionName == primaryPageModule.Module.ModuleDefinitionName && item.Title.ToLower() == primaryPageModule.Title.ToLower());
|
||||||
|
|
||||||
|
var secondaryPageModule = pageModule;
|
||||||
|
if (secondaryPageModule == null)
|
||||||
|
{
|
||||||
|
secondaryPageModule = new PageModule();
|
||||||
|
secondaryPageModule.PageId = secondaryPage.PageId;
|
||||||
|
secondaryPageModule.Module = new Module();
|
||||||
|
secondaryPageModule.Module.SiteId = secondarySiteId;
|
||||||
|
secondaryPageModule.Module.ModuleDefinitionName = primaryPageModule.Module.ModuleDefinitionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pageModule == null || primaryPageModule.ModifiedOn > siteGroupMember.SynchronizedOn || primaryPageModule.Module.ModifiedOn > siteGroupMember.SynchronizedOn)
|
||||||
|
{
|
||||||
|
// set all properties
|
||||||
|
secondaryPageModule.Title = primaryPageModule.Title;
|
||||||
|
secondaryPageModule.Pane = primaryPageModule.Pane;
|
||||||
|
secondaryPageModule.Order = primaryPageModule.Order;
|
||||||
|
secondaryPageModule.ContainerType = primaryPageModule.ContainerType;
|
||||||
|
secondaryPageModule.Header = primaryPageModule.Header;
|
||||||
|
secondaryPageModule.Footer = primaryPageModule.Footer;
|
||||||
|
secondaryPageModule.IsDeleted = primaryPageModule.IsDeleted;
|
||||||
|
secondaryPageModule.Module.PermissionList = SynchronizePermissions(primaryPageModule.Module.PermissionList, secondarySiteId);
|
||||||
|
secondaryPageModule.Module.AllPages = false;
|
||||||
|
secondaryPageModule.Module.IsDeleted = false;
|
||||||
|
|
||||||
|
if (pageModule == null)
|
||||||
|
{
|
||||||
|
// check if module exists in site (ie. a shared instance)
|
||||||
|
var module = secondaryPageModules.FirstOrDefault(item => item.Module.ModuleDefinitionName == primaryPageModule.Module.ModuleDefinitionName && item.Title.ToLower() == primaryPageModule.Title.ToLower())?.Module;
|
||||||
|
if (module == null)
|
||||||
|
{
|
||||||
|
module = moduleRepository.AddModule(secondaryPageModule.Module);
|
||||||
|
log += Log(siteGroupMember, $"Module Added: {secondaryPageModule.Title} - {CreateLink(siteGroupMember.AliasName + "/" + secondaryPage.Path)}");
|
||||||
|
}
|
||||||
|
if (module != null)
|
||||||
|
{
|
||||||
|
secondaryPageModule.ModuleId = module.ModuleId;
|
||||||
|
secondaryPageModule.Module = null; // remove tracking
|
||||||
|
secondaryPageModule = pageModuleRepository.AddPageModule(secondaryPageModule);
|
||||||
|
log += Log(siteGroupMember, $"Module Instance Added: {secondaryPageModule.Title} - {CreateLink(siteGroupMember.AliasName + "/" + secondaryPage.Path)}");
|
||||||
|
secondaryPageModule.Module = module;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// update existing module
|
||||||
|
if (primaryPageModule.Module.ModifiedOn > siteGroupMember.SynchronizedOn)
|
||||||
|
{
|
||||||
|
moduleRepository.UpdateModule(secondaryPageModule.Module);
|
||||||
|
log += Log(siteGroupMember, $"Module Updated: {secondaryPageModule.Title} - {CreateLink(siteGroupMember.AliasName + "/" + secondaryPage.Path)}");
|
||||||
|
}
|
||||||
|
if (primaryPageModule.ModifiedOn > siteGroupMember.SynchronizedOn)
|
||||||
|
{
|
||||||
|
secondaryPageModule = pageModuleRepository.UpdatePageModule(secondaryPageModule);
|
||||||
|
log += Log(siteGroupMember, $"Module Instance Updated: {secondaryPageModule.Title} - {CreateLink(siteGroupMember.AliasName + "/" + secondaryPage.Path)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pageModule != null)
|
||||||
|
{
|
||||||
|
removePageModules.Remove(pageModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
// module settings
|
||||||
|
log += SynchronizeSettings(settingRepository, siteGroupMember, EntityNames.Module, primaryPageModule.ModuleId, secondaryPageModule.ModuleId);
|
||||||
|
|
||||||
|
// module content
|
||||||
|
log += SynchronizeModuleContent(provider, siteGroupMember, primaryPageModule, secondaryPageModule, primaryPage, secondaryPage);
|
||||||
|
}
|
||||||
|
else // change detection
|
||||||
|
{
|
||||||
|
if (primaryPageModule.Module.ModifiedOn > siteGroupMember.SynchronizedOn)
|
||||||
|
{
|
||||||
|
log += Log(siteGroupMember, $"Module Updated: {primaryPageModule.Title} - {CreateLink(siteGroupMember.AliasName + "/" + primaryPage.Path)}");
|
||||||
|
}
|
||||||
|
if (primaryPageModule.ModifiedOn > siteGroupMember.SynchronizedOn)
|
||||||
|
{
|
||||||
|
log += Log(siteGroupMember, $"Module Instance Updated: {primaryPageModule.Title} - {CreateLink(siteGroupMember.AliasName + "/" + primaryPage.Path)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// module settings
|
||||||
|
log += SynchronizeSettings(settingRepository, siteGroupMember, EntityNames.Module, primaryPageModule.ModuleId, -1);
|
||||||
|
|
||||||
|
// module content
|
||||||
|
log += SynchronizeModuleContent(provider, siteGroupMember, primaryPageModule, null, primaryPage, secondaryPage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (siteGroupMember.SiteGroup.Type == SiteGroupTypes.Synchronization)
|
||||||
|
{
|
||||||
|
// remove modules on the secondary page which do not exist on the primary page
|
||||||
|
foreach (var secondaryPageModule in removePageModules)
|
||||||
|
{
|
||||||
|
pageModuleRepository.DeletePageModule(secondaryPageModule.PageModuleId);
|
||||||
|
log += Log(siteGroupMember, $"Module Instance Deleted: {secondaryPageModule.Title} - {CreateLink(siteGroupMember.AliasName + "/" + secondaryPageModule.Page.Path)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string SynchronizeModuleContent(IServiceProvider provider, SiteGroupMember siteGroupMember, PageModule primaryPageModule, PageModule secondaryPageModule, Page primaryPage, Page secondaryPage)
|
||||||
|
{
|
||||||
|
var log = "";
|
||||||
|
|
||||||
|
if (primaryPageModule.Module.ModuleDefinition.ServerManagerType != "")
|
||||||
|
{
|
||||||
|
Type moduleType = Type.GetType(primaryPageModule.Module.ModuleDefinition.ServerManagerType);
|
||||||
|
if (moduleType != null && moduleType.GetInterface(nameof(ISynchronizable)) != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var moduleObject = ActivatorUtilities.CreateInstance(provider, moduleType);
|
||||||
|
var moduleContent = ((ISynchronizable)moduleObject).ExtractModule(primaryPageModule.Module, siteGroupMember.SynchronizedOn.Value);
|
||||||
|
if (!string.IsNullOrEmpty(moduleContent))
|
||||||
|
{
|
||||||
|
if (siteGroupMember.SiteGroup.Type == SiteGroupTypes.Synchronization)
|
||||||
|
{
|
||||||
|
((ISynchronizable)moduleObject).LoadModule(secondaryPageModule.Module, moduleContent);
|
||||||
|
log += Log(siteGroupMember, $"Module Content Updated: {secondaryPageModule.Title} - {CreateLink(siteGroupMember.AliasName + "/" + secondaryPage.Path)}");
|
||||||
|
}
|
||||||
|
else // change detection
|
||||||
|
{
|
||||||
|
log += Log(siteGroupMember, $"Module Content Updated: {primaryPageModule.Title} - {CreateLink(siteGroupMember.AliasName + "/" + primaryPage.Path)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// error exporting/importing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Permission> SynchronizePermissions(List<Permission> permissionList, int siteId)
|
||||||
|
{
|
||||||
|
return permissionList.Select(item => new Permission
|
||||||
|
{
|
||||||
|
SiteId = siteId,
|
||||||
|
PermissionName = item.PermissionName,
|
||||||
|
RoleName = item.RoleName,
|
||||||
|
UserId = item.UserId,
|
||||||
|
IsAuthorized = item.IsAuthorized,
|
||||||
|
CreatedBy = item.CreatedBy,
|
||||||
|
CreatedOn = item.CreatedOn,
|
||||||
|
ModifiedBy = item.ModifiedBy,
|
||||||
|
ModifiedOn = item.ModifiedOn
|
||||||
|
}).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string SynchronizeSettings(ISettingRepository settingRepository, SiteGroupMember siteGroupMember, string entityName, int primaryEntityId, int secondaryEntityId)
|
||||||
|
{
|
||||||
|
var log = "";
|
||||||
|
var updated = false;
|
||||||
|
|
||||||
|
var secondarySettings = settingRepository.GetSettings(entityName, secondaryEntityId).ToList();
|
||||||
|
foreach (var primarySetting in settingRepository.GetSettings(entityName, primaryEntityId))
|
||||||
|
{
|
||||||
|
if (siteGroupMember.SiteGroup.Type == SiteGroupTypes.Synchronization)
|
||||||
|
{
|
||||||
|
var secondarySetting = secondarySettings.FirstOrDefault(item => item.SettingName == primarySetting.SettingName);
|
||||||
|
if (secondarySetting == null)
|
||||||
|
{
|
||||||
|
secondarySetting = new Setting();
|
||||||
|
secondarySetting.EntityName = primarySetting.EntityName;
|
||||||
|
secondarySetting.EntityId = secondaryEntityId;
|
||||||
|
secondarySetting.SettingName = primarySetting.SettingName;
|
||||||
|
secondarySetting.SettingValue = primarySetting.SettingValue;
|
||||||
|
secondarySetting.IsPrivate = primarySetting.IsPrivate;
|
||||||
|
if (!excludedSettings.Any(item => item.EntityName == secondarySetting.EntityName && item.SettingName == secondarySetting.SettingName))
|
||||||
|
{
|
||||||
|
settingRepository.AddSetting(secondarySetting);
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (secondarySetting.SettingValue != primarySetting.SettingValue || secondarySetting.IsPrivate != primarySetting.IsPrivate)
|
||||||
|
{
|
||||||
|
secondarySetting.SettingValue = primarySetting.SettingValue;
|
||||||
|
secondarySetting.IsPrivate = primarySetting.IsPrivate;
|
||||||
|
if (!excludedSettings.Any(item => item.EntityName == secondarySetting.EntityName && item.SettingName == secondarySetting.SettingName))
|
||||||
|
{
|
||||||
|
settingRepository.UpdateSetting(secondarySetting);
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
secondarySettings.Remove(secondarySetting);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // change detection
|
||||||
|
{
|
||||||
|
if (primarySetting.ModifiedOn > siteGroupMember.SynchronizedOn && !excludedSettings.Any(item => item.EntityName == primarySetting.EntityName && item.SettingName == primarySetting.SettingName))
|
||||||
|
{
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (siteGroupMember.SiteGroup.Type == SiteGroupTypes.Synchronization)
|
||||||
|
{
|
||||||
|
// any remaining secondary settings need to be deleted
|
||||||
|
foreach (var secondarySetting in secondarySettings)
|
||||||
|
{
|
||||||
|
if (!excludedSettings.Any(item => item.EntityName == secondarySetting.EntityName && item.SettingName == secondarySetting.SettingName))
|
||||||
|
{
|
||||||
|
settingRepository.DeleteSetting(secondarySetting.EntityName, secondarySetting.SettingId);
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updated)
|
||||||
|
{
|
||||||
|
log += Log(siteGroupMember, $"{entityName} Settings Updated");
|
||||||
|
}
|
||||||
|
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string SendNotifications(IServiceProvider provider, SiteGroupMember siteGroupMember, int siteId, string siteName, string changeLog)
|
||||||
|
{
|
||||||
|
var userRoleRepository = provider.GetRequiredService<IUserRoleRepository>();
|
||||||
|
var notificationRepository = provider.GetRequiredService<INotificationRepository>();
|
||||||
|
var log = "";
|
||||||
|
|
||||||
|
// get administrators for site
|
||||||
|
var userRoles = userRoleRepository.GetUserRoles(RoleNames.Admin, siteId);
|
||||||
|
if (userRoles != null && userRoles.Any())
|
||||||
|
{
|
||||||
|
foreach (var userRole in userRoles)
|
||||||
|
{
|
||||||
|
var notification = new Notification(siteId, userRole.User, $"{siteName} Change Log", changeLog);
|
||||||
|
notificationRepository.AddNotification(notification);
|
||||||
|
}
|
||||||
|
log += Log(siteGroupMember, $"Change Log Sent To Administrators For Secondary Site: {siteName}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log += Log(siteGroupMember, $"Error Sending Change Log - Secondary Site {siteName} Does Not Have Any Administrators Defined");
|
||||||
|
}
|
||||||
|
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string Log(SiteGroupMember siteGroupMember, string content)
|
||||||
|
{
|
||||||
|
// not necessary to log initial synchronization
|
||||||
|
if (siteGroupMember.SynchronizedOn != DateTime.MinValue)
|
||||||
|
{
|
||||||
|
return content + "<br />";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string CreateLink(string url)
|
||||||
|
{
|
||||||
|
return "<a href=\"" + url + "\" target=\"_new\">" + url + "</a>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,6 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Oqtane.Models;
|
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
|
|
||||||
namespace Oqtane.Infrastructure
|
namespace Oqtane.Infrastructure
|
||||||
@@ -14,6 +13,7 @@ namespace Oqtane.Infrastructure
|
|||||||
string GetDefaultCulture();
|
string GetDefaultCulture();
|
||||||
string[] GetSupportedCultures();
|
string[] GetSupportedCultures();
|
||||||
string[] GetInstalledCultures();
|
string[] GetInstalledCultures();
|
||||||
|
string[] GetNeutralCultures();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class LocalizationManager : ILocalizationManager
|
public class LocalizationManager : ILocalizationManager
|
||||||
@@ -41,7 +41,8 @@ namespace Oqtane.Infrastructure
|
|||||||
|
|
||||||
public string[] GetSupportedCultures()
|
public string[] GetSupportedCultures()
|
||||||
{
|
{
|
||||||
return CultureInfo.GetCultures(CultureTypes.AllCultures).Select(item => item.Name).OrderBy(c => c).ToArray();
|
return CultureInfo.GetCultures(CultureTypes.AllCultures)
|
||||||
|
.Select(item => item.Name).OrderBy(c => c).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string[] GetInstalledCultures()
|
public string[] GetInstalledCultures()
|
||||||
@@ -49,7 +50,14 @@ namespace Oqtane.Infrastructure
|
|||||||
return GetSatelliteAssemblyCultures();
|
return GetSatelliteAssemblyCultures();
|
||||||
}
|
}
|
||||||
|
|
||||||
// method is static as it is called during startup
|
public string[] GetNeutralCultures()
|
||||||
|
{
|
||||||
|
return CultureInfo.GetCultures(CultureTypes.AllCultures)
|
||||||
|
.Where(item => item.IsNeutralCulture)
|
||||||
|
.Select(item => item.Name).OrderBy(c => c).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
// note: method is public and static as it is called during startup
|
||||||
public static string[] GetSatelliteAssemblyCultures()
|
public static string[] GetSatelliteAssemblyCultures()
|
||||||
{
|
{
|
||||||
var cultures = new List<string>();
|
var cultures = new List<string>();
|
||||||
|
|||||||
164
Oqtane.Server/Infrastructure/SiteTasks/GlobalReplaceTask.cs
Normal file
164
Oqtane.Server/Infrastructure/SiteTasks/GlobalReplaceTask.cs
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text.Json;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Oqtane.Models;
|
||||||
|
using Oqtane.Modules;
|
||||||
|
using Oqtane.Repository;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
|
namespace Oqtane.Infrastructure
|
||||||
|
{
|
||||||
|
public class GlobalReplaceTask : SiteTaskBase
|
||||||
|
{
|
||||||
|
public override string ExecuteTask(IServiceProvider provider, Site site, string parameters)
|
||||||
|
{
|
||||||
|
string log = "";
|
||||||
|
|
||||||
|
// get services
|
||||||
|
var siteRepository = provider.GetRequiredService<ISiteRepository>();
|
||||||
|
var pageRepository = provider.GetRequiredService<IPageRepository>();
|
||||||
|
var pageModuleRepository = provider.GetRequiredService<IPageModuleRepository>();
|
||||||
|
var TenantManager = provider.GetRequiredService<ITenantManager>();
|
||||||
|
var syncManager = provider.GetRequiredService<ISyncManager>();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(parameters))
|
||||||
|
{
|
||||||
|
// get parameters
|
||||||
|
var globalReplace = JsonSerializer.Deserialize<GlobalReplace>(parameters);
|
||||||
|
|
||||||
|
var find = globalReplace.Find;
|
||||||
|
var replace = globalReplace.Replace;
|
||||||
|
var comparisonType = (globalReplace.CaseSensitive) ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase;
|
||||||
|
var refresh = false;
|
||||||
|
|
||||||
|
log += $"Replacing: '{find}' With: '{replace}' Case Sensitive: {globalReplace.CaseSensitive}<br />";
|
||||||
|
|
||||||
|
// site properties
|
||||||
|
site = siteRepository.GetSite(site.SiteId);
|
||||||
|
var changed = false;
|
||||||
|
if (site.Name != null && site.Name.Contains(find, comparisonType))
|
||||||
|
{
|
||||||
|
site.Name = site.Name.Replace(find, replace, comparisonType);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (site.HeadContent != null && site.HeadContent.Contains(find, comparisonType))
|
||||||
|
{
|
||||||
|
site.HeadContent = site.HeadContent.Replace(find, replace, comparisonType);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (site.BodyContent != null && site.BodyContent.Contains(find, comparisonType))
|
||||||
|
{
|
||||||
|
site.BodyContent = site.BodyContent.Replace(find, replace, comparisonType);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (changed && globalReplace.Site)
|
||||||
|
{
|
||||||
|
siteRepository.UpdateSite(site);
|
||||||
|
log += $"Site Updated<br />";
|
||||||
|
refresh = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pages = pageRepository.GetPages(site.SiteId).ToList();
|
||||||
|
var pageModules = pageModuleRepository.GetPageModules(site.SiteId).ToList();
|
||||||
|
|
||||||
|
// iterate pages
|
||||||
|
foreach (var page in pages)
|
||||||
|
{
|
||||||
|
// page properties
|
||||||
|
changed = false;
|
||||||
|
if (page.Name != null && page.Name.Contains(find, comparisonType))
|
||||||
|
{
|
||||||
|
page.Name = page.Name.Replace(find, replace, comparisonType);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (page.Title != null && page.Title.Contains(find, comparisonType))
|
||||||
|
{
|
||||||
|
page.Title = page.Title.Replace(find, replace, comparisonType);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (page.HeadContent != null && page.HeadContent.Contains(find, comparisonType))
|
||||||
|
{
|
||||||
|
page.HeadContent = page.HeadContent.Replace(find, replace, comparisonType);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (page.BodyContent != null && page.BodyContent.Contains(find, comparisonType))
|
||||||
|
{
|
||||||
|
page.BodyContent = page.BodyContent.Replace(find, replace, comparisonType);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (changed && globalReplace.Pages)
|
||||||
|
{
|
||||||
|
pageRepository.UpdatePage(page);
|
||||||
|
log += $"Page Updated: /{page.Path}<br />";
|
||||||
|
refresh = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var pageModule in pageModules.Where(item => item.PageId == page.PageId))
|
||||||
|
{
|
||||||
|
// module properties
|
||||||
|
changed = false;
|
||||||
|
if (pageModule.Title != null && pageModule.Title.Contains(find, comparisonType))
|
||||||
|
{
|
||||||
|
pageModule.Title = pageModule.Title.Replace(find, replace, comparisonType);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (pageModule.Header != null && pageModule.Header.Contains(find, comparisonType))
|
||||||
|
{
|
||||||
|
pageModule.Header = pageModule.Header.Replace(find, replace, comparisonType);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (pageModule.Footer != null && pageModule.Footer.Contains(find, comparisonType))
|
||||||
|
{
|
||||||
|
pageModule.Footer = pageModule.Footer.Replace(find, replace, comparisonType);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (changed && globalReplace.Modules)
|
||||||
|
{
|
||||||
|
pageModuleRepository.UpdatePageModule(pageModule);
|
||||||
|
log += $"Module Updated: {pageModule.Title} Page: /{page.Path}<br />";
|
||||||
|
refresh = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// module content
|
||||||
|
if (pageModule.Module.ModuleDefinition != null && pageModule.Module.ModuleDefinition.ServerManagerType != "")
|
||||||
|
{
|
||||||
|
Type moduleType = Type.GetType(pageModule.Module.ModuleDefinition.ServerManagerType);
|
||||||
|
if (moduleType != null && moduleType.GetInterface(nameof(IPortable)) != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var moduleObject = ActivatorUtilities.CreateInstance(provider, moduleType);
|
||||||
|
var moduleContent = ((IPortable)moduleObject).ExportModule(pageModule.Module);
|
||||||
|
if (!string.IsNullOrEmpty(moduleContent) && moduleContent.Contains(WebUtility.HtmlEncode(find), comparisonType) && globalReplace.Content)
|
||||||
|
{
|
||||||
|
moduleContent = moduleContent.Replace(WebUtility.HtmlEncode(find), WebUtility.HtmlEncode(replace), comparisonType);
|
||||||
|
((IPortable)moduleObject).ImportModule(pageModule.Module, moduleContent, pageModule.Module.ModuleDefinition.Version);
|
||||||
|
log += $"Module Content Updated: {pageModule.Title} Page: /{page.Path}<br />";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
log += $"Error Processing Module {pageModule.Module.ModuleDefinition.Name} - {ex.Message}<br />";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refresh)
|
||||||
|
{
|
||||||
|
// clear cache
|
||||||
|
syncManager.AddSyncEvent(TenantManager.GetAlias(), EntityNames.Site, site.SiteId, SyncEventActions.Refresh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log += $"No Criteria Provided<br />";
|
||||||
|
}
|
||||||
|
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
48
Oqtane.Server/Infrastructure/SiteTasks/ImportUsersTask.cs
Normal file
48
Oqtane.Server/Infrastructure/SiteTasks/ImportUsersTask.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Oqtane.Managers;
|
||||||
|
using Oqtane.Models;
|
||||||
|
using Oqtane.Repository;
|
||||||
|
|
||||||
|
namespace Oqtane.Infrastructure
|
||||||
|
{
|
||||||
|
public class ImportUsersTask : SiteTaskBase
|
||||||
|
{
|
||||||
|
public override async Task<string> ExecuteTaskAsync(IServiceProvider provider, Site site, string parameters)
|
||||||
|
{
|
||||||
|
string log = "";
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(parameters) && parameters.Contains(":"))
|
||||||
|
{
|
||||||
|
var fileId = int.Parse(parameters.Split(':')[0]);
|
||||||
|
var notify = bool.Parse(parameters.Split(':')[1]);
|
||||||
|
|
||||||
|
var fileRepository = provider.GetRequiredService<IFileRepository>();
|
||||||
|
var userManager = provider.GetRequiredService<IUserManager>();
|
||||||
|
|
||||||
|
var file = fileRepository.GetFile(fileId);
|
||||||
|
if (file != null)
|
||||||
|
{
|
||||||
|
var filePath = fileRepository.GetFilePath(file);
|
||||||
|
log += $"Importing Users From {filePath}<br />";
|
||||||
|
var result = await userManager.ImportUsers(site.SiteId, filePath, notify);
|
||||||
|
if (result["Success"] == "True")
|
||||||
|
{
|
||||||
|
log += $"{result["Users"]} Users Imported<br />";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log += $"User Import Failed<br />";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log += $"Import Users FileId {fileId} Does Not Exist<br />";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
19
Oqtane.Server/Infrastructure/SiteTasks/SiteTaskBase.cs
Normal file
19
Oqtane.Server/Infrastructure/SiteTasks/SiteTaskBase.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Oqtane.Models;
|
||||||
|
|
||||||
|
namespace Oqtane.Infrastructure
|
||||||
|
{
|
||||||
|
public class SiteTaskBase : ISiteTask
|
||||||
|
{
|
||||||
|
public virtual string ExecuteTask(IServiceProvider provider, Site site, string parameters)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual Task<string> ExecuteTaskAsync(IServiceProvider provider, Site site, string parameters)
|
||||||
|
{
|
||||||
|
return Task.FromResult(string.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -607,6 +607,34 @@ namespace Oqtane.Infrastructure.SiteTemplates
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
pageTemplates.Add(new PageTemplate
|
||||||
|
{
|
||||||
|
Name = "Global Replace",
|
||||||
|
Parent = "Admin",
|
||||||
|
Order = 23,
|
||||||
|
Path = "admin/replace",
|
||||||
|
Icon = Icons.LoopSquare,
|
||||||
|
IsNavigation = false,
|
||||||
|
IsPersonalizable = false,
|
||||||
|
PermissionList = new List<Permission>
|
||||||
|
{
|
||||||
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
|
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||||
|
},
|
||||||
|
PageTemplateModules = new List<PageTemplateModule>
|
||||||
|
{
|
||||||
|
new PageTemplateModule
|
||||||
|
{
|
||||||
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.GlobalReplace.Index).ToModuleDefinitionName(), Title = "Global Replace", Pane = PaneNames.Default,
|
||||||
|
PermissionList = new List<Permission>
|
||||||
|
{
|
||||||
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
|
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||||
|
},
|
||||||
|
Content = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// host pages (order starts at 51)
|
// host pages (order starts at 51)
|
||||||
pageTemplates.Add(new PageTemplate
|
pageTemplates.Add(new PageTemplate
|
||||||
|
|||||||
@@ -49,7 +49,10 @@ namespace Oqtane.Infrastructure.SiteTemplates
|
|||||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||||
},
|
},
|
||||||
PageTemplateModules = new List<PageTemplateModule> {
|
PageTemplateModules = new List<PageTemplateModule> {
|
||||||
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Welcome To Oqtane...", Pane = PaneNames.Default,
|
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client",
|
||||||
|
Title = "Welcome To Oqtane...",
|
||||||
|
Pane = PaneNames.Default,
|
||||||
|
Order = 1,
|
||||||
PermissionList = new List<Permission> {
|
PermissionList = new List<Permission> {
|
||||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
@@ -60,7 +63,10 @@ namespace Oqtane.Infrastructure.SiteTemplates
|
|||||||
"<p><a href=\"https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor\" target=\"_new\">Blazor</a> is a modern front-end web framework based on HTML, CSS, and C# that helps you build web applications faster. Blazor provides a component-based architecture with server-side rendering and full client-side interactivity in a single solution, where you can switch between server-side and client-side rendering modes and even mix them in the same web page. For desktop or mobile scenarios, Blazor Hybrid is part of .NET MAUI and uses a Web View to render components natively on all modern devices.</p>" +
|
"<p><a href=\"https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor\" target=\"_new\">Blazor</a> is a modern front-end web framework based on HTML, CSS, and C# that helps you build web applications faster. Blazor provides a component-based architecture with server-side rendering and full client-side interactivity in a single solution, where you can switch between server-side and client-side rendering modes and even mix them in the same web page. For desktop or mobile scenarios, Blazor Hybrid is part of .NET MAUI and uses a Web View to render components natively on all modern devices.</p>" +
|
||||||
"<p>Blazor is a feature of <a href=\"https://dotnet.microsoft.com/apps/aspnet\" target=\"_new\">ASP.NET</a>, the popular cross platform development framework from Microsoft that provides powerful tools and libraries for building modern software applications.</p>"
|
"<p>Blazor is a feature of <a href=\"https://dotnet.microsoft.com/apps/aspnet\" target=\"_new\">ASP.NET</a>, the popular cross platform development framework from Microsoft that provides powerful tools and libraries for building modern software applications.</p>"
|
||||||
},
|
},
|
||||||
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "MIT License", Pane = PaneNames.Default,
|
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client",
|
||||||
|
Title = "MIT License",
|
||||||
|
Pane = PaneNames.Default,
|
||||||
|
Order = 3,
|
||||||
PermissionList = new List<Permission> {
|
PermissionList = new List<Permission> {
|
||||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
@@ -71,7 +77,10 @@ namespace Oqtane.Infrastructure.SiteTemplates
|
|||||||
"<p>The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</p>" +
|
"<p>The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</p>" +
|
||||||
"<p>THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p>"
|
"<p>THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p>"
|
||||||
},
|
},
|
||||||
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Secure Content", Pane = PaneNames.Default,
|
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client",
|
||||||
|
Title = "Secure Content",
|
||||||
|
Pane = PaneNames.Default,
|
||||||
|
Order = 5,
|
||||||
PermissionList = new List<Permission> {
|
PermissionList = new List<Permission> {
|
||||||
new Permission(PermissionNames.View, RoleNames.Registered, true),
|
new Permission(PermissionNames.View, RoleNames.Registered, true),
|
||||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
@@ -96,7 +105,10 @@ namespace Oqtane.Infrastructure.SiteTemplates
|
|||||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||||
},
|
},
|
||||||
PageTemplateModules = new List<PageTemplateModule> {
|
PageTemplateModules = new List<PageTemplateModule> {
|
||||||
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Secure Content", Pane = PaneNames.Default,
|
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client",
|
||||||
|
Title = "Secure Content",
|
||||||
|
Pane = PaneNames.Default,
|
||||||
|
Order = 1,
|
||||||
PermissionList = new List<Permission> {
|
PermissionList = new List<Permission> {
|
||||||
new Permission(PermissionNames.View, RoleNames.Registered, true),
|
new Permission(PermissionNames.View, RoleNames.Registered, true),
|
||||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
@@ -121,7 +133,10 @@ namespace Oqtane.Infrastructure.SiteTemplates
|
|||||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||||
},
|
},
|
||||||
PageTemplateModules = new List<PageTemplateModule> {
|
PageTemplateModules = new List<PageTemplateModule> {
|
||||||
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "My Page", Pane = PaneNames.Default,
|
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client",
|
||||||
|
Title = "My Page",
|
||||||
|
Pane = PaneNames.Default,
|
||||||
|
Order = 1,
|
||||||
PermissionList = new List<Permission> {
|
PermissionList = new List<Permission> {
|
||||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
|
|||||||
@@ -93,6 +93,9 @@ namespace Oqtane.Infrastructure
|
|||||||
case "10.0.4":
|
case "10.0.4":
|
||||||
Upgrade_10_0_4(tenant, scope);
|
Upgrade_10_0_4(tenant, scope);
|
||||||
break;
|
break;
|
||||||
|
case "10.1.0":
|
||||||
|
Upgrade_10_1_0(tenant, scope);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -602,6 +605,45 @@ namespace Oqtane.Infrastructure
|
|||||||
RemoveAssemblies(tenant, assemblies, "10.0.4");
|
RemoveAssemblies(tenant, assemblies, "10.0.4");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Upgrade_10_1_0(Tenant tenant, IServiceScope scope)
|
||||||
|
{
|
||||||
|
var pageTemplates = new List<PageTemplate>
|
||||||
|
{
|
||||||
|
new PageTemplate
|
||||||
|
{
|
||||||
|
Update = false,
|
||||||
|
Name = "Global Replace",
|
||||||
|
Parent = "Admin",
|
||||||
|
Order = 23,
|
||||||
|
Path = "admin/replace",
|
||||||
|
Icon = Icons.LoopSquare,
|
||||||
|
IsNavigation = false,
|
||||||
|
IsPersonalizable = false,
|
||||||
|
PermissionList = new List<Permission>
|
||||||
|
{
|
||||||
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
|
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||||
|
},
|
||||||
|
PageTemplateModules = new List<PageTemplateModule>
|
||||||
|
{
|
||||||
|
new PageTemplateModule
|
||||||
|
{
|
||||||
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.GlobalReplace.Index).ToModuleDefinitionName(), Title = "Global Replace", Pane = PaneNames.Default,
|
||||||
|
PermissionList = new List<Permission>
|
||||||
|
{
|
||||||
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
|
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||||
|
},
|
||||||
|
Content = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AddPagesToSites(scope, tenant, pageTemplates);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void AddPagesToSites(IServiceScope scope, Tenant tenant, List<PageTemplate> pageTemplates)
|
private void AddPagesToSites(IServiceScope scope, Tenant tenant, List<PageTemplate> pageTemplates)
|
||||||
{
|
{
|
||||||
var tenants = scope.ServiceProvider.GetRequiredService<ITenantManager>();
|
var tenants = scope.ServiceProvider.GetRequiredService<ITenantManager>();
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||||
|
using Oqtane.Databases.Interfaces;
|
||||||
|
|
||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||||
|
|
||||||
|
namespace Oqtane.Migrations.EntityBuilders
|
||||||
|
{
|
||||||
|
public class SiteGroupEntityBuilder : AuditableBaseEntityBuilder<SiteGroupEntityBuilder>
|
||||||
|
{
|
||||||
|
private const string _entityTableName = "SiteGroup";
|
||||||
|
private readonly PrimaryKey<SiteGroupEntityBuilder> _primaryKey = new("PK_SiteGroup", x => x.SiteGroupId);
|
||||||
|
|
||||||
|
public SiteGroupEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||||
|
{
|
||||||
|
EntityTableName = _entityTableName;
|
||||||
|
PrimaryKey = _primaryKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override SiteGroupEntityBuilder BuildTable(ColumnsBuilder table)
|
||||||
|
{
|
||||||
|
SiteGroupId = AddAutoIncrementColumn(table, "SiteGroupId");
|
||||||
|
Name = AddStringColumn(table, "Name", 200);
|
||||||
|
Type = AddStringColumn(table, "Type", 50);
|
||||||
|
PrimarySiteId = AddIntegerColumn(table, "PrimarySiteId");
|
||||||
|
Synchronize = AddBooleanColumn(table, "Synchronize");
|
||||||
|
|
||||||
|
AddAuditableColumns(table);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperationBuilder<AddColumnOperation> SiteGroupId { get; set; }
|
||||||
|
|
||||||
|
public OperationBuilder<AddColumnOperation> Name { get; set; }
|
||||||
|
|
||||||
|
public OperationBuilder<AddColumnOperation> Type { get; set; }
|
||||||
|
|
||||||
|
public OperationBuilder<AddColumnOperation> PrimarySiteId { get; set; }
|
||||||
|
|
||||||
|
public OperationBuilder<AddColumnOperation> Synchronize { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||||
|
using Oqtane.Databases.Interfaces;
|
||||||
|
|
||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||||
|
|
||||||
|
namespace Oqtane.Migrations.EntityBuilders
|
||||||
|
{
|
||||||
|
public class SiteGroupMemberEntityBuilder : AuditableBaseEntityBuilder<SiteGroupMemberEntityBuilder>
|
||||||
|
{
|
||||||
|
private const string _entityTableName = "SiteGroupMember";
|
||||||
|
private readonly PrimaryKey<SiteGroupMemberEntityBuilder> _primaryKey = new("PK_SiteGroupMember", x => x.SiteGroupMemberId);
|
||||||
|
private readonly ForeignKey<SiteGroupMemberEntityBuilder> _groupForeignKey = new("FK_SiteGroupMember_SiteGroup", x => x.SiteGroupId, "SiteGroup", "SiteGroupId", ReferentialAction.Cascade);
|
||||||
|
private readonly ForeignKey<SiteGroupMemberEntityBuilder> _siteForeignKey = new("FK_SiteGroupMember_Site", x => x.SiteId, "Site", "SiteId", ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
public SiteGroupMemberEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||||
|
{
|
||||||
|
EntityTableName = _entityTableName;
|
||||||
|
PrimaryKey = _primaryKey;
|
||||||
|
ForeignKeys.Add(_groupForeignKey);
|
||||||
|
ForeignKeys.Add(_siteForeignKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override SiteGroupMemberEntityBuilder BuildTable(ColumnsBuilder table)
|
||||||
|
{
|
||||||
|
SiteGroupMemberId = AddAutoIncrementColumn(table, "SiteGroupMemberId");
|
||||||
|
SiteGroupId = AddIntegerColumn(table, "SiteGroupId");
|
||||||
|
SiteId = AddIntegerColumn(table, "SiteId");
|
||||||
|
SynchronizedOn = AddDateTimeColumn(table, "SynchronizedOn", true);
|
||||||
|
|
||||||
|
AddAuditableColumns(table);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperationBuilder<AddColumnOperation> SiteGroupMemberId { get; set; }
|
||||||
|
|
||||||
|
public OperationBuilder<AddColumnOperation> SiteGroupId { get; set; }
|
||||||
|
|
||||||
|
public OperationBuilder<AddColumnOperation> SiteId { get; set; }
|
||||||
|
|
||||||
|
public OperationBuilder<AddColumnOperation> SynchronizedOn { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||||
|
using Oqtane.Databases.Interfaces;
|
||||||
|
|
||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||||
|
|
||||||
|
namespace Oqtane.Migrations.EntityBuilders
|
||||||
|
{
|
||||||
|
public class SiteTaskEntityBuilder : AuditableBaseEntityBuilder<SiteTaskEntityBuilder>
|
||||||
|
{
|
||||||
|
private const string _entityTableName = "SiteTask";
|
||||||
|
private readonly PrimaryKey<SiteTaskEntityBuilder> _primaryKey = new("PK_SiteTask", x => x.SiteTaskId);
|
||||||
|
private readonly ForeignKey<SiteTaskEntityBuilder> _siteForeignKey = new("FK_SiteTask_Site", x => x.SiteId, "Site", "SiteId", ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
public SiteTaskEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||||
|
{
|
||||||
|
EntityTableName = _entityTableName;
|
||||||
|
PrimaryKey = _primaryKey;
|
||||||
|
ForeignKeys.Add(_siteForeignKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override SiteTaskEntityBuilder BuildTable(ColumnsBuilder table)
|
||||||
|
{
|
||||||
|
SiteTaskId = AddAutoIncrementColumn(table,"SiteTaskId");
|
||||||
|
SiteId = AddIntegerColumn(table,"SiteId");
|
||||||
|
Name = AddStringColumn(table, "Name", 200);
|
||||||
|
Type = AddStringColumn(table, "Type", 200);
|
||||||
|
Parameters = AddMaxStringColumn(table, "Parameters", true);
|
||||||
|
IsCompleted = AddBooleanColumn(table, "IsCompleted", true);
|
||||||
|
Status = AddMaxStringColumn(table, "Status", true);
|
||||||
|
|
||||||
|
AddAuditableColumns(table);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperationBuilder<AddColumnOperation> SiteTaskId { get; private set; }
|
||||||
|
|
||||||
|
public OperationBuilder<AddColumnOperation> SiteId { get; private set; }
|
||||||
|
|
||||||
|
public OperationBuilder<AddColumnOperation> Name { get; private set; }
|
||||||
|
|
||||||
|
public OperationBuilder<AddColumnOperation> Type { get; private set; }
|
||||||
|
|
||||||
|
public OperationBuilder<AddColumnOperation> Parameters { get; private set; }
|
||||||
|
|
||||||
|
public OperationBuilder<AddColumnOperation> IsCompleted { get; private set; }
|
||||||
|
|
||||||
|
public OperationBuilder<AddColumnOperation> Status { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
32
Oqtane.Server/Migrations/Tenant/10010001_AddSiteGroups.cs
Normal file
32
Oqtane.Server/Migrations/Tenant/10010001_AddSiteGroups.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Oqtane.Databases.Interfaces;
|
||||||
|
using Oqtane.Migrations.EntityBuilders;
|
||||||
|
using Oqtane.Repository;
|
||||||
|
|
||||||
|
namespace Oqtane.Migrations.Tenant
|
||||||
|
{
|
||||||
|
[DbContext(typeof(TenantDBContext))]
|
||||||
|
[Migration("Tenant.10.01.00.01")]
|
||||||
|
public class AddSiteGroups : MultiDatabaseMigration
|
||||||
|
{
|
||||||
|
public AddSiteGroups(IDatabase database) : base(database)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
var siteGroupEntityBuilder = new SiteGroupEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
|
siteGroupEntityBuilder.Create();
|
||||||
|
|
||||||
|
var siteGroupMemberEntityBuilder = new SiteGroupMemberEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
|
siteGroupMemberEntityBuilder.Create();
|
||||||
|
siteGroupMemberEntityBuilder.AddIndex("IX_SiteGroupMember", new[] { "SiteId", "SiteGroupId" }, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
// not implemented
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
33
Oqtane.Server/Migrations/Tenant/10010002_AddCultureCode.cs
Normal file
33
Oqtane.Server/Migrations/Tenant/10010002_AddCultureCode.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Oqtane.Databases.Interfaces;
|
||||||
|
using Oqtane.Migrations.EntityBuilders;
|
||||||
|
using Oqtane.Repository;
|
||||||
|
|
||||||
|
namespace Oqtane.Migrations.Tenant
|
||||||
|
{
|
||||||
|
[DbContext(typeof(TenantDBContext))]
|
||||||
|
[Migration("Tenant.10.01.00.02")]
|
||||||
|
public class AddCultureCode : MultiDatabaseMigration
|
||||||
|
{
|
||||||
|
public AddCultureCode(IDatabase database) : base(database)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
|
siteEntityBuilder.AddStringColumn("CultureCode", 10, true);
|
||||||
|
siteEntityBuilder.UpdateData("CultureCode", $"'{Shared.Constants.DefaultCulture}'");
|
||||||
|
|
||||||
|
var userEntityBuilder = new UserEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
|
userEntityBuilder.AddStringColumn("CultureCode", 10, true);
|
||||||
|
userEntityBuilder.UpdateData("CultureCode", $"'{Shared.Constants.DefaultCulture}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
// not implemented
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
Oqtane.Server/Migrations/Tenant/10010003_RemoveHomePageId.cs
Normal file
28
Oqtane.Server/Migrations/Tenant/10010003_RemoveHomePageId.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Oqtane.Databases.Interfaces;
|
||||||
|
using Oqtane.Migrations.EntityBuilders;
|
||||||
|
using Oqtane.Repository;
|
||||||
|
|
||||||
|
namespace Oqtane.Migrations.Tenant
|
||||||
|
{
|
||||||
|
[DbContext(typeof(TenantDBContext))]
|
||||||
|
[Migration("Tenant.10.01.00.03")]
|
||||||
|
public class RemoveHomePageId : MultiDatabaseMigration
|
||||||
|
{
|
||||||
|
public RemoveHomePageId(IDatabase database) : base(database)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
var siteEntityBuilder = new SiteEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
|
siteEntityBuilder.DropColumn("HomePageId");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
// not implemented
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
Oqtane.Server/Migrations/Tenant/10010004_AddSiteTasks.cs
Normal file
28
Oqtane.Server/Migrations/Tenant/10010004_AddSiteTasks.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Oqtane.Databases.Interfaces;
|
||||||
|
using Oqtane.Migrations.EntityBuilders;
|
||||||
|
using Oqtane.Repository;
|
||||||
|
|
||||||
|
namespace Oqtane.Migrations.Tenant
|
||||||
|
{
|
||||||
|
[DbContext(typeof(TenantDBContext))]
|
||||||
|
[Migration("Tenant.10.01.00.04")]
|
||||||
|
public class AddSiteTasks : MultiDatabaseMigration
|
||||||
|
{
|
||||||
|
public AddSiteTasks(IDatabase database) : base(database)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
var siteTaskEntityBuilder = new SiteTaskEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
|
siteTaskEntityBuilder.Create();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
// not implemented
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user