Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
commit
74c403cef1
|
@ -1,31 +1,39 @@
|
||||||
@inject IInstallationService InstallationService
|
@inject IInstallationService InstallationService
|
||||||
|
|
||||||
@if (_initialized)
|
@if (_initialized)
|
||||||
{
|
{
|
||||||
@if (!_installed)
|
@if (!_installation.Success)
|
||||||
{
|
{
|
||||||
<Installer />
|
<Installer />
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<CascadingAuthenticationState>
|
@if (string.IsNullOrEmpty(_installation.Message))
|
||||||
<CascadingValue Value="@PageState">
|
{
|
||||||
<SiteRouter OnStateChange="@ChangeState" />
|
<CascadingAuthenticationState>
|
||||||
</CascadingValue>
|
<CascadingValue Value="@PageState">
|
||||||
</CascadingAuthenticationState>
|
<SiteRouter OnStateChange="@ChangeState" />
|
||||||
|
</CascadingValue>
|
||||||
|
</CascadingAuthenticationState>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<div class="app-alert">
|
||||||
|
@_installation.Message
|
||||||
|
</div>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
private Installation _installation;
|
||||||
private bool _initialized;
|
private bool _initialized;
|
||||||
private bool _installed;
|
|
||||||
|
|
||||||
private PageState PageState { get; set; }
|
private PageState PageState { get; set; }
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
var installation = await InstallationService.IsInstalled();
|
_installation = await InstallationService.IsInstalled();
|
||||||
_installed = installation.Success;
|
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2" align="center">
|
<td colspan="2" align="center">
|
||||||
<Label For="permissions" HelpText="Select the permissions you want for the folder" ResourceKey="Permissions">Permissions: </Label>
|
<Label For="permissions" HelpText="Select the permissions you want for the folder" ResourceKey="Permissions">Permissions: </Label>
|
||||||
<PermissionGrid EntityName="@EntityNames.Folder" PermissionNames="Browse,View,Edit" Permissions="@_permissions" @ref="_permissionGrid" />
|
<PermissionGrid EntityName="@EntityNames.Folder" PermissionNames="@(PermissionNames.Browse + "," + PermissionNames.View + "," + PermissionNames.Edit)" Permissions="@_permissions" @ref="_permissionGrid" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -11,26 +11,28 @@
|
||||||
}
|
}
|
||||||
<AuthorizeView>
|
<AuthorizeView>
|
||||||
<NotAuthorized>
|
<NotAuthorized>
|
||||||
<div class="container Oqtane-Modules-Admin-Login">
|
<form @ref="login" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||||
<div class="form-group">
|
<div class="container Oqtane-Modules-Admin-Login" @onkeypress="@(e => KeyPressed(e))">
|
||||||
<label for="Username" class="control-label">@Localizer["Username:"] </label>
|
<div class="form-group">
|
||||||
<input type="text" name="Username" class="form-control username" placeholder="Username" @bind="@_username" id="Username" />
|
<label for="Username" class="control-label">@Localizer["Username:"] </label>
|
||||||
</div>
|
<input type="text" @ref="username" name="Username" class="form-control username" placeholder="Username" @bind="@_username" id="Username" required />
|
||||||
<div class="form-group">
|
|
||||||
<label for="Password" class="control-label">@Localizer["Password:"] </label>
|
|
||||||
<input type="password" name="Password" class="form-control password" placeholder="Password" @bind="@_password" id="Password" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="form-check form-check-inline">
|
|
||||||
<label class="form-check-label" for="Remember">@Localizer["Remember Me?"]</label>
|
|
||||||
<input type="checkbox" class="form-check-input" name="Remember" @bind="@_remember" id="Remember" />
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="Password" class="control-label">@Localizer["Password:"] </label>
|
||||||
|
<input type="password" name="Password" class="form-control password" placeholder="Password" @bind="@_password" id="Password" required />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-check form-check-inline">
|
||||||
|
<label class="form-check-label" for="Remember">@Localizer["Remember Me?"]</label>
|
||||||
|
<input type="checkbox" class="form-check-input" name="Remember" @bind="@_remember" id="Remember" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-primary" @onclick="Login">@Localizer["Login"]</button>
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="Cancel">@Localizer["Cancel"]</button>
|
||||||
|
<br /><br />
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="Forgot">@Localizer["Forgot Password"]</button>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-primary" @onclick="Login">@Localizer["Login"]</button>
|
</form>
|
||||||
<button type="button" class="btn btn-secondary" @onclick="Cancel">@Localizer["Cancel"]</button>
|
|
||||||
<br /><br />
|
|
||||||
<button type="button" class="btn btn-secondary" @onclick="Forgot">@Localizer["Forgot Password"]</button>
|
|
||||||
</div>
|
|
||||||
</NotAuthorized>
|
</NotAuthorized>
|
||||||
</AuthorizeView>
|
</AuthorizeView>
|
||||||
|
|
||||||
|
@ -41,6 +43,10 @@
|
||||||
private string _username = string.Empty;
|
private string _username = string.Empty;
|
||||||
private string _password = string.Empty;
|
private string _password = string.Empty;
|
||||||
private bool _remember = false;
|
private bool _remember = false;
|
||||||
|
private bool validated = false;
|
||||||
|
|
||||||
|
private ElementReference login;
|
||||||
|
private ElementReference username;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
||||||
|
|
||||||
|
@ -80,52 +86,68 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
|
{
|
||||||
|
if (firstRender)
|
||||||
|
{
|
||||||
|
await username.FocusAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task Login()
|
private async Task Login()
|
||||||
{
|
{
|
||||||
if (PageState.Runtime == Oqtane.Shared.Runtime.Server)
|
validated = true;
|
||||||
|
var interop = new Interop(JSRuntime);
|
||||||
|
if (await interop.FormValid(login))
|
||||||
{
|
{
|
||||||
// server-side Blazor
|
if (PageState.Runtime == Oqtane.Shared.Runtime.Server)
|
||||||
var user = new User();
|
|
||||||
user.SiteId = PageState.Site.SiteId;
|
|
||||||
user.Username = _username;
|
|
||||||
user.Password = _password;
|
|
||||||
user = await UserService.LoginUserAsync(user, false, false);
|
|
||||||
|
|
||||||
if (user.IsAuthenticated)
|
|
||||||
{
|
{
|
||||||
await logger.LogInformation("Login Successful For Username {Username}", _username);
|
// server-side Blazor
|
||||||
// complete the login on the server so that the cookies are set correctly on SignalR
|
var user = new User();
|
||||||
var interop = new Interop(JSRuntime);
|
user.SiteId = PageState.Site.SiteId;
|
||||||
string antiforgerytoken = await interop.GetElementByName("__RequestVerificationToken");
|
user.Username = _username;
|
||||||
var fields = new { __RequestVerificationToken = antiforgerytoken, username = _username, password = _password, remember = _remember, returnurl = _returnUrl };
|
user.Password = _password;
|
||||||
await interop.SubmitForm($"/{PageState.Alias.AliasId}/pages/login/", fields);
|
user = await UserService.LoginUserAsync(user, false, false);
|
||||||
|
|
||||||
|
if (user.IsAuthenticated)
|
||||||
|
{
|
||||||
|
await logger.LogInformation("Login Successful For Username {Username}", _username);
|
||||||
|
// complete the login on the server so that the cookies are set correctly on SignalR
|
||||||
|
string antiforgerytoken = await interop.GetElementByName("__RequestVerificationToken");
|
||||||
|
var fields = new { __RequestVerificationToken = antiforgerytoken, username = _username, password = _password, remember = _remember, returnurl = _returnUrl };
|
||||||
|
await interop.SubmitForm($"/{PageState.Alias.AliasId}/pages/login/", fields);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await logger.LogInformation("Login Failed For Username {Username}", _username);
|
||||||
|
AddModuleMessage(Localizer["Login Failed. Please Remember That Passwords Are Case Sensitive And User Accounts Require Verification When They Are Initially Created So You May Wish To Check Your Email."], MessageType.Error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await logger.LogInformation("Login Failed For Username {Username}", _username);
|
// client-side Blazor
|
||||||
AddModuleMessage(Localizer["Login Failed. Please Remember That Passwords Are Case Sensitive And User Accounts Require Email Verification When They Initially Created."], MessageType.Error);
|
var user = new User();
|
||||||
|
user.SiteId = PageState.Site.SiteId;
|
||||||
|
user.Username = _username;
|
||||||
|
user.Password = _password;
|
||||||
|
user = await UserService.LoginUserAsync(user, true, _remember);
|
||||||
|
if (user.IsAuthenticated)
|
||||||
|
{
|
||||||
|
await logger.LogInformation("Login Successful For Username {Username}", _username);
|
||||||
|
var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider));
|
||||||
|
authstateprovider.NotifyAuthenticationChanged();
|
||||||
|
NavigationManager.NavigateTo(NavigateUrl(_returnUrl, "reload"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await logger.LogInformation("Login Failed For Username {Username}", _username);
|
||||||
|
AddModuleMessage(Localizer["Login Failed. Please Remember That Passwords Are Case Sensitive And User Accounts Require Verification When They Are Initially Created So You May Wish To Check Your Email."], MessageType.Error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// client-side Blazor
|
AddModuleMessage(Localizer["Please Provide Your Username And Password"], MessageType.Warning);
|
||||||
var user = new User();
|
|
||||||
user.SiteId = PageState.Site.SiteId;
|
|
||||||
user.Username = _username;
|
|
||||||
user.Password = _password;
|
|
||||||
user = await UserService.LoginUserAsync(user, true, _remember);
|
|
||||||
if (user.IsAuthenticated)
|
|
||||||
{
|
|
||||||
await logger.LogInformation("Login Successful For Username {Username}", _username);
|
|
||||||
var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider));
|
|
||||||
authstateprovider.NotifyAuthenticationChanged();
|
|
||||||
NavigationManager.NavigateTo(NavigateUrl(_returnUrl, "reload"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await logger.LogInformation("Login Failed For Username {Username}", _username);
|
|
||||||
AddModuleMessage(Localizer["Login Failed. Please Remember That Passwords Are Case Sensitive And User Accounts Require Verification When They Are Initially Created So You May Wish To Check Your Email."], MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,4 +179,12 @@
|
||||||
|
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task KeyPressed(KeyboardEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Code == "Enter" || e.Code == "NumpadEnter")
|
||||||
|
{
|
||||||
|
await Login();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,8 @@ else
|
||||||
<table class="table table-borderless">
|
<table class="table table-borderless">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<label>@Localizer["Level:"] </label>
|
<Label For="level" HelpText="Select the log level for event log items" ResourceKey="Level">Level: </Label><br /><br />
|
||||||
<select class="form-control" @onchange="(e => LevelChanged(e))">
|
<select id="level" class="form-control" @onchange="(e => LevelChanged(e))">
|
||||||
<option value="-"><@Localizer["All Levels"]></option>
|
<option value="-"><@Localizer["All Levels"]></option>
|
||||||
<option value="Trace">@Localizer["Trace"]</option>
|
<option value="Trace">@Localizer["Trace"]</option>
|
||||||
<option value="Debug">@Localizer["Debug"]</option>
|
<option value="Debug">@Localizer["Debug"]</option>
|
||||||
|
@ -24,8 +24,8 @@ else
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<label>@Localizer["Function:"] </label>
|
<Label For="function" HelpText="Select the function for event log items" ResourceKey="Function">Function: </Label><br /><br />
|
||||||
<select class="form-control" @onchange="(e => FunctionChanged(e))">
|
<select id="function" class="form-control" @onchange="(e => FunctionChanged(e))">
|
||||||
<option value="-"><@Localizer["All Functions"]></option>
|
<option value="-"><@Localizer["All Functions"]></option>
|
||||||
<option value="Create">@Localizer["Create"]</option>
|
<option value="Create">@Localizer["Create"]</option>
|
||||||
<option value="Read">@Localizer["Read"]</option>
|
<option value="Read">@Localizer["Read"]</option>
|
||||||
|
@ -36,8 +36,8 @@ else
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<label>@Localizer["Rows:"] </label>
|
<Label For="rows" HelpText="Select the maximum number of event log items to review. Please note that if you choose more than 10 items the information will be split into pages." ResourceKey="Rows">Maximum Items: </Label><br /><br />
|
||||||
<select class="form-control" @onchange="(e => RowsChanged(e))">
|
<select id="rows" class="form-control" @onchange="(e => RowsChanged(e))">
|
||||||
<option value="10">10</option>
|
<option value="10">10</option>
|
||||||
<option value="50">50</option>
|
<option value="50">50</option>
|
||||||
<option value="100">100</option>
|
<option value="100">100</option>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
@using System.Text.RegularExpressions
|
@using System.Text.RegularExpressions
|
||||||
@using System.IO;
|
@using System.IO;
|
||||||
|
|
||||||
@if (string.IsNullOrEmpty(_moduledefinitionname))
|
@if (string.IsNullOrEmpty(_moduledefinitionname) && _systeminfo != null && _templates != null)
|
||||||
{
|
{
|
||||||
<table class="table table-borderless">
|
<table class="table table-borderless">
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -38,13 +38,15 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<Label For="template" HelpText="Select a module template. Internal modules are created inside of the framework solution. External modules are created outside of the framework solution." ResourceKey="Template">Template: </Label>
|
<Label For="template" HelpText="Select a module template. Templates are located in the wwwroot/Modules/Templates folder on the server." ResourceKey="Template">Template: </Label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<select id="template" class="form-control" @onchange="(e => TemplateChanged(e))">
|
<select id="template" class="form-control" @onchange="(e => TemplateChanged(e))">
|
||||||
<option value="-"><@Localizer["Select Template"]></option>
|
<option value="-"><@Localizer["Select Template"]></option>
|
||||||
<option value="internal">@Localizer["Internal"]</option>
|
@foreach (string template in _templates)
|
||||||
<option value="external">@Localizer["External"]</option>
|
{
|
||||||
|
<option value="@template">@template</option>
|
||||||
|
}
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -90,9 +92,11 @@ else
|
||||||
private string _module = string.Empty;
|
private string _module = string.Empty;
|
||||||
private string _description = string.Empty;
|
private string _description = string.Empty;
|
||||||
private string _template = "-";
|
private string _template = "-";
|
||||||
public string _reference = Constants.Version;
|
private string _reference = Constants.Version;
|
||||||
private string _location = string.Empty;
|
private string _location = string.Empty;
|
||||||
|
|
||||||
private Dictionary<string, string> _systeminfo;
|
private Dictionary<string, string> _systeminfo;
|
||||||
|
private List<string> _templates;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||||
|
|
||||||
|
@ -102,12 +106,11 @@ else
|
||||||
{
|
{
|
||||||
_moduledefinitionname = SettingService.GetSetting(ModuleState.Settings, "ModuleDefinitionName", "");
|
_moduledefinitionname = SettingService.GetSetting(ModuleState.Settings, "ModuleDefinitionName", "");
|
||||||
_systeminfo = await SystemService.GetSystemInfoAsync();
|
_systeminfo = await SystemService.GetSystemInfoAsync();
|
||||||
|
_templates = await ModuleDefinitionService.GetModuleDefinitionTemplatesAsync();
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(_moduledefinitionname))
|
if (string.IsNullOrEmpty(_moduledefinitionname))
|
||||||
{
|
{
|
||||||
_owner = ModuleState.Title;
|
AddModuleMessage(Localizer["Please Note That The Module Creator Is Only Intended To Be Used In A Development Environment"], MessageType.Info);
|
||||||
_module = ModuleState.Title;
|
|
||||||
_description = ModuleState.Title;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -185,18 +188,8 @@ else
|
||||||
if (_template != "-" && _systeminfo != null && _systeminfo.ContainsKey("serverpath"))
|
if (_template != "-" && _systeminfo != null && _systeminfo.ContainsKey("serverpath"))
|
||||||
{
|
{
|
||||||
string[] path = _systeminfo["serverpath"].Split(Path.DirectorySeparatorChar);
|
string[] path = _systeminfo["serverpath"].Split(Path.DirectorySeparatorChar);
|
||||||
if (_template == "internal")
|
_location = string.Join(Path.DirectorySeparatorChar, path, 0, path.Length - 2) +
|
||||||
{
|
Path.DirectorySeparatorChar + _owner + "." + _module;
|
||||||
_location = string.Join(Path.DirectorySeparatorChar, path, 0, path.Length - 1) +
|
|
||||||
Path.DirectorySeparatorChar + "Oqtane.Client" +
|
|
||||||
Path.DirectorySeparatorChar + "Modules" +
|
|
||||||
Path.DirectorySeparatorChar + _owner + "." + _module;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_location = string.Join(Path.DirectorySeparatorChar, path, 0, path.Length - 2) +
|
|
||||||
Path.DirectorySeparatorChar + _owner + "." + _module;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ else
|
||||||
<td>
|
<td>
|
||||||
@if (context.AssemblyName != "Oqtane.Client")
|
@if (context.AssemblyName != "Oqtane.Client")
|
||||||
{
|
{
|
||||||
<ActionDialog Header="Delete Module" Message="@("Are You Sure You Wish To Delete The " + context.Name + " Module?")" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" ResourceKey="DeleteModule" />
|
<ActionDialog Header="Delete Module" Message="@Localizer["Are You Sure You Wish To Delete The {0} Module?", context.Name]" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" ResourceKey="DeleteModule" />
|
||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td>@context.Name</td>
|
<td>@context.Name</td>
|
||||||
|
|
|
@ -101,18 +101,11 @@
|
||||||
<Label For="Theme" HelpText="Select the theme for this page" ResourceKey="Theme">Theme: </Label>
|
<Label For="Theme" HelpText="Select the theme for this page" ResourceKey="Theme">Theme: </Label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<select id="Theme" class="form-control" @onchange="(e => ThemeChanged(e))">
|
<select id="Theme" class="form-control" value="@_themetype" @onchange="(e => ThemeChanged(e))">
|
||||||
<option value="-"><@Localizer["Inherit From Site"]></option>
|
<option value="-"><@Localizer["Inherit From Site"]></option>
|
||||||
@foreach (var theme in _themes)
|
@foreach (var theme in _themes)
|
||||||
{
|
{
|
||||||
if (theme.TypeName == _themetype)
|
<option value="@theme.TypeName">@theme.Name</option>
|
||||||
{
|
|
||||||
<option value="@theme.TypeName" selected>@theme.Name</option>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<option value="@theme.TypeName">@theme.Name</option>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -23,15 +23,11 @@
|
||||||
<Label For="Parent" HelpText="Select the parent for the page in the site hierarchy" ResourceKey="Parent">Parent: </Label>
|
<Label For="Parent" HelpText="Select the parent for the page in the site hierarchy" ResourceKey="Parent">Parent: </Label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<select id="Parent" class="form-control" @onchange="(e => ParentChanged(e))">
|
<select id="Parent" class="form-control" value="@_parentid" @onchange="(e => ParentChanged(e))">
|
||||||
<option value="-1"><@Localizer["Site Root"]></option>
|
<option value="-1"><@Localizer["Site Root"]></option>
|
||||||
@foreach (Page page in _pageList)
|
@foreach (Page page in _pageList)
|
||||||
{
|
{
|
||||||
if (page.PageId.ToString() == _parentid)
|
if (page.PageId != _pageId)
|
||||||
{
|
|
||||||
<option value="@(page.PageId)" selected>@(new string('-', page.Level * 2))@(page.Name)</option>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
<option value="@(page.PageId)">@(new string('-', page.Level * 2))@(page.Name)</option>
|
<option value="@(page.PageId)">@(new string('-', page.Level * 2))@(page.Name)</option>
|
||||||
}
|
}
|
||||||
|
@ -112,18 +108,11 @@
|
||||||
<Label For="Theme" HelpText="Select the theme for this page" ResourceKey="Theme">Theme: </Label>
|
<Label For="Theme" HelpText="Select the theme for this page" ResourceKey="Theme">Theme: </Label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<select id="Theme" class="form-control" @onchange="(e => ThemeChanged(e))">
|
<select id="Theme" class="form-control" value="@_themetype" @onchange="(e => ThemeChanged(e))">
|
||||||
<option value="-"><Inherit From Site></option>
|
<option value="-"><@Localizer["Inherit From Site"]></option>
|
||||||
@foreach (var theme in _themes)
|
@foreach (var theme in _themes)
|
||||||
{
|
{
|
||||||
if (theme.TypeName == _themetype)
|
<option value="@theme.TypeName">@theme.Name</option>
|
||||||
{
|
|
||||||
<option value="@theme.TypeName" selected>@theme.Name</option>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<option value="@theme.TypeName">@theme.Name</option>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.PageId.ToString())" ResourceKey="EditPage" /></td>
|
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.PageId.ToString())" ResourceKey="EditPage" /></td>
|
||||||
<td><ActionDialog Header="Delete Page" Message="@("Are You Sure You Wish To Delete The " + context.Name + " Page?")" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeletePage(context))" ResourceKey="DeletePage" /></td>
|
<td><ActionDialog Header="Delete Page" Message="@Localizer["Are You Sure You Wish To Delete The {0} Page?", context.Name]" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeletePage(context))" ResourceKey="DeletePage" /></td>
|
||||||
<td>@(new string('-', context.Level * 2))@(context.Name)</td>
|
<td>@(new string('-', context.Level * 2))@(context.Name)</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
|
|
|
@ -19,7 +19,7 @@ else
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ProfileId.ToString())" ResourceKey="EditProfile" /></td>
|
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ProfileId.ToString())" ResourceKey="EditProfile" /></td>
|
||||||
<td><ActionDialog Header="Delete Profile" Message="@("Are You Sure You Wish To Delete " + context.Name + "?")" Action="Delete" Class="btn btn-danger" OnClick="@(async () => await DeleteProfile(context.ProfileId))" ResourceKey="DeleteProfile" /></td>
|
<td><ActionDialog Header="Delete Profile" Message="@Localizer["Are You Sure You Wish To Delete {0}?", context.Name]" Action="Delete" Class="btn btn-danger" OnClick="@(async () => await DeleteProfile(context.ProfileId))" ResourceKey="DeleteProfile" /></td>
|
||||||
<td>@context.Name</td>
|
<td>@context.Name</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
|
@ -30,9 +30,9 @@ else
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
_profiles = await ProfileService.GetProfilesAsync(PageState.Site.SiteId);
|
await GetProfilesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DeleteProfile(int profileId)
|
private async Task DeleteProfile(int profileId)
|
||||||
|
@ -41,7 +41,12 @@ else
|
||||||
{
|
{
|
||||||
await ProfileService.DeleteProfileAsync(profileId);
|
await ProfileService.DeleteProfileAsync(profileId);
|
||||||
await logger.LogInformation("Profile Deleted {ProfileId}", profileId);
|
await logger.LogInformation("Profile Deleted {ProfileId}", profileId);
|
||||||
|
|
||||||
AddModuleMessage(Localizer["Profile Deleted"], MessageType.Success);
|
AddModuleMessage(Localizer["Profile Deleted"], MessageType.Success);
|
||||||
|
|
||||||
|
await GetProfilesAsync();
|
||||||
|
|
||||||
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -49,4 +54,9 @@ else
|
||||||
AddModuleMessage(Localizer["Error Deleting Profile"], MessageType.Error);
|
AddModuleMessage(Localizer["Error Deleting Profile"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task GetProfilesAsync()
|
||||||
|
{
|
||||||
|
_profiles = await ProfileService.GetProfilesAsync(PageState.Site.SiteId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
@if (_pages.Any())
|
@if (_pages.Any())
|
||||||
{
|
{
|
||||||
<div style="text-align:right;">
|
<div style="text-align:right;">
|
||||||
<ActionDialog Header="Delete All Pages" Message="@Localizer["Are You Sure You Wish To Permanently Delete All Pages?", "Delete All Pages"]" Action="Delete All Pages" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllPages())" ResourceKey="DeleteAllPages" />
|
<ActionDialog Header="Delete All Pages" Message="Are You Sure You Wish To Permanently Delete All Pages?" Action="Delete All Pages" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllPages())" ResourceKey="DeleteAllPages" />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@
|
||||||
@if (_modules.Any())
|
@if (_modules.Any())
|
||||||
{
|
{
|
||||||
<div style="text-align:right;">
|
<div style="text-align:right;">
|
||||||
<ActionDialog Header="Delete All Modules" Message="@Localizer["Are You Sure You Wish To Permanently Delete All Modules?", "Delete All Modules"]" Action="Delete All Modules" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllModules())" ResourceKey="DeleteAllModules" />
|
<ActionDialog Header="Delete All Modules" Message="Are You Sure You Wish To Permanently Delete All Modules?" Action="Delete All Modules" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllModules())" ResourceKey="DeleteAllModules" />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,146 +7,143 @@
|
||||||
@inject IThemeService ThemeService
|
@inject IThemeService ThemeService
|
||||||
@inject ISettingService SettingService
|
@inject ISettingService SettingService
|
||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
|
@inject INotificationService NotificationService
|
||||||
|
|
||||||
@if (_initialized)
|
@if (_initialized)
|
||||||
{
|
{
|
||||||
<table class="table table-borderless">
|
<table class="table table-borderless">
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<Label For="name" HelpText="Enter the site name" ResourceKey="Name">Name: </Label>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input id="name" class="form-control" @bind="@_name" />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<Label For="tenant" HelpText="Enter the tenant for the site" ResourceKey="Tenant">Tenant: </Label>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input id="tenant" class="form-control" @bind="@_tenant" readonly />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<Label For="alias" HelpText="Enter the alias for the server" ResourceKey="Aliases">Aliases: </Label>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<textarea id="alias" class="form-control" @bind="@_urls" rows="3"></textarea>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<Label For="logo" HelpText="Upload a logo for the site" ResourceKey="Logo">Logo: </Label>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<FileManager FileId="@_logofileid" Filter="@Constants.ImageFiles" @ref="_logofilemanager" />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<Label For="favicon" HelpText="Select Your default icon" ResourceKey="FavoriteIcon">Favicon: </Label>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<FileManager FileId="@_faviconfileid" Filter="ico" @ref="_faviconfilemanager" />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<Label For="defaultTheme" HelpText="Select the sites default theme" ResourceKey="DefaultTheme">Default Theme: </Label>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<select id="defaultTheme" class="form-control" @onchange="(e => ThemeChanged(e))">
|
|
||||||
<option value="-"><@Localizer["Select Theme"]></option>
|
|
||||||
@foreach (var theme in _themes)
|
|
||||||
{
|
|
||||||
if (theme.TypeName == _themetype)
|
|
||||||
{
|
|
||||||
<option value="@theme.TypeName" selected>@theme.Name</option>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<option value="@theme.TypeName">@theme.Name</option>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
@if (_layouts.Count > 0)
|
|
||||||
{
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<Label For="defaultLayout" HelpText="Select the sites default layout" ResourceKey="DefaultLayout">Default Layout: </Label>
|
<Label For="name" HelpText="Enter the site name" ResourceKey="Name">Name: </Label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<select id="defaultLayout" class="form-control" @bind="@_layouttype">
|
<input id="name" class="form-control" @bind="@_name" />
|
||||||
<option value="-"><@Localizer["Select Layout"]></option>
|
</td>
|
||||||
@foreach (var layout in _layouts)
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<Label For="tenant" HelpText="Enter the tenant for the site" ResourceKey="Tenant">Tenant: </Label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input id="tenant" class="form-control" @bind="@_tenant" readonly />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<Label For="alias" HelpText="Enter the alias for the server" ResourceKey="Aliases">Aliases: </Label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<textarea id="alias" class="form-control" @bind="@_urls" rows="3"></textarea>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<Label For="allowRegister" HelpText="Do you want the users to be able to register for an account on the site" ResourceKey="AllowRegistration">Allow User Registration? </Label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<select id="allowRegister" class="form-control" @bind="@_allowregistration">
|
||||||
|
<option value="True">@Localizer["Yes"]</option>
|
||||||
|
<option value="False">@Localizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<Label For="isDeleted" HelpText="Is this site deleted?" ResourceKey="IsDeleted">Is Deleted? </Label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<select id="isDeleted" class="form-control" @bind="@_isdeleted">
|
||||||
|
<option value="True">@Localizer["Yes"]</option>
|
||||||
|
<option value="False">@Localizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<Section Name="Appearance" Heading="Appearance" ResourceKey="Appearance">
|
||||||
|
<table class="table table-borderless">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<Label For="logo" HelpText="Specify a logo for the site" ResourceKey="Logo">Logo: </Label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<FileManager FileId="@_logofileid" Filter="@Constants.ImageFiles" @ref="_logofilemanager" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<Label For="favicon" HelpText="Specify a Favicon" ResourceKey="FavoriteIcon">Favicon: </Label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<FileManager FileId="@_faviconfileid" Filter="ico" @ref="_faviconfilemanager" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<Label For="defaultTheme" HelpText="Select the sites default theme" ResourceKey="DefaultTheme">Default Theme: </Label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<select id="defaultTheme" class="form-control" value="@_themetype" @onchange="(e => ThemeChanged(e))">
|
||||||
|
<option value="-"><@Localizer["Select Theme"]></option>
|
||||||
|
@foreach (var theme in _themes)
|
||||||
{
|
{
|
||||||
<option value="@(layout.TypeName)">@(layout.Name)</option>
|
<option value="@theme.TypeName">@theme.Name</option>
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
@if (_layouts.Count > 0)
|
||||||
<tr>
|
{
|
||||||
<td>
|
<tr>
|
||||||
<Label For="defaultContainer" HelpText="Select the default container for the site" ResourceKey="DefaultContainer">Default Container: </Label>
|
<td>
|
||||||
</td>
|
<Label For="defaultLayout" HelpText="Select the sites default layout" ResourceKey="DefaultLayout">Default Layout: </Label>
|
||||||
<td>
|
</td>
|
||||||
<select id="defaultContainer" class="form-control" @bind="@_containertype">
|
<td>
|
||||||
<option value="-"><@Localizer["Select Container"]></option>
|
<select id="defaultLayout" class="form-control" @bind="@_layouttype">
|
||||||
@foreach (var container in _containers)
|
<option value="-"><@Localizer["Select Layout"]></option>
|
||||||
{
|
@foreach (var layout in _layouts)
|
||||||
<option value="@container.TypeName">@container.Name</option>
|
{
|
||||||
}
|
<option value="@(layout.TypeName)">@(layout.Name)</option>
|
||||||
</select>
|
}
|
||||||
</td>
|
</select>
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>
|
}
|
||||||
<Label For="defaultAdminContainer" HelpText="Select the default admin container for the site" ResourceKey="DefaultAdminContainer">Default Admin Container: </Label>
|
<tr>
|
||||||
</td>
|
<td>
|
||||||
<td>
|
<Label For="defaultContainer" HelpText="Select the default container for the site" ResourceKey="DefaultContainer">Default Container: </Label>
|
||||||
<select id="defaultAdminContainer" class="form-control" @bind="@_admincontainertype">
|
</td>
|
||||||
<option value="-"><@Localizer["Select Container"]></option>
|
<td>
|
||||||
<option value=""><@Localizer["Default Admin Container"]></option>
|
<select id="defaultContainer" class="form-control" @bind="@_containertype">
|
||||||
@foreach (var container in _containers)
|
<option value="-"><@Localizer["Select Container"]></option>
|
||||||
{
|
@foreach (var container in _containers)
|
||||||
<option value="@container.TypeName">@container.Name</option>
|
{
|
||||||
}
|
<option value="@container.TypeName">@container.Name</option>
|
||||||
</select>
|
}
|
||||||
</td>
|
</select>
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>
|
<tr>
|
||||||
<Label For="allowRegister" HelpText="Do you want the users to be able to register for an account on the site" ResourceKey="AllowRegistration">Allow User Registration? </Label>
|
<td>
|
||||||
</td>
|
<Label For="defaultAdminContainer" HelpText="Select the default admin container for the site" ResourceKey="DefaultAdminContainer">Default Admin Container: </Label>
|
||||||
<td>
|
</td>
|
||||||
<select id="allowRegister" class="form-control" @bind="@_allowregistration">
|
<td>
|
||||||
<option value="True">@Localizer["Yes"]</option>
|
<select id="defaultAdminContainer" class="form-control" @bind="@_admincontainertype">
|
||||||
<option value="False">@Localizer["No"]</option>
|
<option value="-"><@Localizer["Select Container"]></option>
|
||||||
</select>
|
<option value=""><@Localizer["Default Admin Container"]></option>
|
||||||
</td>
|
@foreach (var container in _containers)
|
||||||
</tr>
|
{
|
||||||
<tr>
|
<option value="@container.TypeName">@container.Name</option>
|
||||||
<td>
|
}
|
||||||
<Label For="isDeleted" HelpText="Is this site deleted?" ResourceKey="IsDeleted">Is Deleted? </Label>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
</tr>
|
||||||
<select id="isDeleted" class="form-control" @bind="@_isdeleted">
|
</table>
|
||||||
<option value="True">@Localizer["Yes"]</option>
|
</Section>
|
||||||
<option value="False">@Localizer["No"]</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<Section Name="SMTP" Heading="SMTP Settings" ResourceKey="SMTPSettings">
|
<Section Name="SMTP" Heading="SMTP Settings" ResourceKey="SMTPSettings">
|
||||||
<table class="table table-borderless">
|
<table class="table table-borderless">
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
@Localizer["Please Note That SMTP Requires The Notification Job To Be Enabled In the Scheduled Jobs"]
|
<strong>@Localizer["Please Note That SMTP Requires The Notification Job To Be Enabled In Scheduled Jobs"]</strong>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -201,6 +198,8 @@
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="SendEmail">@Localizer["Test SMTP Configuration"]</button>
|
||||||
|
<br /><br />
|
||||||
</Section>
|
</Section>
|
||||||
<Section Name="PWA" Heading="Progressive Web Application Settings" ResourceKey="PWASettings">
|
<Section Name="PWA" Heading="Progressive Web Application Settings" ResourceKey="PWASettings">
|
||||||
<table class="table table-borderless">
|
<table class="table table-borderless">
|
||||||
|
@ -482,7 +481,6 @@
|
||||||
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
|
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
|
||||||
|
|
||||||
await logger.LogInformation("Site Settings Saved {Site}", site);
|
await logger.LogInformation("Site Settings Saved {Site}", site);
|
||||||
|
|
||||||
AddModuleMessage(Localizer["Site Settings Saved"], MessageType.Success);
|
AddModuleMessage(Localizer["Site Settings Saved"], MessageType.Success);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -502,4 +500,36 @@
|
||||||
AddModuleMessage(Localizer["Error Saving Site"], MessageType.Error);
|
AddModuleMessage(Localizer["Error Saving Site"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task SendEmail()
|
||||||
|
{
|
||||||
|
if (_smtphost != "" && _smtpport != "" && _smtpsender != "")
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||||
|
SettingService.SetSetting(settings, "SMTPHost", _smtphost);
|
||||||
|
SettingService.SetSetting(settings, "SMTPPort", _smtpport);
|
||||||
|
SettingService.SetSetting(settings, "SMTPSSL", _smtpssl);
|
||||||
|
SettingService.SetSetting(settings, "SMTPUsername", _smtpusername);
|
||||||
|
SettingService.SetSetting(settings, "SMTPPassword", _smtppassword);
|
||||||
|
SettingService.SetSetting(settings, "SMTPSender", _smtpsender);
|
||||||
|
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
||||||
|
await logger.LogInformation("Site SMTP Settings Saved");
|
||||||
|
|
||||||
|
await NotificationService.AddNotificationAsync(new Notification(PageState.Site.SiteId, PageState.User.DisplayName, PageState.User.Email, PageState.User.DisplayName, PageState.User.Email, PageState.Site.Name + " SMTP Configuration Test", "SMTP Server Is Configured Correctly."));
|
||||||
|
AddModuleMessage(Localizer["SMTP Settings Saved And A Message Has Been Sent To The Email Address Associated To Your User Account... Please Wait A Few Minutes For Delivery. If You Do Not Receive The Email Please Review The Notification Job In Scheduled Jobs For Any Log Details."], MessageType.Info);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Testing SMTP Configuration");
|
||||||
|
AddModuleMessage(Localizer["Error Testing SMTP Configuration"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["You Must Specify The SMTP Host, Port, And Sender"], MessageType.Warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,18 +31,11 @@
|
||||||
<Label For="defaultTheme" HelpText="Select the default theme for the website" ResourceKey="DefaultTheme">Default Theme: </Label>
|
<Label For="defaultTheme" HelpText="Select the default theme for the website" ResourceKey="DefaultTheme">Default Theme: </Label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<select id="defaultTheme" class="form-control" @onchange="(e => ThemeChanged(e))">
|
<select id="defaultTheme" class="form-control" value="@_themetype" @onchange="(e => ThemeChanged(e))">
|
||||||
<option value="-"><@Localizer["Select Theme"]></option>
|
<option value="-"><@Localizer["Select Theme"]></option>
|
||||||
@foreach (var theme in _themes)
|
@foreach (var theme in _themes)
|
||||||
{
|
{
|
||||||
if (theme.TypeName == _themetype)
|
<option value="@theme.TypeName">@theme.Name</option>
|
||||||
{
|
|
||||||
<option value="@theme.TypeName" selected>@theme.Name</option>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<option value="@theme.TypeName">@theme.Name</option>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -22,7 +22,7 @@ else
|
||||||
<Row>
|
<Row>
|
||||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.AliasId.ToString())" ResourceKey="EditSite" /></td>
|
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.AliasId.ToString())" ResourceKey="EditSite" /></td>
|
||||||
<td><ActionDialog Header="Delete Site" Message="@Localizer["Are You Sure You Wish To Delete The {0} Site?", context.Name]" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteSite(context))" ResourceKey="DeleteSite" /></td>
|
<td><ActionDialog Header="Delete Site" Message="@Localizer["Are You Sure You Wish To Delete The {0} Site?", context.Name]" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteSite(context))" ResourceKey="DeleteSite" /></td>
|
||||||
<td><a href="@(_scheme + context.Name)">@context.Name</a></td>
|
<td><a href="@(_scheme + context.Name +"?reload")">@context.Name</a></td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
}
|
}
|
||||||
|
|
186
Oqtane.Client/Modules/Admin/ThemeCreator/Index.razor
Normal file
186
Oqtane.Client/Modules/Admin/ThemeCreator/Index.razor
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
@namespace Oqtane.Modules.Admin.ThemeCreator
|
||||||
|
@inherits ModuleBase
|
||||||
|
@inject NavigationManager NavigationManager
|
||||||
|
@inject IThemeService ThemeService
|
||||||
|
@inject IModuleService ModuleService
|
||||||
|
@inject IPageModuleService PageModuleService
|
||||||
|
@inject ISystemService SystemService
|
||||||
|
@inject ISettingService SettingService
|
||||||
|
@inject IStringLocalizer<Index> Localizer
|
||||||
|
@using System.Text.RegularExpressions
|
||||||
|
@using System.IO;
|
||||||
|
|
||||||
|
@if (string.IsNullOrEmpty(_themename) && _systeminfo != null && _templates != null)
|
||||||
|
{
|
||||||
|
<table class="table table-borderless">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<Label For="owner" HelpText="Enter the name of the organization who is developing this theme. It should not contain spaces or punctuation." ResourceKey="OwnerName">Owner Name: </Label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input id="owner" class="form-control" @bind="@_owner" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<Label For="module" HelpText="Enter a name for this theme. It should not contain spaces or punctuation." ResourceKey="ThemeName">Theme Name: </Label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input id="module" class="form-control" @bind="@_theme" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<Label For="template" HelpText="Select a theme template. Templates are located in the wwwroot/Themes/Templates folder on the server." ResourceKey="Template">Template: </Label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<select id="template" class="form-control" @onchange="(e => TemplateChanged(e))">
|
||||||
|
<option value="-"><@Localizer["Select Template"]></option>
|
||||||
|
@foreach (string template in _templates)
|
||||||
|
{
|
||||||
|
<option value="@template">@template</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<Label For="reference" HelpText="Select a framework reference version" ResourceKey="FrameworkReference">Framework Reference: </Label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<select id="reference" class="form-control" @bind="@_reference">
|
||||||
|
@foreach (string version in Constants.ReleaseVersions.Split(','))
|
||||||
|
{
|
||||||
|
if (Version.Parse(version).CompareTo(Version.Parse("2.0.0")) >= 0)
|
||||||
|
{
|
||||||
|
<option value="@(version)">@(version)</option>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<option value="local">@Localizer["Local Version"]</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@if (!string.IsNullOrEmpty(_location))
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<Label For="location" HelpText="Location where the theme will be created" ResourceKey="Location">Location: </Label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input id="module" class="form-control" @bind="@_location" readonly />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</table>
|
||||||
|
<button type="button" class="btn btn-success" @onclick="CreateTheme">@Localizer["Create Theme"]</button>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-success" @onclick="ActivateTheme">@Localizer["Activate Theme"]</button>
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private string _themename = string.Empty;
|
||||||
|
private string _owner = string.Empty;
|
||||||
|
private string _theme = string.Empty;
|
||||||
|
private string _template = "-";
|
||||||
|
private string _reference = Constants.Version;
|
||||||
|
private string _location = string.Empty;
|
||||||
|
|
||||||
|
private Dictionary<string, string> _systeminfo;
|
||||||
|
private List<string> _templates;
|
||||||
|
|
||||||
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_themename = SettingService.GetSetting(ModuleState.Settings, "ThemeName", "");
|
||||||
|
_systeminfo = await SystemService.GetSystemInfoAsync();
|
||||||
|
_templates = await ThemeService.GetThemeTemplatesAsync();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(_themename))
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Please Note That The Theme Creator Is Only Intended To Be Used In A Development Environment"], MessageType.Info);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Once You Have Compiled The Theme And Restarted The Application You Can Activate The Theme Below"], MessageType.Info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Loading Theme Creator");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CreateTheme()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (IsValid(_owner) && IsValid(_theme) && _owner != _theme && _template != "-")
|
||||||
|
{
|
||||||
|
var theme = new Theme { Owner = _owner, Name = _theme, Template = _template, Version = _reference };
|
||||||
|
theme = await ThemeService.CreateThemeAsync(theme);
|
||||||
|
|
||||||
|
var settings = ModuleState.Settings;
|
||||||
|
SettingService.SetSetting(settings, "ThemeName", theme.ThemeName);
|
||||||
|
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
|
||||||
|
|
||||||
|
GetLocation();
|
||||||
|
|
||||||
|
AddModuleMessage(Localizer["The Source Code For Your Theme Has Been Created At The Location Specified Below And Must Be Compiled In Order To Make It Functional. Once It Has Been Compiled You Must <a href=\"{0}\">Restart</a> Your Application To Apply These Changes.", NavigateUrl("admin/system")], MessageType.Success);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["You Must Provide A Valid Owner Name And Theme Name ( ie. No Punctuation Or Spaces And The Values Cannot Be The Same ) And Choose A Template"], MessageType.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Creating Theme");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ActivateTheme()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(_themename))
|
||||||
|
{
|
||||||
|
await PageModuleService.DeletePageModuleAsync(ModuleState.PageModuleId);
|
||||||
|
await ModuleService.DeleteModuleAsync(ModuleState.ModuleId);
|
||||||
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Activating Theme");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsValid(string name)
|
||||||
|
{
|
||||||
|
// must contain letters, underscores and digits and first character must be letter or underscore
|
||||||
|
return !string.IsNullOrEmpty(name) && Regex.IsMatch(name, "^[A-Za-z_][A-Za-z0-9_]*$");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TemplateChanged(ChangeEventArgs e)
|
||||||
|
{
|
||||||
|
_template = (string)e.Value;
|
||||||
|
GetLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetLocation()
|
||||||
|
{
|
||||||
|
_location = string.Empty;
|
||||||
|
if (_template != "-" && _systeminfo != null && _systeminfo.ContainsKey("serverpath"))
|
||||||
|
{
|
||||||
|
string[] path = _systeminfo["serverpath"].Split(Path.DirectorySeparatorChar);
|
||||||
|
_location = string.Join(Path.DirectorySeparatorChar, path, 0, path.Length - 2) +
|
||||||
|
Path.DirectorySeparatorChar + _owner + "." + _theme;
|
||||||
|
}
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
15
Oqtane.Client/Modules/Admin/ThemeCreator/ModuleInfo.cs
Normal file
15
Oqtane.Client/Modules/Admin/ThemeCreator/ModuleInfo.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
using Oqtane.Models;
|
||||||
|
|
||||||
|
namespace Oqtane.Modules.Admin.ThemeCreator
|
||||||
|
{
|
||||||
|
public class ModuleInfo : IModule
|
||||||
|
{
|
||||||
|
public ModuleDefinition ModuleDefinition => new ModuleDefinition
|
||||||
|
{
|
||||||
|
Name = "Theme Creator",
|
||||||
|
Description = "Enables software developers to quickly create themes by automating many of the initial theme creation tasks",
|
||||||
|
Version = "1.0.0",
|
||||||
|
Categories = "Developer"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,7 +24,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<Label For="version" HelpText="The version of the thene" ResourceKey="Version">Version: </Label>
|
<Label For="version" HelpText="The version of the theme" ResourceKey="Version">Version: </Label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<input id="version" class="form-control" @bind="@_version" disabled />
|
<input id="version" class="form-control" @bind="@_version" disabled />
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
{
|
{
|
||||||
var notification = new Notification(PageState.Site.SiteId, PageState.User, user, subject, body, null);
|
var notification = new Notification(PageState.Site.SiteId, PageState.User, user, subject, body, null);
|
||||||
notification = await NotificationService.AddNotificationAsync(notification);
|
notification = await NotificationService.AddNotificationAsync(notification);
|
||||||
await logger.LogInformation("Notification Created {Notification}", notification);
|
await logger.LogInformation("Notification Created {NotificationId}", notification.NotificationId);
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -183,7 +183,7 @@
|
||||||
{
|
{
|
||||||
var notification = new Notification(PageState.Site.SiteId, PageState.User, user, subject, body, notificationid);
|
var notification = new Notification(PageState.Site.SiteId, PageState.User, user, subject, body, notificationid);
|
||||||
notification = await NotificationService.AddNotificationAsync(notification);
|
notification = await NotificationService.AddNotificationAsync(notification);
|
||||||
await logger.LogInformation("Notification Created {Notification}", notification);
|
await logger.LogInformation("Notification Created {NotificationId}", notification.NotificationId);
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -85,7 +85,7 @@ else
|
||||||
var user = await UserService.GetUserAsync(UserRole.UserId, PageState.Site.SiteId);
|
var user = await UserService.GetUserAsync(UserRole.UserId, PageState.Site.SiteId);
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
await UserService.DeleteUserAsync(user.UserId);
|
await UserService.DeleteUserAsync(user.UserId, PageState.Site.SiteId);
|
||||||
await logger.LogInformation("User Deleted {User}", UserRole.User);
|
await logger.LogInformation("User Deleted {User}", UserRole.User);
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,21 +12,14 @@
|
||||||
@if (ShowFolders || FolderId <= 0)
|
@if (ShowFolders || FolderId <= 0)
|
||||||
{
|
{
|
||||||
<div>
|
<div>
|
||||||
<select class="form-control" @onchange="(e => FolderChanged(e))">
|
<select class="form-control" value="@FolderId" @onchange="(e => FolderChanged(e))">
|
||||||
@if (string.IsNullOrEmpty(Folder))
|
@if (string.IsNullOrEmpty(Folder))
|
||||||
{
|
{
|
||||||
<option value="-1"><@Localizer["Select Folder"]></option>
|
<option value="-1"><@Localizer["Select Folder"]></option>
|
||||||
}
|
}
|
||||||
@foreach (Folder folder in _folders)
|
@foreach (Folder folder in _folders)
|
||||||
{
|
{
|
||||||
if (folder.FolderId == FolderId)
|
<option value="@(folder.FolderId)">@(new string('-', folder.Level * 2))@(folder.Name)</option>
|
||||||
{
|
|
||||||
<option value="@(folder.FolderId)" selected>@(new string('-', folder.Level * 2))@(folder.Name)</option>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<option value="@(folder.FolderId)">@(new string('-', folder.Level * 2))@(folder.Name)</option>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
@ -34,18 +27,11 @@
|
||||||
@if (ShowFiles)
|
@if (ShowFiles)
|
||||||
{
|
{
|
||||||
<div>
|
<div>
|
||||||
<select class="form-control" @onchange="(e => FileChanged(e))">
|
<select class="form-control" value="@FileId" @onchange="(e => FileChanged(e))">
|
||||||
<option value="-1"><@Localizer["Select File"]></option>
|
<option value="-1"><@Localizer["Select File"]></option>
|
||||||
@foreach (File file in _files)
|
@foreach (File file in _files)
|
||||||
{
|
{
|
||||||
if (file.FileId == FileId)
|
<option value="@(file.FileId)">@(file.Name)</option>
|
||||||
{
|
|
||||||
<option value="@(file.FileId)" selected>@(file.Name)</option>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<option value="@(file.FileId)">@(file.Name)</option>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
@namespace Oqtane.Modules.Controls
|
@namespace Oqtane.Modules.Controls
|
||||||
@inherits ModuleControlBase
|
@inherits ModuleControlBase
|
||||||
@typeparam TableItem
|
@typeparam TableItem
|
||||||
|
|
||||||
|
@ -114,10 +114,10 @@
|
||||||
@code {
|
@code {
|
||||||
private int _pages = 0;
|
private int _pages = 0;
|
||||||
private int _page = 1;
|
private int _page = 1;
|
||||||
private int _maxItems;
|
private int _maxItems = 10;
|
||||||
private int _maxPages;
|
private int _maxPages = 5;
|
||||||
private int _startPage;
|
private int _startPage = 0;
|
||||||
private int _endPage;
|
private int _endPage = 0;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Format { get; set; }
|
public string Format { get; set; }
|
||||||
|
@ -172,24 +172,20 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(PageSize))
|
if (!string.IsNullOrEmpty(PageSize))
|
||||||
{
|
|
||||||
_maxItems = 10;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
_maxItems = int.Parse(PageSize);
|
_maxItems = int.Parse(PageSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(DisplayPages))
|
if (!string.IsNullOrEmpty(DisplayPages))
|
||||||
{
|
|
||||||
_maxPages = 5;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
_maxPages = int.Parse(DisplayPages);
|
_maxPages = int.Parse(DisplayPages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_page = 1;
|
||||||
|
_startPage = 0;
|
||||||
|
_endPage = 0;
|
||||||
|
|
||||||
if (Items != null)
|
if (Items != null)
|
||||||
{
|
{
|
||||||
ItemList = Items.Skip((_page - 1) * _maxItems).Take(_maxItems);
|
ItemList = Items.Skip((_page - 1) * _maxItems).Take(_maxItems);
|
||||||
|
|
0
Oqtane.Client/Resources/.gitkeep
Normal file
0
Oqtane.Client/Resources/.gitkeep
Normal file
|
@ -35,13 +35,7 @@ namespace Oqtane.Services
|
||||||
|
|
||||||
public async Task<Folder> GetFolderAsync(int siteId, [NotNull] string folderPath)
|
public async Task<Folder> GetFolderAsync(int siteId, [NotNull] string folderPath)
|
||||||
{
|
{
|
||||||
if (!(folderPath.EndsWith(System.IO.Path.DirectorySeparatorChar) || folderPath.EndsWith(System.IO.Path.AltDirectorySeparatorChar)))
|
|
||||||
{
|
|
||||||
folderPath = Utilities.PathCombine(folderPath, System.IO.Path.DirectorySeparatorChar.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
var path = WebUtility.UrlEncode(folderPath);
|
var path = WebUtility.UrlEncode(folderPath);
|
||||||
|
|
||||||
return await GetJsonAsync<Folder>($"{ApiUrl}/{siteId}/{path}");
|
return await GetJsonAsync<Folder>($"{ApiUrl}/{siteId}/{path}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,5 +13,6 @@ namespace Oqtane.Services
|
||||||
Task InstallModuleDefinitionsAsync();
|
Task InstallModuleDefinitionsAsync();
|
||||||
Task DeleteModuleDefinitionAsync(int moduleDefinitionId, int siteId);
|
Task DeleteModuleDefinitionAsync(int moduleDefinitionId, int siteId);
|
||||||
Task<ModuleDefinition> CreateModuleDefinitionAsync(ModuleDefinition moduleDefinition);
|
Task<ModuleDefinition> CreateModuleDefinitionAsync(ModuleDefinition moduleDefinition);
|
||||||
|
Task<List<string>> GetModuleDefinitionTemplatesAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
@ -12,5 +12,7 @@ namespace Oqtane.Services
|
||||||
List<ThemeControl> GetContainerControls(List<Theme> themes, string themeName);
|
List<ThemeControl> GetContainerControls(List<Theme> themes, string themeName);
|
||||||
Task InstallThemesAsync();
|
Task InstallThemesAsync();
|
||||||
Task DeleteThemeAsync(string themeName);
|
Task DeleteThemeAsync(string themeName);
|
||||||
|
Task<Theme> CreateThemeAsync(Theme theme);
|
||||||
|
Task<List<string>> GetThemeTemplatesAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Oqtane.Services
|
namespace Oqtane.Services
|
||||||
|
@ -13,7 +13,7 @@ namespace Oqtane.Services
|
||||||
|
|
||||||
Task<User> UpdateUserAsync(User user);
|
Task<User> UpdateUserAsync(User user);
|
||||||
|
|
||||||
Task DeleteUserAsync(int userId);
|
Task DeleteUserAsync(int userId, int siteId);
|
||||||
|
|
||||||
Task<User> LoginUserAsync(User user, bool setCookie, bool isPersistent);
|
Task<User> LoginUserAsync(User user, bool setCookie, bool isPersistent);
|
||||||
|
|
||||||
|
|
|
@ -53,5 +53,11 @@ namespace Oqtane.Services
|
||||||
{
|
{
|
||||||
return await PostJsonAsync($"{Apiurl}", moduleDefinition);
|
return await PostJsonAsync($"{Apiurl}", moduleDefinition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<List<string>> GetModuleDefinitionTemplatesAsync()
|
||||||
|
{
|
||||||
|
List<string> templates = await GetJsonAsync<List<string>>($"{Apiurl}/templates");
|
||||||
|
return templates;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -50,5 +50,16 @@ namespace Oqtane.Services
|
||||||
{
|
{
|
||||||
await DeleteAsync($"{ApiUrl}/{themeName}");
|
await DeleteAsync($"{ApiUrl}/{themeName}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<Theme> CreateThemeAsync(Theme theme)
|
||||||
|
{
|
||||||
|
return await PostJsonAsync($"{ApiUrl}", theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<string>> GetThemeTemplatesAsync()
|
||||||
|
{
|
||||||
|
List<string> templates = await GetJsonAsync<List<string>>($"{ApiUrl}/templates");
|
||||||
|
return templates;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -36,9 +36,9 @@ namespace Oqtane.Services
|
||||||
return await PutJsonAsync<User>($"{Apiurl}/{user.UserId}", user);
|
return await PutJsonAsync<User>($"{Apiurl}/{user.UserId}", user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteUserAsync(int userId)
|
public async Task DeleteUserAsync(int userId, int siteId)
|
||||||
{
|
{
|
||||||
await DeleteAsync($"{Apiurl}/{userId}");
|
await DeleteAsync($"{Apiurl}/{userId}?siteid={siteId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<User> LoginUserAsync(User user, bool setCookie, bool isPersistent)
|
public async Task<User> LoginUserAsync(User user, bool setCookie, bool isPersistent)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
@namespace Oqtane.Themes.BlazorTheme
|
@namespace Oqtane.Themes.BlazorTheme
|
||||||
@inherits ThemeBase
|
@inherits ThemeBase
|
||||||
|
|
||||||
<div class="breadcrumbs">
|
<div class="breadcrumbs">
|
||||||
|
@ -19,9 +19,6 @@
|
||||||
<div class="row px-4">
|
<div class="row px-4">
|
||||||
<Pane Name="Content" />
|
<Pane Name="Content" />
|
||||||
</div>
|
</div>
|
||||||
<div class="row px-4">
|
|
||||||
<Pane Name="Admin" />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -8,15 +8,15 @@
|
||||||
{
|
{
|
||||||
if (childPage.PageId == PageState.Page.PageId)
|
if (childPage.PageId == PageState.Page.PageId)
|
||||||
{
|
{
|
||||||
<a class="dropdown-item active" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
<a class="nav-link active px-3" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
||||||
<FontIcon Value="@childPage.Icon" />
|
<span class="@childPage.Icon" aria-hidden="true" />
|
||||||
@childPage.Name <span class="sr-only">(current)</span>
|
@childPage.Name <span class="sr-only">(current)</span>
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<a class="dropdown-item" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
<a class="nav-link px-3" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
||||||
<FontIcon Value="@childPage.Icon" />
|
<span class="@childPage.Icon" aria-hidden="true" />
|
||||||
@childPage.Name
|
@childPage.Name
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ else
|
||||||
{
|
{
|
||||||
<li class="nav-item active">
|
<li class="nav-item active">
|
||||||
<a class="nav-link" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
<a class="nav-link" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
||||||
<FontIcon Value="@childPage.Icon" />
|
<span class="@childPage.Icon" aria-hidden="true" />
|
||||||
@childPage.Name <span class="sr-only">(current)</span>
|
@childPage.Name <span class="sr-only">(current)</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -43,7 +43,7 @@ else
|
||||||
{
|
{
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
<a class="nav-link" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
||||||
<FontIcon Value="@childPage.Icon" />
|
<span class="@childPage.Icon" aria-hidden="true" />
|
||||||
@childPage.Name
|
@childPage.Name
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -55,7 +55,7 @@ else
|
||||||
{
|
{
|
||||||
<li class="nav-item dropdown active">
|
<li class="nav-item dropdown active">
|
||||||
<a class="nav-link dropdown-toggle" href="@GetUrl(childPage)" target="@GetTarget(childPage)" id="@($"navbarDropdown{childPage.PageId}")" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<a class="nav-link dropdown-toggle" href="@GetUrl(childPage)" target="@GetTarget(childPage)" id="@($"navbarDropdown{childPage.PageId}")" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
<FontIcon Value="@childPage.Icon" />
|
<span class="@childPage.Icon" aria-hidden="true" />
|
||||||
@childPage.Name <span class="sr-only">(current)</span>
|
@childPage.Name <span class="sr-only">(current)</span>
|
||||||
</a>
|
</a>
|
||||||
<MenuItemsHorizontal ParentPage="childPage" Pages="Pages" />
|
<MenuItemsHorizontal ParentPage="childPage" Pages="Pages" />
|
||||||
|
@ -65,7 +65,7 @@ else
|
||||||
{
|
{
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
<a class="nav-link dropdown-toggle" href="@GetUrl(childPage)" target="@GetTarget(childPage)" id="@($"navbarDropdown{childPage.PageId}")" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<a class="nav-link dropdown-toggle" href="@GetUrl(childPage)" target="@GetTarget(childPage)" id="@($"navbarDropdown{childPage.PageId}")" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
<FontIcon Value="@childPage.Icon" />
|
<span class="@childPage.Icon" aria-hidden="true" />
|
||||||
@childPage.Name
|
@childPage.Name
|
||||||
</a>
|
</a>
|
||||||
<MenuItemsHorizontal ParentPage="childPage" Pages="Pages" />
|
<MenuItemsHorizontal ParentPage="childPage" Pages="Pages" />
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
{
|
{
|
||||||
<li class="nav-item px-3" style="margin-left: @(childPage.Level * 15)px;">
|
<li class="nav-item px-3" style="margin-left: @(childPage.Level * 15)px;">
|
||||||
<a class="nav-link active" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
<a class="nav-link active" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
||||||
<FontIcon Value="@childPage.Icon" />
|
<span class="@childPage.Icon" aria-hidden="true" />
|
||||||
@childPage.Name <span class="sr-only">(current)</span>
|
@childPage.Name <span class="sr-only">(current)</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
{
|
{
|
||||||
<li class="nav-item px-3" style="margin-left: @(childPage.Level * 15)px;">
|
<li class="nav-item px-3" style="margin-left: @(childPage.Level * 15)px;">
|
||||||
<a class="nav-link" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
<a class="nav-link" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
||||||
<FontIcon Value="@childPage.Icon" />
|
<span class="@childPage.Icon" aria-hidden="true" />
|
||||||
@childPage.Name
|
@childPage.Name
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -38,7 +38,7 @@ else
|
||||||
{
|
{
|
||||||
<li class="nav-item px-3" style="margin-left: @(childPage.Level * 15)px;">
|
<li class="nav-item px-3" style="margin-left: @(childPage.Level * 15)px;">
|
||||||
<a class="nav-link active" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
<a class="nav-link active" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
||||||
<FontIcon Value="@childPage.Icon" />
|
<span class="@childPage.Icon" aria-hidden="true" />
|
||||||
@childPage.Name <span class="sr-only">(current)</span>
|
@childPage.Name <span class="sr-only">(current)</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -47,7 +47,7 @@ else
|
||||||
{
|
{
|
||||||
<li class="nav-item px-3" style="margin-left: @(childPage.Level * 15)px;">
|
<li class="nav-item px-3" style="margin-left: @(childPage.Level * 15)px;">
|
||||||
<a class="nav-link" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
<a class="nav-link" href="@GetUrl(childPage)" target="@GetTarget(childPage)">
|
||||||
<FontIcon Value="@childPage.Icon" />
|
<span class="@childPage.Icon" aria-hidden="true" />
|
||||||
@childPage.Name
|
@childPage.Name
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -2,33 +2,41 @@
|
||||||
@inherits ModuleActionsBase
|
@inherits ModuleActionsBase
|
||||||
@attribute [OqtaneIgnore]
|
@attribute [OqtaneIgnore]
|
||||||
|
|
||||||
@if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, ModuleState.Permissions))
|
@if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, ModuleState.Permissions) && PageState.Action == Constants.DefaultAction)
|
||||||
{
|
{
|
||||||
<div class="app-moduleactions">
|
<div class="app-moduleactions">
|
||||||
<a class="nav-link dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"></a>
|
<a class="nav-link dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"></a>
|
||||||
<div class="dropdown-menu" x-placement="bottom-start" style="position: absolute; will-change: transform; top: 0px; left: 0px; transform: translate3d(0px, 37px, 0px);">
|
<ul class="dropdown-menu" x-placement="bottom-start" style="position: absolute; will-change: transform; top: 0px; left: 0px; transform: translate3d(0px, 37px, 0px);">
|
||||||
@foreach (var action in Actions)
|
@foreach (var action in Actions.Where(item => !item.Name.Contains("Pane")))
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(action.Name))
|
if (string.IsNullOrEmpty(action.Name))
|
||||||
{
|
{
|
||||||
<div class="dropdown-divider"></div>
|
<li class="dropdown-divider"></li>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<a class="dropdown-item" @onclick="(async () => await ModuleAction(action))">
|
<li>
|
||||||
@if (string.IsNullOrEmpty(action.Icon))
|
<a class="dropdown-item" @onclick="(async () => await ModuleAction(action))">
|
||||||
{
|
<span class="@action.Icon" aria-hidden="true"></span> @action.Name
|
||||||
@((MarkupString) " ");
|
</a>
|
||||||
}
|
</li>
|
||||||
else
|
|
||||||
{
|
|
||||||
<span class="@action.Icon" aria-hidden="true"></span>
|
|
||||||
}
|
|
||||||
|
|
||||||
@action.Name
|
|
||||||
</a>
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</div>
|
<li class="dropdown-submenu">
|
||||||
|
<a class="dropdown-item" onclick="return subMenu(this)">
|
||||||
|
<span class="@Icons.AccountLogin" aria-hidden="true"></span> Move To >
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
@foreach (var action in Actions.Where(item => item.Name.Contains("Pane")))
|
||||||
|
{
|
||||||
|
<li>
|
||||||
|
<a class="dropdown-item" @onclick="(async () => await ModuleAction(action))">
|
||||||
|
<span class="@action.Icon" aria-hidden="true"></span> @action.Name
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -76,7 +76,7 @@ namespace Oqtane.Themes.Controls
|
||||||
{
|
{
|
||||||
if (pane != ModuleState.Pane)
|
if (pane != ModuleState.Pane)
|
||||||
{
|
{
|
||||||
actionList.Add(new ActionViewModel {Icon = Icons.AccountLogin, Name = "Move To " + pane + " Pane", Action = async (s, m) => await MoveToPane(s, pane, m)});
|
actionList.Add(new ActionViewModel {Icon = Icons.AccountLogin, Name = pane + " Pane", Action = async (s, m) => await MoveToPane(s, pane, m)});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
@namespace Oqtane.Themes.OqtaneTheme
|
||||||
|
@inherits ContainerBase
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<ModuleActions /><ModuleInstance />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
public override string Name => "No Background Color - No Title";
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
@namespace Oqtane.Themes.OqtaneTheme
|
||||||
|
@inherits ContainerBase
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row px-4">
|
||||||
|
<div class="d-flex flex-nowrap">
|
||||||
|
<ModuleActions /><h2><ModuleTitle /></h2>
|
||||||
|
</div>
|
||||||
|
<hr class="app-rule" />
|
||||||
|
</div>
|
||||||
|
<div class="row px-4">
|
||||||
|
<div class="container">
|
||||||
|
<ModuleInstance />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
public override string Name => "No Background Color - With Title";
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
@namespace Oqtane.Themes.OqtaneTheme
|
||||||
|
@inherits ContainerBase
|
||||||
|
|
||||||
|
<div class="container bg-primary">
|
||||||
|
<ModuleActions /><ModuleInstance />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
public override string Name => "Primary Background Color - No Title";
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
@namespace Oqtane.Themes.OqtaneTheme
|
||||||
|
@inherits ContainerBase
|
||||||
|
|
||||||
|
<div class="container bg-primary">
|
||||||
|
<div class="row px-4">
|
||||||
|
<div class="d-flex flex-nowrap">
|
||||||
|
<ModuleActions /><h2><ModuleTitle /></h2>
|
||||||
|
</div>
|
||||||
|
<hr class="app-rule" />
|
||||||
|
</div>
|
||||||
|
<div class="row px-4">
|
||||||
|
<div class="container">
|
||||||
|
<ModuleInstance />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
public override string Name => "Primary Background Color - With Title";
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
@namespace Oqtane.Themes.OqtaneTheme
|
||||||
|
@inherits ContainerBase
|
||||||
|
|
||||||
|
<div class="container bg-secondary">
|
||||||
|
<ModuleActions /><ModuleInstance />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
public override string Name => "Secondary Background Color - No Title";
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
@namespace Oqtane.Themes.OqtaneTheme
|
||||||
|
@inherits ContainerBase
|
||||||
|
|
||||||
|
<div class="container bg-secondary">
|
||||||
|
<div class="row px-4">
|
||||||
|
<div class="d-flex flex-nowrap">
|
||||||
|
<ModuleActions /><h2><ModuleTitle /></h2>
|
||||||
|
</div>
|
||||||
|
<hr class="app-rule" />
|
||||||
|
</div>
|
||||||
|
<div class="row px-4">
|
||||||
|
<div class="container">
|
||||||
|
<ModuleInstance />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
public override string Name => "Secondary Background Color - With Title";
|
||||||
|
}
|
90
Oqtane.Client/Themes/OqtaneTheme/Layouts/MultiPane.razor
Normal file
90
Oqtane.Client/Themes/OqtaneTheme/Layouts/MultiPane.razor
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
@namespace Oqtane.Themes.OqtaneTheme
|
||||||
|
@inherits LayoutBase
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<Pane Name="Content" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Pane Name="Top Full Width" />
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<Pane Name="Top 100%" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<Pane Name="Left 50%" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<Pane Name="Right 50%" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<Pane Name="Left 33%" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<Pane Name="Center 33%" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<Pane Name="Right 33%" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<Pane Name="Left Outer 25%" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<Pane Name="Left Inner 25%" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<Pane Name="Right Inner 25%" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<Pane Name="Right Outer 25%" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<Pane Name="Left 25%" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<Pane Name="Center 50%" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<Pane Name="Right 25%" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<Pane Name="Left Sidebar 66%" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<Pane Name="Right Sidebar 33%" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<Pane Name="Left Sidebar 33%" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-8">
|
||||||
|
<Pane Name="Right Sidebar 66%" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<Pane Name="Bottom 100%" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Pane Name="Bottom Full Width" />
|
||||||
|
|
||||||
|
@code {
|
||||||
|
public override string Name => "Multiple Panes";
|
||||||
|
|
||||||
|
public override string Panes => "Content, Top Full Width,Top 100%,Left 50%,Right 50%,Left 33%,Center 33%,Right 33%,Left Outer 25%,Left Inner 25%,Right Inner 25%,Right Outer 25%,Left 25%,Center 50%,Right 25%,Left Sidebar 66%,Right Sidebar 33%,Left Sidebar 33%,Right Sidebar 66%,Bottom 100%,Bottom Full Width";
|
||||||
|
}
|
16
Oqtane.Client/Themes/OqtaneTheme/Layouts/SinglePane.razor
Normal file
16
Oqtane.Client/Themes/OqtaneTheme/Layouts/SinglePane.razor
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
@namespace Oqtane.Themes.OqtaneTheme
|
||||||
|
@inherits LayoutBase
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<Pane Name="Content" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
public override string Name => "Single Pane";
|
||||||
|
|
||||||
|
public override string Panes => "Content";
|
||||||
|
}
|
|
@ -1,20 +0,0 @@
|
||||||
@namespace Oqtane.Themes.OqtaneTheme
|
|
||||||
@inherits LayoutBase
|
|
||||||
|
|
||||||
<div class="row px-4">
|
|
||||||
<Pane Name="Top" />
|
|
||||||
</div>
|
|
||||||
<div class="row px-4">
|
|
||||||
<div class="col-sm"><Pane Name="Left" /></div>
|
|
||||||
<div class="col-sm"><Pane Name="Content" /></div>
|
|
||||||
<div class="col-sm"><Pane Name="Right" /></div>
|
|
||||||
</div>
|
|
||||||
<div class="row px-4">
|
|
||||||
<Pane Name="Bottom" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@code {
|
|
||||||
public override string Name => "Multiple Panes";
|
|
||||||
|
|
||||||
public override string Panes => "Top,Left,Content,Right,Bottom";
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
@namespace Oqtane.Themes.OqtaneTheme
|
|
||||||
@inherits ContainerBase
|
|
||||||
<div class="container">
|
|
||||||
@if (PageState.EditMode)
|
|
||||||
{
|
|
||||||
<ModuleActions />
|
|
||||||
}
|
|
||||||
<ModuleInstance />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@code {
|
|
||||||
public override string Name => "No Header";
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
@namespace Oqtane.Themes.OqtaneTheme
|
|
||||||
@inherits LayoutBase
|
|
||||||
|
|
||||||
<div class="row px-4">
|
|
||||||
<Pane Name="Content" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@code {
|
|
||||||
public override string Name => "Single Pane";
|
|
||||||
|
|
||||||
public override string Panes => "Content";
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
@namespace Oqtane.Themes.OqtaneTheme
|
@namespace Oqtane.Themes.OqtaneTheme
|
||||||
@inherits ThemeBase
|
@inherits ThemeBase
|
||||||
|
|
||||||
<main role="main">
|
<main role="main">
|
||||||
|
@ -8,16 +8,11 @@
|
||||||
<div class="controls-group"><UserProfile /> <Login /> <ControlPanel /></div>
|
<div class="controls-group"><UserProfile /> <Login /> <ControlPanel /></div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="content container">
|
<PaneLayout />
|
||||||
<PaneLayout />
|
|
||||||
<div class="row px-4">
|
|
||||||
<Pane Name="Admin" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
public override string Name => "Default";
|
public override string Name => "Default Theme";
|
||||||
|
|
||||||
public override string Panes => string.Empty;
|
public override string Panes => string.Empty;
|
||||||
|
|
|
@ -1,11 +1,21 @@
|
||||||
@namespace Oqtane.UI
|
@namespace Oqtane.UI
|
||||||
|
|
||||||
<CascadingValue Value="@_moduleState" IsFixed="true">
|
<CascadingValue Value="@_moduleState" IsFixed="true">
|
||||||
@DynamicComponent
|
@if (_useadminborder)
|
||||||
|
{
|
||||||
|
<div class="app-pane-admin-border">
|
||||||
|
@DynamicComponent
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@DynamicComponent
|
||||||
|
}
|
||||||
</CascadingValue>
|
</CascadingValue>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private Module _moduleState;
|
private Module _moduleState;
|
||||||
|
private bool _useadminborder = false;
|
||||||
|
|
||||||
[CascadingParameter]
|
[CascadingParameter]
|
||||||
protected PageState PageState { get; set; }
|
protected PageState PageState { get; set; }
|
||||||
|
@ -24,6 +34,15 @@
|
||||||
container = (!string.IsNullOrEmpty(PageState.Site.AdminContainerType)) ? PageState.Site.AdminContainerType : Constants.DefaultAdminContainer;
|
container = (!string.IsNullOrEmpty(PageState.Site.AdminContainerType)) ? PageState.Site.AdminContainerType : Constants.DefaultAdminContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions) && PageState.Action == Constants.DefaultAction)
|
||||||
|
{
|
||||||
|
_useadminborder = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_useadminborder = false;
|
||||||
|
}
|
||||||
|
|
||||||
DynamicComponent = builder =>
|
DynamicComponent = builder =>
|
||||||
{
|
{
|
||||||
Type containerType = Type.GetType(container);
|
Type containerType = Type.GetType(container);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.JSInterop;
|
using Microsoft.JSInterop;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
@ -232,5 +233,19 @@ namespace Oqtane.UI
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ValueTask<bool> FormValid(ElementReference form)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return _jsRuntime.InvokeAsync<bool>(
|
||||||
|
"Oqtane.Interop.formValid",
|
||||||
|
form);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return new ValueTask<bool>(Task.FromResult(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
@if (_useadminborder)
|
@if (_useadminborder)
|
||||||
{
|
{
|
||||||
<div class="@_paneadminborder">
|
<div class="app-pane-admin-border">
|
||||||
@((MarkupString)_panetitle)
|
@((MarkupString)_panetitle)
|
||||||
@DynamicComponent
|
@DynamicComponent
|
||||||
</div>
|
</div>
|
||||||
|
@ -18,7 +18,6 @@ else
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private bool _useadminborder = false;
|
private bool _useadminborder = false;
|
||||||
private string _paneadminborder = "container";
|
|
||||||
private string _panetitle = "";
|
private string _panetitle = "";
|
||||||
|
|
||||||
[CascadingParameter]
|
[CascadingParameter]
|
||||||
|
@ -31,15 +30,14 @@ else
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions) && Name != PaneNames.Admin)
|
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions) && PageState.Action == Constants.DefaultAction)
|
||||||
{
|
{
|
||||||
_useadminborder = true;
|
_useadminborder = true;
|
||||||
_paneadminborder = "app-pane-admin-border";
|
|
||||||
_panetitle = "<div class=\"app-pane-admin-title\">" + Name + " Pane</div>";
|
_panetitle = "<div class=\"app-pane-admin-title\">" + Name + " Pane</div>";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_paneadminborder = "container";
|
_useadminborder = false;
|
||||||
_panetitle = "";
|
_panetitle = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,7 @@
|
||||||
var urlparameters = string.Empty;
|
var urlparameters = string.Empty;
|
||||||
var editmode = false;
|
var editmode = false;
|
||||||
var reload = Reload.None;
|
var reload = Reload.None;
|
||||||
var lastsyncdate = DateTime.UtcNow;
|
var lastsyncdate = DateTime.UtcNow.AddHours(-1);
|
||||||
var runtime = GetRuntime();
|
var runtime = GetRuntime();
|
||||||
|
|
||||||
Uri uri = new Uri(_absoluteUri);
|
Uri uri = new Uri(_absoluteUri);
|
||||||
|
@ -107,9 +107,14 @@
|
||||||
SiteState.Alias = alias; // set state for services
|
SiteState.Alias = alias; // set state for services
|
||||||
lastsyncdate = alias.SyncDate;
|
lastsyncdate = alias.SyncDate;
|
||||||
|
|
||||||
// process any sync events for site
|
// process any sync events
|
||||||
if (reload != Reload.Site && alias.SyncEvents.Any())
|
if (reload != Reload.Site && alias.SyncEvents.Any())
|
||||||
{
|
{
|
||||||
|
// if running on WebAssembly reload the client application if the server application was restarted
|
||||||
|
if (runtime == Shared.Runtime.WebAssembly && PageState != null && alias.SyncEvents.Exists(item => item.TenantId == -1))
|
||||||
|
{
|
||||||
|
NavigationManager.NavigateTo(_absoluteUri + (!_absoluteUri.Contains("?") ? "?" : "&") + "reload", true);
|
||||||
|
}
|
||||||
if (alias.SyncEvents.Exists(item => item.EntityName == EntityNames.Site && item.EntityId == alias.SiteId))
|
if (alias.SyncEvents.Exists(item => item.EntityName == EntityNames.Site && item.EntityId == alias.SiteId))
|
||||||
{
|
{
|
||||||
reload = Reload.Site;
|
reload = Reload.Site;
|
||||||
|
|
83
Oqtane.Client/wwwroot/Themes/Siliqon.TestTheme/Theme.css
Normal file
83
Oqtane.Client/wwwroot/Themes/Siliqon.TestTheme/Theme.css
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/* Oqtane Styles */
|
||||||
|
|
||||||
|
body {
|
||||||
|
padding-top: 7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
z-index: 2000;
|
||||||
|
padding-top: 15px;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-menu .nav-item {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-menu .nav-item a {
|
||||||
|
border-radius: 4px;
|
||||||
|
height: 3rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-menu .nav-item a.active {
|
||||||
|
background-color: rgba(255,255,255,0.25);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-menu .nav-item a:hover {
|
||||||
|
background-color: rgba(255,255,255,0.1);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-menu .nav-link .oi {
|
||||||
|
width: 1.5rem;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
vertical-align: text-top;
|
||||||
|
top: -2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-toggler {
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.app-moduleactions a.dropdown-toggle, div.app-moduleactions div.dropdown-menu {
|
||||||
|
color:#ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
|
||||||
|
.app-menu {
|
||||||
|
width: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar {
|
||||||
|
position: fixed;
|
||||||
|
top: 60px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
height: 60px;
|
||||||
|
top: 15px;
|
||||||
|
position: fixed;
|
||||||
|
top: 0px;
|
||||||
|
width: 100%;
|
||||||
|
background-color: rgb(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls-group {
|
||||||
|
float: right;
|
||||||
|
margin-right: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
position: relative;
|
||||||
|
top: 60px;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
@ -69,6 +69,10 @@ namespace Oqtane.Controllers
|
||||||
public Folder GetByPath(int siteId, string path)
|
public Folder GetByPath(int siteId, string path)
|
||||||
{
|
{
|
||||||
var folderPath = WebUtility.UrlDecode(path);
|
var folderPath = WebUtility.UrlDecode(path);
|
||||||
|
if (!(folderPath.EndsWith(System.IO.Path.DirectorySeparatorChar) || folderPath.EndsWith(System.IO.Path.AltDirectorySeparatorChar)))
|
||||||
|
{
|
||||||
|
folderPath = Utilities.PathCombine(folderPath, System.IO.Path.DirectorySeparatorChar.ToString());
|
||||||
|
}
|
||||||
Folder folder = _folders.GetFolder(siteId, folderPath);
|
Folder folder = _folders.GetFolder(siteId, folderPath);
|
||||||
if (folder != null)
|
if (folder != null)
|
||||||
if (_userPermissions.IsAuthorized(User, PermissionNames.Browse, folder.Permissions))
|
if (_userPermissions.IsAuthorized(User, PermissionNames.Browse, folder.Permissions))
|
||||||
|
|
|
@ -55,8 +55,7 @@ namespace Oqtane.Controllers
|
||||||
[HttpGet("installed")]
|
[HttpGet("installed")]
|
||||||
public Installation IsInstalled()
|
public Installation IsInstalled()
|
||||||
{
|
{
|
||||||
bool isInstalled = _databaseManager.IsInstalled();
|
return _databaseManager.IsInstalled();
|
||||||
return new Installation {Success = isInstalled, Message = string.Empty};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("upgrade")]
|
[HttpGet("upgrade")]
|
||||||
|
@ -130,7 +129,14 @@ namespace Oqtane.Controllers
|
||||||
var instance = Activator.CreateInstance(type) as IModule;
|
var instance = Activator.CreateInstance(type) as IModule;
|
||||||
foreach (string name in instance.ModuleDefinition.Dependencies.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
foreach (string name in instance.ModuleDefinition.Dependencies.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||||
{
|
{
|
||||||
if (!list.Contains(name)) list.Insert(0, name);
|
if (System.IO.File.Exists(Path.Combine(binFolder, name + ".dll")))
|
||||||
|
{
|
||||||
|
if (!list.Contains(name)) list.Insert(0, name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("Module " + instance.ModuleDefinition.ModuleDefinitionName + " dependency " + name + ".dll does not exist");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (var type in assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(ITheme))))
|
foreach (var type in assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(ITheme))))
|
||||||
|
@ -138,7 +144,14 @@ namespace Oqtane.Controllers
|
||||||
var instance = Activator.CreateInstance(type) as ITheme;
|
var instance = Activator.CreateInstance(type) as ITheme;
|
||||||
foreach (string name in instance.Theme.Dependencies.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
foreach (string name in instance.Theme.Dependencies.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||||
{
|
{
|
||||||
if (!list.Contains(name)) list.Insert(0, name);
|
if (System.IO.File.Exists(Path.Combine(binFolder, name + ".dll")))
|
||||||
|
{
|
||||||
|
if (!list.Contains(name)) list.Insert(0, name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("Theme " + instance.Theme.ThemeName + " dependency " + name + ".dll does not exist" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,6 @@ using Oqtane.Repository;
|
||||||
using Oqtane.Security;
|
using Oqtane.Security;
|
||||||
using System;
|
using System;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using System.Xml.Linq;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace Oqtane.Controllers
|
namespace Oqtane.Controllers
|
||||||
|
@ -174,7 +172,21 @@ namespace Oqtane.Controllers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST api/<controller>?moduleid=x
|
// GET: api/<controller>/templates
|
||||||
|
[HttpGet("templates")]
|
||||||
|
[Authorize(Roles = RoleNames.Host)]
|
||||||
|
public List<string> GetTemplates()
|
||||||
|
{
|
||||||
|
var templates = new List<string>();
|
||||||
|
string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Modules", "Templates", Path.DirectorySeparatorChar.ToString());
|
||||||
|
foreach (string directory in Directory.GetDirectories(templatePath))
|
||||||
|
{
|
||||||
|
templates.Add(directory.Replace(templatePath, ""));
|
||||||
|
}
|
||||||
|
return templates;
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST api/<controller>
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Authorize(Roles = RoleNames.Host)]
|
[Authorize(Roles = RoleNames.Host)]
|
||||||
public ModuleDefinition Post([FromBody] ModuleDefinition moduleDefinition)
|
public ModuleDefinition Post([FromBody] ModuleDefinition moduleDefinition)
|
||||||
|
@ -185,30 +197,12 @@ namespace Oqtane.Controllers
|
||||||
DirectoryInfo rootFolder = Directory.GetParent(_environment.ContentRootPath);
|
DirectoryInfo rootFolder = Directory.GetParent(_environment.ContentRootPath);
|
||||||
string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Modules", "Templates", moduleDefinition.Template,Path.DirectorySeparatorChar.ToString());
|
string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Modules", "Templates", moduleDefinition.Template,Path.DirectorySeparatorChar.ToString());
|
||||||
|
|
||||||
if (moduleDefinition.Template == "internal")
|
rootPath = Utilities.PathCombine(rootFolder.Parent.FullName , moduleDefinition.Owner + "." + moduleDefinition.Name,Path.DirectorySeparatorChar.ToString());
|
||||||
{
|
moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + ", " + moduleDefinition.Owner + "." + moduleDefinition.Name + ".Client.Oqtane";
|
||||||
rootPath = Utilities.PathCombine(rootFolder.FullName,Path.DirectorySeparatorChar.ToString());
|
moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + ".Manager." + moduleDefinition.Name + "Manager, " + moduleDefinition.Owner + "." + moduleDefinition.Name + ".Server.Oqtane";
|
||||||
moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + ", Oqtane.Client";
|
|
||||||
moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + ".Manager." + moduleDefinition.Name + "Manager, Oqtane.Server";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rootPath = Utilities.PathCombine(rootFolder.Parent.FullName , moduleDefinition.Owner + "." + moduleDefinition.Name,Path.DirectorySeparatorChar.ToString());
|
|
||||||
moduleDefinition.ModuleDefinitionName = moduleDefinition.Owner + "." + moduleDefinition.Name + ", " + moduleDefinition.Owner + "." + moduleDefinition.Name + ".Client.Oqtane";
|
|
||||||
moduleDefinition.ServerManagerType = moduleDefinition.Owner + "." + moduleDefinition.Name + ".Manager." + moduleDefinition.Name + "Manager, " + moduleDefinition.Owner + "." + moduleDefinition.Name + ".Server.Oqtane";
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessTemplatesRecursively(new DirectoryInfo(templatePath), rootPath, rootFolder.Name, templatePath, moduleDefinition);
|
ProcessTemplatesRecursively(new DirectoryInfo(templatePath), rootPath, rootFolder.Name, templatePath, moduleDefinition);
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Module Definition Created {ModuleDefinition}", moduleDefinition);
|
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Module Definition Created {ModuleDefinition}", moduleDefinition);
|
||||||
|
|
||||||
if (moduleDefinition.Template == "internal")
|
|
||||||
{
|
|
||||||
// add embedded resources to project file
|
|
||||||
List<string> resources = new List<string>();
|
|
||||||
resources.Add(Utilities.PathCombine("Modules", moduleDefinition.Owner + "." + moduleDefinition.Name, "Scripts", moduleDefinition.Owner + "." + moduleDefinition.Name + ".1.0.0.sql"));
|
|
||||||
resources.Add(Utilities.PathCombine("Modules", moduleDefinition.Owner + "." + moduleDefinition.Name, "Scripts", moduleDefinition.Owner + "." + moduleDefinition.Name + ".Uninstall.sql"));
|
|
||||||
EmbedResourceFiles(Utilities.PathCombine(rootPath, "Oqtane.Server", "Oqtane.Server.csproj"), resources);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return moduleDefinition;
|
return moduleDefinition;
|
||||||
|
@ -269,19 +263,5 @@ namespace Oqtane.Controllers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmbedResourceFiles(string projectfile, List<string> resources)
|
|
||||||
{
|
|
||||||
XDocument project = XDocument.Load(projectfile);
|
|
||||||
var itemGroup = project.Descendants("ItemGroup").Descendants("EmbeddedResource").FirstOrDefault().Parent;
|
|
||||||
if (itemGroup != null)
|
|
||||||
{
|
|
||||||
foreach (var resource in resources)
|
|
||||||
{
|
|
||||||
itemGroup.Add(new XElement("EmbeddedResource", new XAttribute("Include", resource)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
project.Save(projectfile);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Oqtane.Enums;
|
using Oqtane.Enums;
|
||||||
|
@ -65,7 +65,7 @@ namespace Oqtane.Controllers
|
||||||
if (IsAuthorized(notification.FromUserId))
|
if (IsAuthorized(notification.FromUserId))
|
||||||
{
|
{
|
||||||
notification = _notifications.AddNotification(notification);
|
notification = _notifications.AddNotification(notification);
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Notification Added {Notification}", notification);
|
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Notification Added {NotificationId}", notification.NotificationId);
|
||||||
}
|
}
|
||||||
return notification;
|
return notification;
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ namespace Oqtane.Controllers
|
||||||
if (IsAuthorized(notification.FromUserId))
|
if (IsAuthorized(notification.FromUserId))
|
||||||
{
|
{
|
||||||
notification = _notifications.UpdateNotification(notification);
|
notification = _notifications.UpdateNotification(notification);
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Notification Updated {Folder}", notification);
|
_logger.Log(LogLevel.Information, this, LogFunction.Update, "Notification Updated {NotificationId}", notification.NotificationId);
|
||||||
}
|
}
|
||||||
return notification;
|
return notification;
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,5 +103,91 @@ namespace Oqtane.Controllers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GET: api/<controller>/templates
|
||||||
|
[HttpGet("templates")]
|
||||||
|
[Authorize(Roles = RoleNames.Host)]
|
||||||
|
public List<string> GetTemplates()
|
||||||
|
{
|
||||||
|
var templates = new List<string>();
|
||||||
|
string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Themes", "Templates", Path.DirectorySeparatorChar.ToString());
|
||||||
|
foreach (string directory in Directory.GetDirectories(templatePath))
|
||||||
|
{
|
||||||
|
templates.Add(directory.Replace(templatePath, ""));
|
||||||
|
}
|
||||||
|
return templates;
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST api/<controller>
|
||||||
|
[HttpPost]
|
||||||
|
[Authorize(Roles = RoleNames.Host)]
|
||||||
|
public Theme Post([FromBody] Theme theme)
|
||||||
|
{
|
||||||
|
if (ModelState.IsValid)
|
||||||
|
{
|
||||||
|
string rootPath;
|
||||||
|
DirectoryInfo rootFolder = Directory.GetParent(_environment.ContentRootPath);
|
||||||
|
string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Themes", "Templates", theme.Template, Path.DirectorySeparatorChar.ToString());
|
||||||
|
|
||||||
|
rootPath = Utilities.PathCombine(rootFolder.Parent.FullName, theme.Owner + "." + theme.Name, Path.DirectorySeparatorChar.ToString());
|
||||||
|
theme.ThemeName = theme.Owner + "." + theme.Name + ", " + theme.Owner + "." + theme.Name + ".Client.Oqtane";
|
||||||
|
|
||||||
|
ProcessTemplatesRecursively(new DirectoryInfo(templatePath), rootPath, rootFolder.Name, templatePath, theme);
|
||||||
|
_logger.Log(LogLevel.Information, this, LogFunction.Create, "Theme Created {Theme}", theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
return theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessTemplatesRecursively(DirectoryInfo current, string rootPath, string rootFolder, string templatePath, Theme theme)
|
||||||
|
{
|
||||||
|
// process folder
|
||||||
|
string folderPath = Utilities.PathCombine(rootPath, current.FullName.Replace(templatePath, ""));
|
||||||
|
folderPath = folderPath.Replace("[Owner]", theme.Owner);
|
||||||
|
folderPath = folderPath.Replace("[Theme]", theme.Name);
|
||||||
|
if (!Directory.Exists(folderPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(folderPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileInfo[] files = current.GetFiles("*.*");
|
||||||
|
if (files != null)
|
||||||
|
{
|
||||||
|
foreach (FileInfo file in files)
|
||||||
|
{
|
||||||
|
// process file
|
||||||
|
string filePath = Path.Combine(folderPath, file.Name);
|
||||||
|
filePath = filePath.Replace("[Owner]", theme.Owner);
|
||||||
|
filePath = filePath.Replace("[Theme]", theme.Name);
|
||||||
|
|
||||||
|
string text = System.IO.File.ReadAllText(file.FullName);
|
||||||
|
text = text.Replace("[Owner]", theme.Owner);
|
||||||
|
text = text.Replace("[Theme]", theme.Name);
|
||||||
|
text = text.Replace("[RootPath]", rootPath);
|
||||||
|
text = text.Replace("[RootFolder]", rootFolder);
|
||||||
|
text = text.Replace("[Folder]", folderPath);
|
||||||
|
text = text.Replace("[File]", Path.GetFileName(filePath));
|
||||||
|
if (theme.Version == "local")
|
||||||
|
{
|
||||||
|
text = text.Replace("[FrameworkVersion]", Constants.Version);
|
||||||
|
text = text.Replace("[ClientReference]", "<Reference Include=\"Oqtane.Client\"><HintPath>..\\..\\oqtane.framework\\Oqtane.Server\\bin\\Debug\\net5.0\\Oqtane.Client.dll</HintPath></Reference>");
|
||||||
|
text = text.Replace("[SharedReference]", "<Reference Include=\"Oqtane.Shared\"><HintPath>..\\..\\oqtane.framework\\Oqtane.Server\\bin\\Debug\\net5.0\\Oqtane.Shared.dll</HintPath></Reference>");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
text = text.Replace("[FrameworkVersion]", theme.Version);
|
||||||
|
text = text.Replace("[ClientReference]", "<PackageReference Include=\"Oqtane.Client\" Version=\"" + theme.Version + "\" />");
|
||||||
|
text = text.Replace("[SharedReference]", "<PackageReference Include=\"Oqtane.Shared\" Version=\"" + theme.Version + "\" />");
|
||||||
|
}
|
||||||
|
System.IO.File.WriteAllText(filePath, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectoryInfo[] folders = current.GetDirectories();
|
||||||
|
|
||||||
|
foreach (DirectoryInfo folder in folders.Reverse())
|
||||||
|
{
|
||||||
|
ProcessTemplatesRecursively(folder, rootPath, rootFolder, templatePath, theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,7 +111,6 @@ namespace Oqtane.Controllers
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO shoud be moved to another layer
|
|
||||||
private async Task<User> CreateUser(User user)
|
private async Task<User> CreateUser(User user)
|
||||||
{
|
{
|
||||||
User newUser = null;
|
User newUser = null;
|
||||||
|
@ -261,18 +260,50 @@ namespace Oqtane.Controllers
|
||||||
// DELETE api/<controller>/5?siteid=x
|
// DELETE api/<controller>/5?siteid=x
|
||||||
[HttpDelete("{id}")]
|
[HttpDelete("{id}")]
|
||||||
[Authorize(Roles = RoleNames.Admin)]
|
[Authorize(Roles = RoleNames.Admin)]
|
||||||
public async Task Delete(int id)
|
public async Task Delete(int id, string siteid)
|
||||||
{
|
{
|
||||||
IdentityUser identityuser = await _identityUserManager.FindByNameAsync(_users.GetUser(id).Username);
|
User user = _users.GetUser(id);
|
||||||
|
if (user != null)
|
||||||
if (identityuser != null)
|
|
||||||
{
|
{
|
||||||
var result = await _identityUserManager.DeleteAsync(identityuser);
|
// remove user roles for site
|
||||||
|
foreach (UserRole userrole in _userRoles.GetUserRoles(user.UserId, Int32.Parse(siteid)).ToList())
|
||||||
if (result != null)
|
|
||||||
{
|
{
|
||||||
_users.DeleteUser(id);
|
_userRoles.DeleteUserRole(userrole.UserRoleId);
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Deleted {UserId}", id);
|
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Role Deleted {UserRole}", userrole);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove user folder for site
|
||||||
|
var folder = _folders.GetFolder(Int32.Parse(siteid), Utilities.PathCombine("Users", user.UserId.ToString(), Path.DirectorySeparatorChar.ToString()));
|
||||||
|
if (folder != null)
|
||||||
|
{
|
||||||
|
if (Directory.Exists(_folders.GetFolderPath(folder)))
|
||||||
|
{
|
||||||
|
Directory.Delete(_folders.GetFolderPath(folder), true);
|
||||||
|
}
|
||||||
|
_folders.DeleteFolder(folder.FolderId);
|
||||||
|
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Folder Deleted {Folder}", folder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete user if they are not a member of any other sites
|
||||||
|
if (!_userRoles.GetUserRoles(user.UserId, -1).Any())
|
||||||
|
{
|
||||||
|
// get identity user
|
||||||
|
IdentityUser identityuser = await _identityUserManager.FindByNameAsync(user.Username);
|
||||||
|
if (identityuser != null)
|
||||||
|
{
|
||||||
|
// delete identity user
|
||||||
|
var result = await _identityUserManager.DeleteAsync(identityuser);
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
// delete user
|
||||||
|
_users.DeleteUser(user.UserId);
|
||||||
|
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Deleted {UserId}", user.UserId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Delete, "Error Deleting User {UserId}", user.UserId, result.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,27 +37,30 @@ namespace Oqtane.Infrastructure
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsInstalled()
|
public Installation IsInstalled()
|
||||||
{
|
{
|
||||||
var defaultConnectionString = NormalizeConnectionString(_config.GetConnectionString(SettingKeys.ConnectionStringKey));
|
var result = new Installation { Success = false, Message = string.Empty };
|
||||||
var result = !string.IsNullOrEmpty(defaultConnectionString);
|
if (!string.IsNullOrEmpty(_config.GetConnectionString(SettingKeys.ConnectionStringKey)))
|
||||||
if (result)
|
|
||||||
{
|
{
|
||||||
|
result.Success = true;
|
||||||
using (var scope = _serviceScopeFactory.CreateScope())
|
using (var scope = _serviceScopeFactory.CreateScope())
|
||||||
{
|
{
|
||||||
var db = scope.ServiceProvider.GetRequiredService<MasterDBContext>();
|
var db = scope.ServiceProvider.GetRequiredService<MasterDBContext>();
|
||||||
result = db.Database.CanConnect();
|
if (db.Database.CanConnect())
|
||||||
if (result)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
result = db.Tenant.Any();
|
var provisioned = db.Tenant.Any();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
result = false;
|
result.Message = "Master Database Not Installed Correctly";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.Message = "Cannot Connect To Master Database";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -84,7 +87,8 @@ namespace Oqtane.Infrastructure
|
||||||
IsNewTenant = false
|
IsNewTenant = false
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!IsInstalled())
|
var installation = IsInstalled();
|
||||||
|
if (!installation.Success)
|
||||||
{
|
{
|
||||||
install.Aliases = GetInstallationConfig(SettingKeys.DefaultAliasKey, string.Empty);
|
install.Aliases = GetInstallationConfig(SettingKeys.DefaultAliasKey, string.Empty);
|
||||||
install.HostPassword = GetInstallationConfig(SettingKeys.HostPasswordKey, string.Empty);
|
install.HostPassword = GetInstallationConfig(SettingKeys.HostPasswordKey, string.Empty);
|
||||||
|
@ -107,6 +111,14 @@ namespace Oqtane.Infrastructure
|
||||||
install.ConnectionString = "";
|
install.ConnectionString = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(installation.Message))
|
||||||
|
{
|
||||||
|
// problem with prior installation
|
||||||
|
install.ConnectionString = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
|
|
||||||
namespace Oqtane.Infrastructure
|
namespace Oqtane.Infrastructure
|
||||||
{
|
{
|
||||||
public interface IDatabaseManager
|
public interface IDatabaseManager
|
||||||
{
|
{
|
||||||
bool IsInstalled();
|
Installation IsInstalled();
|
||||||
Installation Install();
|
Installation Install();
|
||||||
Installation Install(InstallConfig install);
|
Installation Install(InstallConfig install);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ namespace Oqtane.SiteTemplates
|
||||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||||
}.EncodePermissions() ,
|
}.EncodePermissions() ,
|
||||||
PageTemplateModules = new List<PageTemplateModule> {
|
PageTemplateModules = new List<PageTemplateModule> {
|
||||||
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Welcome To Oqtane...", Pane = "Content",
|
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Welcome To Oqtane...", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission> {
|
ModulePermissions = 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),
|
||||||
|
@ -70,7 +70,7 @@ namespace Oqtane.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 = "Content",
|
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Secure Content", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission> {
|
ModulePermissions = 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),
|
||||||
|
@ -94,7 +94,7 @@ namespace Oqtane.SiteTemplates
|
||||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||||
}.EncodePermissions(),
|
}.EncodePermissions(),
|
||||||
PageTemplateModules = new List<PageTemplateModule> {
|
PageTemplateModules = new List<PageTemplateModule> {
|
||||||
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Secure Content", Pane = "Content",
|
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Secure Content", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission> {
|
ModulePermissions = 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),
|
||||||
|
@ -118,7 +118,7 @@ namespace Oqtane.SiteTemplates
|
||||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||||
}.EncodePermissions(),
|
}.EncodePermissions(),
|
||||||
PageTemplateModules = new List<PageTemplateModule> {
|
PageTemplateModules = new List<PageTemplateModule> {
|
||||||
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "My Page", Pane = "Content",
|
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "My Page", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission> {
|
ModulePermissions = 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),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -17,7 +17,7 @@ namespace Oqtane.Infrastructure
|
||||||
|
|
||||||
public List<SyncEvent> GetSyncEvents(int tenantId, DateTime lastSyncDate)
|
public List<SyncEvent> GetSyncEvents(int tenantId, DateTime lastSyncDate)
|
||||||
{
|
{
|
||||||
return SyncEvents.Where(item => item.TenantId == tenantId && item.ModifiedOn >= lastSyncDate).ToList();
|
return SyncEvents.Where(item => (item.TenantId == tenantId || item.TenantId == -1) && item.ModifiedOn >= lastSyncDate).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddSyncEvent(int tenantId, string entityName, int entityId)
|
public void AddSyncEvent(int tenantId, string entityName, int entityId)
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Oqtane.Extensions;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using Oqtane.Repository;
|
using Oqtane.Repository;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Oqtane.Infrastructure
|
namespace Oqtane.Infrastructure
|
||||||
|
@ -12,80 +13,105 @@ namespace Oqtane.Infrastructure
|
||||||
{
|
{
|
||||||
private readonly IAliasRepository _aliases;
|
private readonly IAliasRepository _aliases;
|
||||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||||
|
private readonly IWebHostEnvironment _environment;
|
||||||
|
|
||||||
public UpgradeManager(IAliasRepository aliases, IServiceScopeFactory serviceScopeFactory)
|
public UpgradeManager(IAliasRepository aliases, IServiceScopeFactory serviceScopeFactory, IWebHostEnvironment environment)
|
||||||
{
|
{
|
||||||
_aliases = aliases;
|
_aliases = aliases;
|
||||||
_serviceScopeFactory = serviceScopeFactory;
|
_serviceScopeFactory = serviceScopeFactory;
|
||||||
|
_environment = environment;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Upgrade(Tenant tenant, string version)
|
public void Upgrade(Tenant tenant, string version)
|
||||||
{
|
{
|
||||||
// core framework upgrade logic - note that you can check if current tenant is Master if you only want to execute logic once
|
// core framework upgrade logic - executed for every tenant
|
||||||
var pageTemplates = new List<PageTemplate>();
|
using (var scope = _serviceScopeFactory.CreateScope())
|
||||||
|
|
||||||
switch (version)
|
|
||||||
{
|
{
|
||||||
case "0.9.0":
|
// set SiteState based on tenant
|
||||||
// add a page to all existing sites on upgrade
|
var siteState = scope.ServiceProvider.GetRequiredService<SiteState>();
|
||||||
|
siteState.Alias = new Alias { TenantId = tenant.TenantId };
|
||||||
|
|
||||||
//pageTemplates.Add(new PageTemplate
|
switch (version)
|
||||||
//{
|
{
|
||||||
// Name = "Test",
|
case "1.0.0":
|
||||||
// Parent = "",
|
Upgrade_1_0_0(tenant, scope);
|
||||||
// Path = "test",
|
break;
|
||||||
// Icon = Icons.Badge,
|
case "2.0.2":
|
||||||
// IsNavigation = true,
|
Upgrade_2_0_2(tenant, scope);
|
||||||
// IsPersonalizable = false,
|
break;
|
||||||
// EditMode = false,
|
}
|
||||||
// PagePermissions = new List<Permission>
|
|
||||||
// {
|
|
||||||
// new Permission(PermissionNames.View, RoleNames.Admin, true),
|
|
||||||
// new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
|
||||||
// new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
|
||||||
// }.EncodePermissions(),
|
|
||||||
// PageTemplateModules = new List<PageTemplateModule>
|
|
||||||
// {
|
|
||||||
// new PageTemplateModule
|
|
||||||
// {
|
|
||||||
// ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Login.Index).ToModuleDefinitionName(), Title = "Test", Pane = "Content",
|
|
||||||
// ModulePermissions = new List<Permission>
|
|
||||||
// {
|
|
||||||
// new Permission(PermissionNames.View, RoleNames.Admin, true),
|
|
||||||
// new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
|
||||||
// new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
|
||||||
// }.EncodePermissions(),
|
|
||||||
// Content = ""
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//});
|
|
||||||
CreateSitePages(tenant, pageTemplates);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateSitePages(Tenant tenant, List<PageTemplate> pageTemplates)
|
private void Upgrade_1_0_0(Tenant tenant, IServiceScope scope)
|
||||||
|
{
|
||||||
|
var pageTemplates = new List<PageTemplate>();
|
||||||
|
|
||||||
|
// **Note: this code is commented out on purpose - it provides an example of how to programmatically add a page to all existing sites on upgrade
|
||||||
|
|
||||||
|
//pageTemplates.Add(new PageTemplate
|
||||||
|
//{
|
||||||
|
// Name = "Test",
|
||||||
|
// Parent = "",
|
||||||
|
// Path = "test",
|
||||||
|
// Icon = Icons.Badge,
|
||||||
|
// IsNavigation = true,
|
||||||
|
// IsPersonalizable = false,
|
||||||
|
// EditMode = false,
|
||||||
|
// PagePermissions = new List<Permission>
|
||||||
|
// {
|
||||||
|
// new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
|
// new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||||
|
// new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||||
|
// }.EncodePermissions(),
|
||||||
|
// PageTemplateModules = new List<PageTemplateModule>
|
||||||
|
// {
|
||||||
|
// new PageTemplateModule
|
||||||
|
// {
|
||||||
|
// ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Login.Index).ToModuleDefinitionName(), Title = "Test", Pane = "Content",
|
||||||
|
// ModulePermissions = new List<Permission>
|
||||||
|
// {
|
||||||
|
// new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
|
// new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||||
|
// new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||||
|
// }.EncodePermissions(),
|
||||||
|
// Content = ""
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//});
|
||||||
|
|
||||||
|
CreateSitePages(scope, pageTemplates);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Upgrade_2_0_2(Tenant tenant, IServiceScope scope)
|
||||||
|
{
|
||||||
|
if (tenant.Name == TenantNames.Master)
|
||||||
|
{
|
||||||
|
// remove Internal module template files as they are no longer supported
|
||||||
|
var internalTemplatePath = Utilities.PathCombine(_environment.WebRootPath, "Modules", "Templates", "Internal", Path.DirectorySeparatorChar.ToString());
|
||||||
|
if (Directory.Exists(internalTemplatePath))
|
||||||
|
{
|
||||||
|
Directory.Delete(internalTemplatePath, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize SiteGuid
|
||||||
|
var sites = scope.ServiceProvider.GetRequiredService<ISiteRepository>();
|
||||||
|
foreach (Site site in sites.GetSites().ToList())
|
||||||
|
{
|
||||||
|
site.SiteGuid = System.Guid.NewGuid().ToString();
|
||||||
|
sites.UpdateSite(site);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateSitePages(IServiceScope scope, List<PageTemplate> pageTemplates)
|
||||||
{
|
{
|
||||||
if (pageTemplates.Count != 0)
|
if (pageTemplates.Count != 0)
|
||||||
{
|
{
|
||||||
var processed = new List<Site>();
|
var sites = scope.ServiceProvider.GetRequiredService<ISiteRepository>();
|
||||||
foreach (Alias alias in _aliases.GetAliases().Where(item => item.TenantId == tenant.TenantId))
|
foreach (Site site in sites.GetSites().ToList())
|
||||||
{
|
{
|
||||||
if (!processed.Exists(item => item.SiteId == alias.SiteId))
|
sites.CreatePages(site, pageTemplates);
|
||||||
{
|
|
||||||
using (var scope = _serviceScopeFactory.CreateScope())
|
|
||||||
{
|
|
||||||
var siteState = scope.ServiceProvider.GetRequiredService<SiteState>();
|
|
||||||
siteState.Alias = alias;
|
|
||||||
var sites = scope.ServiceProvider.GetRequiredService<ISiteRepository>();
|
|
||||||
var site = sites.GetSite(alias.SiteId);
|
|
||||||
if (site != null)
|
|
||||||
{
|
|
||||||
sites.CreatePages(site, pageTemplates);
|
|
||||||
}
|
|
||||||
processed.Add(site);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
@page "/"
|
@page "/"
|
||||||
@namespace Oqtane.Pages
|
@namespace Oqtane.Pages
|
||||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
@using Microsoft.Extensions.Configuration
|
@using Microsoft.Extensions.Configuration
|
||||||
|
@ -15,6 +15,7 @@
|
||||||
<!-- stub the PWA manifest but defer the assignment of href -->
|
<!-- stub the PWA manifest but defer the assignment of href -->
|
||||||
<link id="app-manifest" rel="manifest" />
|
<link id="app-manifest" rel="manifest" />
|
||||||
<link rel="stylesheet" href="css/app.css" />
|
<link rel="stylesheet" href="css/app.css" />
|
||||||
|
<script src="js/app.js"></script>
|
||||||
<script src="js/loadjs.min.js"></script>
|
<script src="js/loadjs.min.js"></script>
|
||||||
@Html.Raw(@Model.HeadResources)
|
@Html.Raw(@Model.HeadResources)
|
||||||
</head>
|
</head>
|
||||||
|
@ -35,6 +36,13 @@
|
||||||
<a class="dismiss">🗙</a>
|
<a class="dismiss">🗙</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@if (Model.Message != "")
|
||||||
|
{
|
||||||
|
<div class="app-alert">
|
||||||
|
@Model.Message
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<script src="js/interop.js"></script>
|
<script src="js/interop.js"></script>
|
||||||
|
|
||||||
@if (Configuration.GetSection("Runtime").Value == "WebAssembly")
|
@if (Configuration.GetSection("Runtime").Value == "WebAssembly")
|
||||||
|
|
|
@ -39,6 +39,7 @@ namespace Oqtane.Pages
|
||||||
|
|
||||||
public string HeadResources = "";
|
public string HeadResources = "";
|
||||||
public string BodyResources = "";
|
public string BodyResources = "";
|
||||||
|
public string Message = "";
|
||||||
|
|
||||||
public void OnGet()
|
public void OnGet()
|
||||||
{
|
{
|
||||||
|
@ -54,20 +55,28 @@ namespace Oqtane.Pages
|
||||||
if (HttpContext.Request.Cookies[CookieRequestCultureProvider.DefaultCookieName] == null && !string.IsNullOrEmpty(_configuration.GetConnectionString("DefaultConnection")))
|
if (HttpContext.Request.Cookies[CookieRequestCultureProvider.DefaultCookieName] == null && !string.IsNullOrEmpty(_configuration.GetConnectionString("DefaultConnection")))
|
||||||
{
|
{
|
||||||
var uri = new Uri(Request.GetDisplayUrl());
|
var uri = new Uri(Request.GetDisplayUrl());
|
||||||
var alias = _aliases.GetAlias(uri.Authority + "/" + uri.LocalPath.Substring(1));
|
var hostname = uri.Authority + "/" + uri.LocalPath.Substring(1);
|
||||||
_state.Alias = alias;
|
var alias = _aliases.GetAlias(hostname);
|
||||||
|
if (alias != null)
|
||||||
// set default language for site if the culture is not supported
|
|
||||||
var languages = _languages.GetLanguages(alias.SiteId);
|
|
||||||
if (languages.Any() && languages.All(l => l.Code != CultureInfo.CurrentUICulture.Name))
|
|
||||||
{
|
{
|
||||||
var defaultLanguage = languages.Where(l => l.IsDefault).SingleOrDefault() ?? languages.First();
|
_state.Alias = alias;
|
||||||
|
|
||||||
SetLocalizationCookie(defaultLanguage.Code);
|
// set default language for site if the culture is not supported
|
||||||
|
var languages = _languages.GetLanguages(alias.SiteId);
|
||||||
|
if (languages.Any() && languages.All(l => l.Code != CultureInfo.CurrentUICulture.Name))
|
||||||
|
{
|
||||||
|
var defaultLanguage = languages.Where(l => l.IsDefault).SingleOrDefault() ?? languages.First();
|
||||||
|
|
||||||
|
SetLocalizationCookie(defaultLanguage.Code);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetLocalizationCookie(_localizationManager.GetDefaultCulture());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SetLocalizationCookie(_localizationManager.GetDefaultCulture());
|
Message = $"No Matching Alias For Host Name {hostname}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
|
|
||||||
namespace Oqtane.Repository
|
namespace Oqtane.Repository
|
||||||
|
|
|
@ -68,7 +68,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
new PageTemplateModule
|
new PageTemplateModule
|
||||||
{
|
{
|
||||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Login.Index).ToModuleDefinitionName(), Title = "User Login", Pane = "Content",
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Login.Index).ToModuleDefinitionName(), Title = "User Login", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission>
|
ModulePermissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
|
@ -97,7 +97,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
new PageTemplateModule
|
new PageTemplateModule
|
||||||
{
|
{
|
||||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Register.Index).ToModuleDefinitionName(), Title = "User Registration", Pane = "Content",
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Register.Index).ToModuleDefinitionName(), Title = "User Registration", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission>
|
ModulePermissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
|
@ -127,7 +127,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
new PageTemplateModule
|
new PageTemplateModule
|
||||||
{
|
{
|
||||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Reset.Index).ToModuleDefinitionName(), Title = "Password Reset", Pane = "Content",
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Reset.Index).ToModuleDefinitionName(), Title = "Password Reset", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission>
|
ModulePermissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
|
@ -156,7 +156,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
new PageTemplateModule
|
new PageTemplateModule
|
||||||
{
|
{
|
||||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.UserProfile.Index).ToModuleDefinitionName(), Title = "User Profile", Pane = "Content",
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.UserProfile.Index).ToModuleDefinitionName(), Title = "User Profile", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission>
|
ModulePermissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
|
@ -181,7 +181,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
new PageTemplateModule
|
new PageTemplateModule
|
||||||
{
|
{
|
||||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Dashboard.Index).ToModuleDefinitionName(), Title = "Admin Dashboard", Pane = "Content",
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Dashboard.Index).ToModuleDefinitionName(), Title = "Admin Dashboard", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission>
|
ModulePermissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
|
@ -208,7 +208,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
new PageTemplateModule
|
new PageTemplateModule
|
||||||
{
|
{
|
||||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Site.Index).ToModuleDefinitionName(), Title = "Site Settings", Pane = "Content",
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Site.Index).ToModuleDefinitionName(), Title = "Site Settings", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission>
|
ModulePermissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
|
@ -235,7 +235,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
new PageTemplateModule
|
new PageTemplateModule
|
||||||
{
|
{
|
||||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Pages.Index).ToModuleDefinitionName(), Title = "Page Management", Pane = "Content",
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Pages.Index).ToModuleDefinitionName(), Title = "Page Management", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission>
|
ModulePermissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
|
@ -262,7 +262,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
new PageTemplateModule
|
new PageTemplateModule
|
||||||
{
|
{
|
||||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Users.Index).ToModuleDefinitionName(), Title = "User Management", Pane = "Content",
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Users.Index).ToModuleDefinitionName(), Title = "User Management", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission>
|
ModulePermissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
|
@ -289,7 +289,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
new PageTemplateModule
|
new PageTemplateModule
|
||||||
{
|
{
|
||||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Profiles.Index).ToModuleDefinitionName(), Title = "Profile Management", Pane = "Content",
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Profiles.Index).ToModuleDefinitionName(), Title = "Profile Management", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission>
|
ModulePermissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
|
@ -316,7 +316,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
new PageTemplateModule
|
new PageTemplateModule
|
||||||
{
|
{
|
||||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Roles.Index).ToModuleDefinitionName(), Title = "Role Management", Pane = "Content",
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Roles.Index).ToModuleDefinitionName(), Title = "Role Management", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission>
|
ModulePermissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
|
@ -343,7 +343,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
new PageTemplateModule
|
new PageTemplateModule
|
||||||
{
|
{
|
||||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Files.Index).ToModuleDefinitionName(), Title = "File Management", Pane = "Content",
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Files.Index).ToModuleDefinitionName(), Title = "File Management", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission>
|
ModulePermissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
|
@ -370,7 +370,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
new PageTemplateModule
|
new PageTemplateModule
|
||||||
{
|
{
|
||||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.RecycleBin.Index).ToModuleDefinitionName(), Title = "Recycle Bin", Pane = "Content",
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.RecycleBin.Index).ToModuleDefinitionName(), Title = "Recycle Bin", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission>
|
ModulePermissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
|
@ -399,7 +399,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
new PageTemplateModule
|
new PageTemplateModule
|
||||||
{
|
{
|
||||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Logs.Index).ToModuleDefinitionName(), Title = "Event Log", Pane = "Content",
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Logs.Index).ToModuleDefinitionName(), Title = "Event Log", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission>
|
ModulePermissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||||
|
@ -421,7 +421,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
new PageTemplateModule
|
new PageTemplateModule
|
||||||
{
|
{
|
||||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Sites.Index).ToModuleDefinitionName(), Title = "Site Management", Pane = "Content",
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Sites.Index).ToModuleDefinitionName(), Title = "Site Management", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission>
|
ModulePermissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||||
|
@ -443,7 +443,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
new PageTemplateModule
|
new PageTemplateModule
|
||||||
{
|
{
|
||||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.ModuleDefinitions.Index).ToModuleDefinitionName(), Title = "Module Management", Pane = "Content",
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.ModuleDefinitions.Index).ToModuleDefinitionName(), Title = "Module Management", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission>
|
ModulePermissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||||
|
@ -465,7 +465,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
new PageTemplateModule
|
new PageTemplateModule
|
||||||
{
|
{
|
||||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Themes.Index).ToModuleDefinitionName(), Title = "Theme Management", Pane = "Content",
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Themes.Index).ToModuleDefinitionName(), Title = "Theme Management", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission>
|
ModulePermissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||||
|
@ -494,7 +494,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
new PageTemplateModule
|
new PageTemplateModule
|
||||||
{
|
{
|
||||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Languages.Index).ToModuleDefinitionName(), Title = "Language Management", Pane = "Content",
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Languages.Index).ToModuleDefinitionName(), Title = "Language Management", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission>
|
ModulePermissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||||
|
@ -518,7 +518,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
new PageTemplateModule
|
new PageTemplateModule
|
||||||
{
|
{
|
||||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Jobs.Index).ToModuleDefinitionName(), Title = "Scheduled Jobs", Pane = "Content",
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Jobs.Index).ToModuleDefinitionName(), Title = "Scheduled Jobs", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission>
|
ModulePermissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||||
|
@ -540,7 +540,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
new PageTemplateModule
|
new PageTemplateModule
|
||||||
{
|
{
|
||||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Sql.Index).ToModuleDefinitionName(), Title = "Sql Management", Pane = "Content",
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Sql.Index).ToModuleDefinitionName(), Title = "Sql Management", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission>
|
ModulePermissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||||
|
@ -562,7 +562,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
new PageTemplateModule
|
new PageTemplateModule
|
||||||
{
|
{
|
||||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.SystemInfo.Index).ToModuleDefinitionName(), Title = "System Info", Pane = "Content",
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.SystemInfo.Index).ToModuleDefinitionName(), Title = "System Info", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission>
|
ModulePermissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||||
|
@ -584,7 +584,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
new PageTemplateModule
|
new PageTemplateModule
|
||||||
{
|
{
|
||||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Upgrade.Index).ToModuleDefinitionName(), Title = "System Update", Pane = "Content",
|
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Upgrade.Index).ToModuleDefinitionName(), Title = "System Update", Pane = PaneNames.Admin,
|
||||||
ModulePermissions = new List<Permission>
|
ModulePermissions = new List<Permission>
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||||
|
@ -605,7 +605,7 @@ namespace Oqtane.Repository
|
||||||
|
|
||||||
public Site AddSite(Site site)
|
public Site AddSite(Site site)
|
||||||
{
|
{
|
||||||
|
site.SiteGuid = System.Guid.NewGuid().ToString();
|
||||||
_db.Site.Add(site);
|
_db.Site.Add(site);
|
||||||
_db.SaveChanges();
|
_db.SaveChanges();
|
||||||
CreateSite(site);
|
CreateSite(site);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
|
@ -27,7 +27,7 @@ namespace Oqtane.Repository
|
||||||
return _db.UserRole.Where(item => item.UserId == userId)
|
return _db.UserRole.Where(item => item.UserId == userId)
|
||||||
.Include(item => item.Role) // eager load roles
|
.Include(item => item.Role) // eager load roles
|
||||||
.Include(item => item.User) // eager load users
|
.Include(item => item.User) // eager load users
|
||||||
.Where(item => item.Role.SiteId == siteId || item.Role.SiteId == null);
|
.Where(item => item.Role.SiteId == siteId || item.Role.SiteId == null || siteId == -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserRole AddUserRole(UserRole userRole)
|
public UserRole AddUserRole(UserRole userRole)
|
||||||
|
|
10
Oqtane.Server/Scripts/Tenant.02.00.02.01.sql
Normal file
10
Oqtane.Server/Scripts/Tenant.02.00.02.01.sql
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Version 2.0.2 Tenant migration script
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[Site] ADD
|
||||||
|
[SiteGuid] [char](36) NULL
|
||||||
|
GO
|
||||||
|
|
20
Oqtane.Server/Scripts/Tenant.02.00.02.02.sql
Normal file
20
Oqtane.Server/Scripts/Tenant.02.00.02.02.sql
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Version 2.0.2 Tenant migration script
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
UPDATE [dbo].[Site] SET DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client' WHERE DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client';
|
||||||
|
GO
|
||||||
|
UPDATE [dbo].[Site] SET DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client' WHERE DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.NoTitle, Oqtane.Client';
|
||||||
|
GO
|
||||||
|
|
||||||
|
UPDATE [dbo].[Page] SET DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client' WHERE DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client';
|
||||||
|
GO
|
||||||
|
UPDATE [dbo].[Page] SET DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client' WHERE DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.NoTitle, Oqtane.Client';
|
||||||
|
GO
|
||||||
|
|
||||||
|
UPDATE [dbo].[PageModule] SET ContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client' WHERE ContainerType = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client';
|
||||||
|
GO
|
||||||
|
UPDATE [dbo].[PageModule] SET ContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client' WHERE ContainerType = 'Oqtane.Themes.OqtaneTheme.NoTitle, Oqtane.Client';
|
||||||
|
GO
|
|
@ -227,7 +227,7 @@ namespace Oqtane
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISyncManager sync)
|
||||||
{
|
{
|
||||||
ServiceActivator.Configure(app.ApplicationServices);
|
ServiceActivator.Configure(app.ApplicationServices);
|
||||||
|
|
||||||
|
@ -265,6 +265,9 @@ namespace Oqtane
|
||||||
endpoints.MapControllers();
|
endpoints.MapControllers();
|
||||||
endpoints.MapFallbackToPage("/_Host");
|
endpoints.MapFallbackToPage("/_Host");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// create a sync event to identify server application startup
|
||||||
|
sync.AddSyncEvent(-1, "Application", -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,22 +74,29 @@
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (PageState.Action == "Add")
|
if (string.IsNullOrEmpty(_name))
|
||||||
{
|
{
|
||||||
[Module] [Module] = new [Module]();
|
if (PageState.Action == "Add")
|
||||||
[Module].ModuleId = ModuleState.ModuleId;
|
{
|
||||||
[Module].Name = _name;
|
[Module] [Module] = new [Module]();
|
||||||
[Module] = await [Module]Service.Add[Module]Async([Module]);
|
[Module].ModuleId = ModuleState.ModuleId;
|
||||||
await logger.LogInformation("[Module] Added {[Module]}", [Module]);
|
[Module].Name = _name;
|
||||||
|
[Module] = await [Module]Service.Add[Module]Async([Module]);
|
||||||
|
await logger.LogInformation("[Module] Added {[Module]}", [Module]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[Module] [Module] = await [Module]Service.Get[Module]Async(_id, ModuleState.ModuleId);
|
||||||
|
[Module].Name = _name;
|
||||||
|
await [Module]Service.Update[Module]Async([Module]);
|
||||||
|
await logger.LogInformation("[Module] Updated {[Module]}", [Module]);
|
||||||
|
}
|
||||||
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
[Module] [Module] = await [Module]Service.Get[Module]Async(_id, ModuleState.ModuleId);
|
AddModuleMessage("The Name Is Required", MessageType.Warning);
|
||||||
[Module].Name = _name;
|
|
||||||
await [Module]Service.Update[Module]Async([Module]);
|
|
||||||
await logger.LogInformation("[Module] Updated {[Module]}", [Module]);
|
|
||||||
}
|
}
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
|
@ -1,100 +0,0 @@
|
||||||
@using Oqtane.Modules.Controls
|
|
||||||
@using [Owner].[Module].Services
|
|
||||||
@using [Owner].[Module].Models
|
|
||||||
|
|
||||||
@namespace [Owner].[Module]
|
|
||||||
@inherits ModuleBase
|
|
||||||
@inject I[Module]Service [Module]Service
|
|
||||||
@inject NavigationManager NavigationManager
|
|
||||||
|
|
||||||
<table class="table table-borderless">
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<Label For="name" HelpText="Enter a name">Name: </Label>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input id="name" class="form-control" @bind="@_name" />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<button type="button" class="btn btn-success" @onclick="Save">Save</button>
|
|
||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">Cancel</NavLink>
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
@if (PageState.Action == "Edit")
|
|
||||||
{
|
|
||||||
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon"></AuditInfo>
|
|
||||||
}
|
|
||||||
|
|
||||||
@code {
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
|
||||||
|
|
||||||
public override string Actions => "Add,Edit";
|
|
||||||
|
|
||||||
public override string Title => "Manage [Module]";
|
|
||||||
|
|
||||||
public override List<Resource> Resources => new List<Resource>()
|
|
||||||
{
|
|
||||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" }
|
|
||||||
};
|
|
||||||
|
|
||||||
int _id;
|
|
||||||
string _name;
|
|
||||||
string _createdby;
|
|
||||||
DateTime _createdon;
|
|
||||||
string _modifiedby;
|
|
||||||
DateTime _modifiedon;
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (PageState.Action == "Edit")
|
|
||||||
{
|
|
||||||
_id = Int32.Parse(PageState.QueryString["id"]);
|
|
||||||
[Module] [Module] = await [Module]Service.Get[Module]Async(_id, ModuleState.ModuleId);
|
|
||||||
if ([Module] != null)
|
|
||||||
{
|
|
||||||
_name = [Module].Name;
|
|
||||||
_createdby = [Module].CreatedBy;
|
|
||||||
_createdon = [Module].CreatedOn;
|
|
||||||
_modifiedby = [Module].ModifiedBy;
|
|
||||||
_modifiedon = [Module].ModifiedOn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Loading [Module] {[Module]Id} {Error}", _id, ex.Message);
|
|
||||||
AddModuleMessage("Error Loading [Module]", MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task Save()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (PageState.Action == "Add")
|
|
||||||
{
|
|
||||||
[Module] [Module] = new [Module]();
|
|
||||||
[Module].ModuleId = ModuleState.ModuleId;
|
|
||||||
[Module].Name = _name;
|
|
||||||
[Module] = await [Module]Service.Add[Module]Async([Module]);
|
|
||||||
await logger.LogInformation("[Module] Added {[Module]}", [Module]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
[Module] [Module] = await [Module]Service.Get[Module]Async(_id, ModuleState.ModuleId);
|
|
||||||
[Module].Name = _name;
|
|
||||||
await [Module]Service.Update[Module]Async([Module]);
|
|
||||||
await logger.LogInformation("[Module] Updated {[Module]}", [Module]);
|
|
||||||
}
|
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Saving [Module] {Error}", ex.Message);
|
|
||||||
AddModuleMessage("Error Saving [Module]", MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,100 +0,0 @@
|
||||||
@using [Owner].[Module].Services
|
|
||||||
@using [Owner].[Module].Models
|
|
||||||
|
|
||||||
@namespace [Owner].[Module]
|
|
||||||
@inherits ModuleBase
|
|
||||||
@inject I[Module]Service [Module]Service
|
|
||||||
@inject NavigationManager NavigationManager
|
|
||||||
|
|
||||||
@if (_[Module]s == null)
|
|
||||||
{
|
|
||||||
<p><em>Loading...</em></p>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<ActionLink Action="Add" Security="SecurityAccessLevel.Edit" Text="Add [Module]" />
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
@if (@_[Module]s.Count != 0)
|
|
||||||
{
|
|
||||||
<Pager Items="@_[Module]s">
|
|
||||||
<Header>
|
|
||||||
<th style="width: 1px;"> </th>
|
|
||||||
<th style="width: 1px;"> </th>
|
|
||||||
<th>Name</th>
|
|
||||||
</Header>
|
|
||||||
<Row>
|
|
||||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.[Module]Id.ToString())" /></td>
|
|
||||||
<td><ActionDialog Header="Delete [Module]" Message="@("Are You Sure You Wish To Delete The " + context.Name + " [Module]?")" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await Delete(context))" /></td>
|
|
||||||
<td>@context.Name</td>
|
|
||||||
</Row>
|
|
||||||
</Pager>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<p>No [Module]s To Display</p>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
<!-- The content below is for informational purposes only and can be safely removed -->
|
|
||||||
|
|
||||||
<hr />
|
|
||||||
[Module] Module Created Successfully. Use Edit Mode To Add A [Module]. You Can Access The Files At The Following Locations:<br /><br />
|
|
||||||
[RootPath]Oqtane.Client\Modules\[Module]\<br />
|
|
||||||
- Edit.razor - component for adding or editing content<br />
|
|
||||||
- Index.razor - main component for your module **the content you are reading is in this file**<br />
|
|
||||||
- ModuleInfo.cs - implements IModule interface to provide configuration settings for your module<br />
|
|
||||||
- Settings.razor - component for managing module settings<br />
|
|
||||||
- Services\I[Module]Service.cs - interface for defining service API methods<br />
|
|
||||||
- Services\[Module]Service.cs - implements service API interface methods<br /><br />
|
|
||||||
[RootPath]Oqtane.Server\Modules\[Module]\<br />
|
|
||||||
- Controllers\[Module]Controller.cs - API methods implemented using a REST pattern<br />
|
|
||||||
- Manager\[Module]Manager.cs - implements optional module interfaces for features such as import/export of content<br />
|
|
||||||
- Repository\I[Module]Repository.cs - interface for defining repository methods<br />
|
|
||||||
- Repository\[Module]Respository.cs - implements repository interface methods for data access using EF Core<br />
|
|
||||||
- Repository\[Module]Context.cs - provides a DB Context for data access<br />
|
|
||||||
- Scripts\[Owner].[Module]s.1.0.0.sql - database schema definition script<br />
|
|
||||||
- Scripts\[Owner].[Module]s.Uninstall.sql - database uninstall script<br /><br />
|
|
||||||
[RootPath]Oqtane.Shared\Modules\[Module]\<br />
|
|
||||||
- Models\[Module].cs - model definition<br /><br />
|
|
||||||
|
|
||||||
<!-- The content above is for informational purposes only and can be safely removed -->
|
|
||||||
|
|
||||||
@code {
|
|
||||||
public override List<Resource> Resources => new List<Resource>()
|
|
||||||
{
|
|
||||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" },
|
|
||||||
new Resource { ResourceType = ResourceType.Script, Url = ModulePath() + "Module.js" }
|
|
||||||
};
|
|
||||||
|
|
||||||
List<[Module]> _[Module]s;
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_[Module]s = await [Module]Service.Get[Module]sAsync(ModuleState.ModuleId);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Loading [Module] {Error}", ex.Message);
|
|
||||||
AddModuleMessage("Error Loading [Module]", MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task Delete([Module] [Module])
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await [Module]Service.Delete[Module]Async([Module].[Module]Id, ModuleState.ModuleId);
|
|
||||||
await logger.LogInformation("[Module] Deleted {[Module]}", [Module]);
|
|
||||||
_[Module]s = await [Module]Service.Get[Module]sAsync(ModuleState.ModuleId);
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Deleting [Module] {[Module]} {Error}", [Module], ex.Message);
|
|
||||||
AddModuleMessage("Error Deleting [Module]", MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
using Microsoft.JSInterop;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace [Owner].[Module]
|
|
||||||
{
|
|
||||||
public class Interop
|
|
||||||
{
|
|
||||||
private readonly IJSRuntime _jsRuntime;
|
|
||||||
|
|
||||||
public Interop(IJSRuntime jsRuntime)
|
|
||||||
{
|
|
||||||
_jsRuntime = jsRuntime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
using Oqtane.Models;
|
|
||||||
using Oqtane.Modules;
|
|
||||||
|
|
||||||
namespace [Owner].[Module]
|
|
||||||
{
|
|
||||||
public class ModuleInfo : IModule
|
|
||||||
{
|
|
||||||
public ModuleDefinition ModuleDefinition => new ModuleDefinition
|
|
||||||
{
|
|
||||||
Name = "[Module]",
|
|
||||||
Description = "[Module]",
|
|
||||||
Version = "1.0.0",
|
|
||||||
ServerManagerType = "[ServerManagerType]",
|
|
||||||
ReleaseVersions = "1.0.0"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using [Owner].[Module].Models;
|
|
||||||
|
|
||||||
namespace [Owner].[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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Oqtane.Modules;
|
|
||||||
using Oqtane.Services;
|
|
||||||
using Oqtane.Shared;
|
|
||||||
using [Owner].[Module].Models;
|
|
||||||
|
|
||||||
namespace [Owner].[Module].Services
|
|
||||||
{
|
|
||||||
public class [Module]Service : ServiceBase, I[Module]Service, IService
|
|
||||||
{
|
|
||||||
private readonly SiteState _siteState;
|
|
||||||
|
|
||||||
public [Module]Service(HttpClient http, SiteState siteState) : base(http)
|
|
||||||
{
|
|
||||||
_siteState = siteState;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string Apiurl => CreateApiUrl(_siteState.Alias, "[Module]");
|
|
||||||
|
|
||||||
public async Task<List<Models.[Module]>> Get[Module]sAsync(int ModuleId)
|
|
||||||
{
|
|
||||||
List<Models.[Module]> [Module]s = await GetJsonAsync<List<Models.[Module]>>(CreateAuthorizationPolicyUrl($"{Apiurl}?moduleid={ModuleId}", ModuleId));
|
|
||||||
return [Module]s.OrderBy(item => item.Name).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Models.[Module]> Get[Module]Async(int [Module]Id, int ModuleId)
|
|
||||||
{
|
|
||||||
return await GetJsonAsync<Models.[Module]>(CreateAuthorizationPolicyUrl($"{Apiurl}/{[Module]Id}", ModuleId));
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Models.[Module]> Add[Module]Async(Models.[Module] [Module])
|
|
||||||
{
|
|
||||||
return await PostJsonAsync<Models.[Module]>(CreateAuthorizationPolicyUrl($"{Apiurl}", [Module].ModuleId), [Module]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Models.[Module]> Update[Module]Async(Models.[Module] [Module])
|
|
||||||
{
|
|
||||||
return await PutJsonAsync<Models.[Module]>(CreateAuthorizationPolicyUrl($"{Apiurl}/{[Module].[Module]Id}", [Module].ModuleId), [Module]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete[Module]Async(int [Module]Id, int ModuleId)
|
|
||||||
{
|
|
||||||
await DeleteAsync(CreateAuthorizationPolicyUrl($"{Apiurl}/{[Module]Id}", ModuleId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
@namespace [Owner].[Module]
|
|
||||||
@inherits ModuleBase
|
|
||||||
@inject ISettingService SettingService
|
|
||||||
|
|
||||||
<table class="table table-borderless">
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<Label For="value" HelpText="Enter a value">Name: </Label>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input id="value" type="text" class="form-control" @bind="@_value" />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
@code {
|
|
||||||
public override string Title => "[Module] Settings";
|
|
||||||
|
|
||||||
string _value;
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Dictionary<string, string> settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId);
|
|
||||||
_value = SettingService.GetSetting(settings, "SettingName", "");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task UpdateSettings()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Dictionary<string, string> settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId);
|
|
||||||
SettingService.SetSetting(settings, "SettingName", _value);
|
|
||||||
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,91 +0,0 @@
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Oqtane.Shared;
|
|
||||||
using Oqtane.Enums;
|
|
||||||
using Oqtane.Infrastructure;
|
|
||||||
using [Owner].[Module].Models;
|
|
||||||
using [Owner].[Module].Repository;
|
|
||||||
|
|
||||||
namespace [Owner].[Module].Controllers
|
|
||||||
{
|
|
||||||
[Route(ControllerRoutes.Default)]
|
|
||||||
public class [Module]Controller : Controller
|
|
||||||
{
|
|
||||||
private readonly I[Module]Repository _[Module]Repository;
|
|
||||||
private readonly ILogManager _logger;
|
|
||||||
protected int _entityId = -1;
|
|
||||||
|
|
||||||
public [Module]Controller(I[Module]Repository [Module]Repository, ILogManager logger, IHttpContextAccessor accessor)
|
|
||||||
{
|
|
||||||
_[Module]Repository = [Module]Repository;
|
|
||||||
_logger = logger;
|
|
||||||
|
|
||||||
if (accessor.HttpContext.Request.Query.ContainsKey("entityid"))
|
|
||||||
{
|
|
||||||
_entityId = int.Parse(accessor.HttpContext.Request.Query["entityid"]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GET: api/<controller>?moduleid=x
|
|
||||||
[HttpGet]
|
|
||||||
[Authorize(Policy = PolicyNames.ViewModule)]
|
|
||||||
public IEnumerable<Models.[Module]> Get(string moduleid)
|
|
||||||
{
|
|
||||||
return _[Module]Repository.Get[Module]s(int.Parse(moduleid));
|
|
||||||
}
|
|
||||||
|
|
||||||
// GET api/<controller>/5
|
|
||||||
[HttpGet("{id}")]
|
|
||||||
[Authorize(Policy = PolicyNames.ViewModule)]
|
|
||||||
public Models.[Module] Get(int id)
|
|
||||||
{
|
|
||||||
Models.[Module] [Module] = _[Module]Repository.Get[Module](id);
|
|
||||||
if ([Module] != null && [Module].ModuleId != _entityId)
|
|
||||||
{
|
|
||||||
[Module] = null;
|
|
||||||
}
|
|
||||||
return [Module];
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST api/<controller>
|
|
||||||
[HttpPost]
|
|
||||||
[Authorize(Policy = PolicyNames.EditModule)]
|
|
||||||
public Models.[Module] Post([FromBody] Models.[Module] [Module])
|
|
||||||
{
|
|
||||||
if (ModelState.IsValid && [Module].ModuleId == _entityId)
|
|
||||||
{
|
|
||||||
[Module] = _[Module]Repository.Add[Module]([Module]);
|
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "[Module] Added {[Module]}", [Module]);
|
|
||||||
}
|
|
||||||
return [Module];
|
|
||||||
}
|
|
||||||
|
|
||||||
// PUT api/<controller>/5
|
|
||||||
[HttpPut("{id}")]
|
|
||||||
[Authorize(Policy = PolicyNames.EditModule)]
|
|
||||||
public Models.[Module] Put(int id, [FromBody] Models.[Module] [Module])
|
|
||||||
{
|
|
||||||
if (ModelState.IsValid && [Module].ModuleId == _entityId)
|
|
||||||
{
|
|
||||||
[Module] = _[Module]Repository.Update[Module]([Module]);
|
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "[Module] Updated {[Module]}", [Module]);
|
|
||||||
}
|
|
||||||
return [Module];
|
|
||||||
}
|
|
||||||
|
|
||||||
// DELETE api/<controller>/5
|
|
||||||
[HttpDelete("{id}")]
|
|
||||||
[Authorize(Policy = PolicyNames.EditModule)]
|
|
||||||
public void Delete(int id)
|
|
||||||
{
|
|
||||||
Models.[Module] [Module] = _[Module]Repository.Get[Module](id);
|
|
||||||
if ([Module] != null && [Module].ModuleId == _entityId)
|
|
||||||
{
|
|
||||||
_[Module]Repository.Delete[Module](id);
|
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "[Module] Deleted {[Module]Id}", id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text.Json;
|
|
||||||
using Oqtane.Modules;
|
|
||||||
using Oqtane.Models;
|
|
||||||
using Oqtane.Infrastructure;
|
|
||||||
using Oqtane.Repository;
|
|
||||||
using [Owner].[Module].Models;
|
|
||||||
using [Owner].[Module].Repository;
|
|
||||||
|
|
||||||
namespace [Owner].[Module].Manager
|
|
||||||
{
|
|
||||||
public class [Module]Manager : IInstallable, IPortable
|
|
||||||
{
|
|
||||||
private I[Module]Repository _[Module]Repository;
|
|
||||||
private ISqlRepository _sql;
|
|
||||||
|
|
||||||
public [Module]Manager(I[Module]Repository [Module]Repository, ISqlRepository sql)
|
|
||||||
{
|
|
||||||
_[Module]Repository = [Module]Repository;
|
|
||||||
_sql = sql;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Install(Tenant tenant, string version)
|
|
||||||
{
|
|
||||||
return _sql.ExecuteScript(tenant, GetType().Assembly, "[Owner].[Module]." + version + ".sql");
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Uninstall(Tenant tenant)
|
|
||||||
{
|
|
||||||
return _sql.ExecuteScript(tenant, GetType().Assembly, "[Owner].[Module].Uninstall.sql");
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ExportModule(Module module)
|
|
||||||
{
|
|
||||||
string content = "";
|
|
||||||
List<Models.[Module]> [Module]s = _[Module]Repository.Get[Module]s(module.ModuleId).ToList();
|
|
||||||
if ([Module]s != null)
|
|
||||||
{
|
|
||||||
content = JsonSerializer.Serialize([Module]s);
|
|
||||||
}
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ImportModule(Module module, string content, string version)
|
|
||||||
{
|
|
||||||
List<Models.[Module]> [Module]s = null;
|
|
||||||
if (!string.IsNullOrEmpty(content))
|
|
||||||
{
|
|
||||||
[Module]s = JsonSerializer.Deserialize<List<Models.[Module]>>(content);
|
|
||||||
}
|
|
||||||
if ([Module]s != null)
|
|
||||||
{
|
|
||||||
foreach(var [Module] in [Module]s)
|
|
||||||
{
|
|
||||||
_[Module]Repository.Add[Module](new Models.[Module] { ModuleId = module.ModuleId, Name = [Module].Name });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using [Owner].[Module].Models;
|
|
||||||
|
|
||||||
namespace [Owner].[Module].Repository
|
|
||||||
{
|
|
||||||
public interface I[Module]Repository
|
|
||||||
{
|
|
||||||
IEnumerable<Models.[Module]> Get[Module]s(int ModuleId);
|
|
||||||
Models.[Module] Get[Module](int [Module]Id);
|
|
||||||
Models.[Module] Add[Module](Models.[Module] [Module]);
|
|
||||||
Models.[Module] Update[Module](Models.[Module] [Module]);
|
|
||||||
void Delete[Module](int [Module]Id);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Oqtane.Modules;
|
|
||||||
using Oqtane.Repository;
|
|
||||||
using [Owner].[Module].Models;
|
|
||||||
|
|
||||||
namespace [Owner].[Module].Repository
|
|
||||||
{
|
|
||||||
public class [Module]Context : DBContextBase, IService
|
|
||||||
{
|
|
||||||
public virtual DbSet<Models.[Module]> [Module] { get; set; }
|
|
||||||
|
|
||||||
public [Module]Context(ITenantResolver tenantResolver, IHttpContextAccessor accessor) : base(tenantResolver, accessor)
|
|
||||||
{
|
|
||||||
// ContextBase handles multi-tenant database connections
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Oqtane.Modules;
|
|
||||||
using [Owner].[Module].Models;
|
|
||||||
|
|
||||||
namespace [Owner].[Module].Repository
|
|
||||||
{
|
|
||||||
public class [Module]Repository : I[Module]Repository, IService
|
|
||||||
{
|
|
||||||
private readonly [Module]Context _db;
|
|
||||||
|
|
||||||
public [Module]Repository([Module]Context context)
|
|
||||||
{
|
|
||||||
_db = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<Models.[Module]> Get[Module]s(int ModuleId)
|
|
||||||
{
|
|
||||||
return _db.[Module].Where(item => item.ModuleId == ModuleId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Models.[Module] Get[Module](int [Module]Id)
|
|
||||||
{
|
|
||||||
return _db.[Module].Find([Module]Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Models.[Module] Add[Module](Models.[Module] [Module])
|
|
||||||
{
|
|
||||||
_db.[Module].Add([Module]);
|
|
||||||
_db.SaveChanges();
|
|
||||||
return [Module];
|
|
||||||
}
|
|
||||||
|
|
||||||
public Models.[Module] Update[Module](Models.[Module] [Module])
|
|
||||||
{
|
|
||||||
_db.Entry([Module]).State = EntityState.Modified;
|
|
||||||
_db.SaveChanges();
|
|
||||||
return [Module];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Delete[Module](int [Module]Id)
|
|
||||||
{
|
|
||||||
Models.[Module] [Module] = _db.[Module].Find([Module]Id);
|
|
||||||
_db.[Module].Remove([Module]);
|
|
||||||
_db.SaveChanges();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
/*
|
|
||||||
Create [Owner][Module] table
|
|
||||||
*/
|
|
||||||
|
|
||||||
CREATE TABLE [dbo].[[Owner][Module]](
|
|
||||||
[[Module]Id] [int] IDENTITY(1,1) NOT NULL,
|
|
||||||
[ModuleId] [int] NOT NULL,
|
|
||||||
[Name] [nvarchar](256) NOT NULL,
|
|
||||||
[CreatedBy] [nvarchar](256) NOT NULL,
|
|
||||||
[CreatedOn] [datetime] NOT NULL,
|
|
||||||
[ModifiedBy] [nvarchar](256) NOT NULL,
|
|
||||||
[ModifiedOn] [datetime] NOT NULL,
|
|
||||||
CONSTRAINT [PK_[Owner][Module]] PRIMARY KEY CLUSTERED
|
|
||||||
(
|
|
||||||
[[Module]Id] ASC
|
|
||||||
)
|
|
||||||
)
|
|
||||||
GO
|
|
||||||
|
|
||||||
/*
|
|
||||||
Create foreign key relationships
|
|
||||||
*/
|
|
||||||
ALTER TABLE [dbo].[[Owner][Module]] WITH CHECK ADD CONSTRAINT [FK_[Owner][Module]_Module] FOREIGN KEY([ModuleId])
|
|
||||||
REFERENCES [dbo].Module ([ModuleId])
|
|
||||||
ON DELETE CASCADE
|
|
||||||
GO
|
|
|
@ -1,6 +0,0 @@
|
||||||
/*
|
|
||||||
Remove [Owner][Module] table
|
|
||||||
*/
|
|
||||||
|
|
||||||
DROP TABLE [dbo].[[Owner][Module]]
|
|
||||||
GO
|
|
|
@ -1 +0,0 @@
|
||||||
/* Module Custom Styles */
|
|
|
@ -1,5 +0,0 @@
|
||||||
/* Module Script */
|
|
||||||
var [Owner] = [Owner] || {};
|
|
||||||
|
|
||||||
[Owner].[Module] = {
|
|
||||||
};
|
|
|
@ -1,19 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
using Oqtane.Models;
|
|
||||||
|
|
||||||
namespace [Owner].[Module].Models
|
|
||||||
{
|
|
||||||
[Table("[Owner][Module]")]
|
|
||||||
public class [Module] : IAuditable
|
|
||||||
{
|
|
||||||
public int [Module]Id { get; set; }
|
|
||||||
public int ModuleId { get; set; }
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
public string CreatedBy { get; set; }
|
|
||||||
public DateTime CreatedOn { get; set; }
|
|
||||||
public string ModifiedBy { get; set; }
|
|
||||||
public DateTime ModifiedOn { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
4
Oqtane.Server/wwwroot/Themes/Templates/External/Client/AssemblyInfo.cs
vendored
Normal file
4
Oqtane.Server/wwwroot/Themes/Templates/External/Client/AssemblyInfo.cs
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
using System.Resources;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
|
||||||
|
[assembly: RootNamespace("[Owner].[Theme].Client")]
|
|
@ -1,5 +1,6 @@
|
||||||
@namespace Oqtane.Themes.OqtaneTheme
|
@namespace [Owner].[Theme]
|
||||||
@inherits ContainerBase
|
@inherits ContainerBase
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row px-4">
|
<div class="row px-4">
|
||||||
<div class="d-flex flex-nowrap">
|
<div class="d-flex flex-nowrap">
|
||||||
|
@ -15,5 +16,5 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
public override string Name => "Standard Header";
|
public override string Name => "Container1";
|
||||||
}
|
}
|
15
Oqtane.Server/wwwroot/Themes/Templates/External/Client/ThemeInfo.cs
vendored
Normal file
15
Oqtane.Server/wwwroot/Themes/Templates/External/Client/ThemeInfo.cs
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
using Oqtane.Models;
|
||||||
|
using Oqtane.Themes;
|
||||||
|
|
||||||
|
namespace [Owner].[Theme]
|
||||||
|
{
|
||||||
|
public class ThemeInfo : ITheme
|
||||||
|
{
|
||||||
|
public Theme Theme => new Theme
|
||||||
|
{
|
||||||
|
Name = "[Theme]",
|
||||||
|
Version = "1.0.0"
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
107
Oqtane.Server/wwwroot/Themes/Templates/External/Client/Themes/Theme1.razor
vendored
Normal file
107
Oqtane.Server/wwwroot/Themes/Templates/External/Client/Themes/Theme1.razor
vendored
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
@namespace [Owner].[Theme]
|
||||||
|
@inherits ThemeBase
|
||||||
|
|
||||||
|
<main role="main">
|
||||||
|
<nav class="navbar navbar-expand-md navbar-dark bg-primary fixed-top">
|
||||||
|
<Logo /><Menu Orientation="Horizontal" />
|
||||||
|
<div class="controls ml-md-auto">
|
||||||
|
<div class="controls-group"><UserProfile /> <Login /> <ControlPanel /></div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<Pane Name="Content" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Pane Name="Top Full Width" />
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<Pane Name="Top 100%" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<Pane Name="Left 50%" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<Pane Name="Right 50%" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<Pane Name="Left 33%" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<Pane Name="Center 33%" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<Pane Name="Right 33%" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<Pane Name="Left Outer 25%" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<Pane Name="Left Inner 25%" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<Pane Name="Right Inner 25%" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<Pane Name="Right Outer 25%" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<Pane Name="Left 25%" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<Pane Name="Center 50%" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<Pane Name="Right 25%" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<Pane Name="Left Sidebar 66%" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<Pane Name="Right Sidebar 33%" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<Pane Name="Left Sidebar 33%" />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-8">
|
||||||
|
<Pane Name="Right Sidebar 66%" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<Pane Name="Bottom 100%" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Pane Name="Bottom Full Width" />
|
||||||
|
</main>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
public override string Name => "Theme1";
|
||||||
|
|
||||||
|
public override string Panes => "Content,Top Full Width,Top 100%,Left 50%,Right 50%,Left 33%,Center 33%,Right 33%,Left Outer 25%,Left Inner 25%,Right Inner 25%,Right Outer 25%,Left 25%,Center 50%,Right 25%,Left Sidebar 66%,Right Sidebar 33%,Left Sidebar 33%,Right Sidebar 66%,Bottom 100%,Bottom Full Width";
|
||||||
|
|
||||||
|
public override List<Resource> Resources => new List<Resource>()
|
||||||
|
{
|
||||||
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css", Integrity = "sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk", CrossOrigin = "anonymous" },
|
||||||
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = ThemePath() + "Theme.css" },
|
||||||
|
new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://code.jquery.com/jquery-3.5.1.slim.min.js", Integrity = "sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj", CrossOrigin = "anonymous" },
|
||||||
|
new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js", Integrity = "sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo", CrossOrigin = "anonymous" },
|
||||||
|
new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js", Integrity = "sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI", CrossOrigin = "anonymous" }
|
||||||
|
};
|
||||||
|
}
|
34
Oqtane.Server/wwwroot/Themes/Templates/External/Client/[Owner].[Theme].Client.csproj
vendored
Normal file
34
Oqtane.Server/wwwroot/Themes/Templates/External/Client/[Owner].[Theme].Client.csproj
vendored
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
|
<RazorLangVersion>3.0</RazorLangVersion>
|
||||||
|
<Version>1.0.0</Version>
|
||||||
|
<Authors>[Owner]</Authors>
|
||||||
|
<Company>[Owner]</Company>
|
||||||
|
<Description>[Description]</Description>
|
||||||
|
<Product>[Owner].[Theme]</Product>
|
||||||
|
<Copyright>[Owner]</Copyright>
|
||||||
|
<AssemblyName>[Owner].[Theme].Client.Oqtane</AssemblyName>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.0" PrivateAssets="all" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="5.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Localization" Version="5.0.0" />
|
||||||
|
<PackageReference Include="System.Net.Http.Json" Version="5.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
[ClientReference]
|
||||||
|
[SharedReference]
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<!-- there may be other elements here -->
|
||||||
|
<BlazorWebAssemblyEnableLinking>false</BlazorWebAssemblyEnableLinking>
|
||||||
|
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
21
Oqtane.Server/wwwroot/Themes/Templates/External/Client/_Imports.razor
vendored
Normal file
21
Oqtane.Server/wwwroot/Themes/Templates/External/Client/_Imports.razor
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
@using System
|
||||||
|
@using System.Linq
|
||||||
|
@using System.Collections.Generic
|
||||||
|
@using System.Net.Http
|
||||||
|
@using System.Net.Http.Json
|
||||||
|
|
||||||
|
@using Microsoft.AspNetCore.Components.Routing
|
||||||
|
@using Microsoft.AspNetCore.Components.Web
|
||||||
|
@using Microsoft.JSInterop
|
||||||
|
|
||||||
|
@using Oqtane.Models
|
||||||
|
@using Oqtane.Modules
|
||||||
|
@using Oqtane.Modules.Controls
|
||||||
|
@using Oqtane.Providers
|
||||||
|
@using Oqtane.Security
|
||||||
|
@using Oqtane.Services
|
||||||
|
@using Oqtane.Shared
|
||||||
|
@using Oqtane.Themes
|
||||||
|
@using Oqtane.Themes.Controls
|
||||||
|
@using Oqtane.UI
|
||||||
|
@using Oqtane.Enums
|
83
Oqtane.Server/wwwroot/Themes/Templates/External/Client/wwwroot/Themes/[Owner].[Theme]/Theme.css
vendored
Normal file
83
Oqtane.Server/wwwroot/Themes/Templates/External/Client/wwwroot/Themes/[Owner].[Theme]/Theme.css
vendored
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/* Oqtane Styles */
|
||||||
|
|
||||||
|
body {
|
||||||
|
padding-top: 7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
z-index: 2000;
|
||||||
|
padding-top: 15px;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-menu .nav-item {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-menu .nav-item a {
|
||||||
|
border-radius: 4px;
|
||||||
|
height: 3rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-menu .nav-item a.active {
|
||||||
|
background-color: rgba(255,255,255,0.25);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-menu .nav-item a:hover {
|
||||||
|
background-color: rgba(255,255,255,0.1);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-menu .nav-link .oi {
|
||||||
|
width: 1.5rem;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
vertical-align: text-top;
|
||||||
|
top: -2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-toggler {
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.app-moduleactions a.dropdown-toggle, div.app-moduleactions div.dropdown-menu {
|
||||||
|
color:#ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
|
||||||
|
.app-menu {
|
||||||
|
width: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar {
|
||||||
|
position: fixed;
|
||||||
|
top: 60px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
height: 60px;
|
||||||
|
top: 15px;
|
||||||
|
position: fixed;
|
||||||
|
top: 0px;
|
||||||
|
width: 100%;
|
||||||
|
background-color: rgb(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls-group {
|
||||||
|
float: right;
|
||||||
|
margin-right: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
position: relative;
|
||||||
|
top: 60px;
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user