Compare commits
130 Commits
Author | SHA1 | Date | |
---|---|---|---|
3d692e4198 | |||
215ca9f755 | |||
7dbcb24f3d | |||
18b4bd62f7 | |||
20f3cf5327 | |||
c1d35e8af5 | |||
e1cd318f61 | |||
4da0952091 | |||
a60f75f0a9 | |||
3814009ad9 | |||
fe7bb00112 | |||
2356753dfc | |||
bd23ec268b | |||
1d5f23c3c7 | |||
f424bf53b3 | |||
efbdf0006e | |||
625b173ee4 | |||
0a8d9bc3d3 | |||
0d0909a461 | |||
ebb0a538f8 | |||
337a566617 | |||
fecee7a12b | |||
282ec99ce8 | |||
17a4985ebe | |||
13b17d91a9 | |||
5782005007 | |||
258f2dbe8f | |||
e7b35bd0c2 | |||
176bd229e6 | |||
c12f1251b0 | |||
0710736661 | |||
51ebe520f4 | |||
1ef566c824 | |||
96cf06fe8d | |||
38ebfdcd0c | |||
b5649e2a6f | |||
5fc6dadeae | |||
22cfec9276 | |||
0a82ec5f0a | |||
3bdd1f6c4f | |||
1e466dc1fe | |||
3b302d2f86 | |||
7f108eebf9 | |||
9d41fee2fe | |||
bef686f95a | |||
4bdcb974bd | |||
af042bd23c | |||
19e3cef7dd | |||
085ab4bfb4 | |||
f7bd03d051 | |||
b48d751717 | |||
92a4a1b210 | |||
6a57fcc04a | |||
749e11762f | |||
61817726c3 | |||
808354e969 | |||
d2f594ff4a | |||
fa18467cdd | |||
4c940d02ef | |||
04202a6b70 | |||
4483901270 | |||
f02d894697 | |||
2bc130856a | |||
aa3a4dca65 | |||
4f65931f51 | |||
93be61e483 | |||
cb7fe364bc | |||
9cdcb4b22c | |||
c49072f9b6 | |||
61df26b667 | |||
25c935f1db | |||
6b982bc0c7 | |||
caccc803d3 | |||
5be640632b | |||
40912f0ffd | |||
d518860a34 | |||
185617ed9e | |||
5ba96b627e | |||
edf955f4cd | |||
8d0b04668e | |||
a72e5e02da | |||
4740404c2e | |||
34253916ea | |||
1d77ba2694 | |||
765041c587 | |||
8c6bca7666 | |||
c1b1cef590 | |||
507f7804c3 | |||
453bacf9bd | |||
25778458c6 | |||
7a42646bed | |||
755b7034d2 | |||
122fcfd701 | |||
2c905eddc2 | |||
3e8eb9abb5 | |||
d2df3b2d9a | |||
2a0c983c2e | |||
1319432fde | |||
02e2aeb6d1 | |||
5e35edd976 | |||
4d63c6266c | |||
48f8d41993 | |||
0b41ccad83 | |||
f994afbc11 | |||
5dea783677 | |||
347ef9a1d0 | |||
739aa5311c | |||
805018286c | |||
45f2a47ba5 | |||
fe503b7bee | |||
6736570ee7 | |||
88c06eea6e | |||
13693ef9e5 | |||
3a54326e73 | |||
941c1c8a45 | |||
d328058075 | |||
9108eb5616 | |||
ea45044dc7 | |||
6b16808207 | |||
4071b285ce | |||
7bc80f0814 | |||
6b57202421 | |||
ca3edb6687 | |||
7428f87899 | |||
02481560a9 | |||
2d66063763 | |||
9158e24295 | |||
118e177756 | |||
88ac82a013 | |||
c025013ca8 |
@ -66,6 +66,12 @@
|
|||||||
|
|
||||||
public override string Title => "File Management";
|
public override string Title => "File Management";
|
||||||
|
|
||||||
|
protected override void OnParametersSet()
|
||||||
|
{
|
||||||
|
base.OnParametersSet();
|
||||||
|
base.SetModuleTitle(Localizer["ModuleTitle.Text"]);
|
||||||
|
}
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -112,6 +112,11 @@
|
|||||||
|
|
||||||
public override string Title => "Folder Management";
|
public override string Title => "Folder Management";
|
||||||
|
|
||||||
|
protected override void OnParametersSet()
|
||||||
|
{
|
||||||
|
base.OnParametersSet();
|
||||||
|
base.SetModuleTitle(Localizer["ModuleTitle.Text"]);
|
||||||
|
}
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
<ActionLink Action="Log" Class="btn btn-secondary" Text="View Logs" ResourceKey="ViewJobs" />
|
<ActionLink Action="Log" Class="btn btn-secondary" Text="View Logs" ResourceKey="ViewJobs" />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="(async () => await Refresh())">Refresh</button>
|
<button type="button" class="btn btn-secondary" @onclick="(async () => await Refresh())">@Localizer["Refresh.Text"]</button>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
<TabStrip>
|
<TabStrip>
|
||||||
<TabPanel Name="Manage" ResourceKey="Manage">
|
<TabPanel Name="Manage" ResourceKey="Manage" Heading="Manage">
|
||||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -45,7 +45,7 @@ else
|
|||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
</form>
|
</form>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel Name="Upload" ResourceKey="Upload" Security="SecurityAccessLevel.Host">
|
<TabPanel Name="Upload" ResourceKey="Upload" Security="SecurityAccessLevel.Host" Heading="Upload">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" HelpText="Upload one or more translations. Once they are uploaded click Install." ResourceKey="LanguageUpload">Translation: </Label>
|
<Label Class="col-sm-3" HelpText="Upload one or more translations. Once they are uploaded click Install." ResourceKey="LanguageUpload">Translation: </Label>
|
||||||
|
@ -11,9 +11,6 @@
|
|||||||
<Authorizing>
|
<Authorizing>
|
||||||
<text>...</text>
|
<text>...</text>
|
||||||
</Authorizing>
|
</Authorizing>
|
||||||
<Authorized>
|
|
||||||
<div>@Localizer["Info.SignedIn"]</div>
|
|
||||||
</Authorized>
|
|
||||||
<NotAuthorized>
|
<NotAuthorized>
|
||||||
@if (!twofactor)
|
@if (!twofactor)
|
||||||
{
|
{
|
||||||
@ -69,259 +66,265 @@
|
|||||||
</AuthorizeView>
|
</AuthorizeView>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private bool _allowsitelogin = true;
|
private bool _allowsitelogin = true;
|
||||||
private bool _allowexternallogin = false;
|
private bool _allowexternallogin = false;
|
||||||
private ElementReference login;
|
private ElementReference login;
|
||||||
private bool validated = false;
|
private bool validated = false;
|
||||||
private bool twofactor = false;
|
private bool twofactor = false;
|
||||||
private string _username = string.Empty;
|
private string _username = string.Empty;
|
||||||
private ElementReference username;
|
private ElementReference username;
|
||||||
private string _password = string.Empty;
|
private string _password = string.Empty;
|
||||||
private string _passwordtype = "password";
|
private string _passwordtype = "password";
|
||||||
private string _togglepassword = string.Empty;
|
private string _togglepassword = string.Empty;
|
||||||
private bool _remember = false;
|
private bool _remember = false;
|
||||||
private string _code = string.Empty;
|
private string _code = string.Empty;
|
||||||
|
|
||||||
private string _returnUrl = string.Empty;
|
private string _returnUrl = string.Empty;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
||||||
|
|
||||||
public override List<Resource> Resources => new List<Resource>()
|
public override List<Resource> Resources => new List<Resource>()
|
||||||
{
|
{
|
||||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" }
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" }
|
||||||
};
|
};
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||||
|
|
||||||
if (PageState.Site.Settings.ContainsKey("LoginOptions:AllowSiteLogin") && !string.IsNullOrEmpty(PageState.Site.Settings["LoginOptions:AllowSiteLogin"]))
|
if (PageState.Site.Settings.ContainsKey("LoginOptions:AllowSiteLogin") && !string.IsNullOrEmpty(PageState.Site.Settings["LoginOptions:AllowSiteLogin"]))
|
||||||
{
|
{
|
||||||
_allowsitelogin = bool.Parse(PageState.Site.Settings["LoginOptions:AllowSiteLogin"]);
|
_allowsitelogin = bool.Parse(PageState.Site.Settings["LoginOptions:AllowSiteLogin"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PageState.Site.Settings.ContainsKey("ExternalLogin:ProviderType") && !string.IsNullOrEmpty(PageState.Site.Settings["ExternalLogin:ProviderType"]))
|
if (PageState.Site.Settings.ContainsKey("ExternalLogin:ProviderType") && !string.IsNullOrEmpty(PageState.Site.Settings["ExternalLogin:ProviderType"]))
|
||||||
{
|
{
|
||||||
_allowexternallogin = true;
|
_allowexternallogin = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PageState.QueryString.ContainsKey("returnurl"))
|
if (PageState.QueryString.ContainsKey("returnurl"))
|
||||||
{
|
{
|
||||||
_returnUrl = PageState.QueryString["returnurl"];
|
_returnUrl = PageState.QueryString["returnurl"];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PageState.QueryString.ContainsKey("name"))
|
if (PageState.QueryString.ContainsKey("name"))
|
||||||
{
|
{
|
||||||
_username = PageState.QueryString["name"];
|
_username = PageState.QueryString["name"];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PageState.QueryString.ContainsKey("token") && !string.IsNullOrEmpty(_username))
|
if (PageState.QueryString.ContainsKey("token") && !string.IsNullOrEmpty(_username))
|
||||||
{
|
{
|
||||||
var user = new User();
|
var user = new User();
|
||||||
user.SiteId = PageState.Site.SiteId;
|
user.SiteId = PageState.Site.SiteId;
|
||||||
user.Username = _username;
|
user.Username = _username;
|
||||||
|
|
||||||
if (PageState.QueryString.ContainsKey("key"))
|
if (PageState.QueryString.ContainsKey("key"))
|
||||||
{
|
{
|
||||||
user = await UserService.LinkUserAsync(user, PageState.QueryString["token"], PageState.Site.Settings["ExternalLogin:ProviderType"], PageState.QueryString["key"], PageState.Site.Settings["ExternalLogin:ProviderName"]);
|
user = await UserService.LinkUserAsync(user, PageState.QueryString["token"], PageState.Site.Settings["ExternalLogin:ProviderType"], PageState.QueryString["key"], PageState.Site.Settings["ExternalLogin:ProviderName"]);
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
await logger.LogInformation(LogFunction.Security, "External Login Linkage Successful For Username {Username}", _username);
|
await logger.LogInformation(LogFunction.Security, "External Login Linkage Successful For Username {Username}", _username);
|
||||||
AddModuleMessage(Localizer["Success.Account.Linked"], MessageType.Info);
|
AddModuleMessage(Localizer["Success.Account.Linked"], MessageType.Info);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await logger.LogError(LogFunction.Security, "External Login Linkage Failed For Username {Username}", _username);
|
await logger.LogError(LogFunction.Security, "External Login Linkage Failed For Username {Username}", _username);
|
||||||
AddModuleMessage(Localizer["Message.Account.NotLinked"], MessageType.Warning);
|
AddModuleMessage(Localizer["Message.Account.NotLinked"], MessageType.Warning);
|
||||||
}
|
}
|
||||||
_username = "";
|
_username = "";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
user = await UserService.VerifyEmailAsync(user, PageState.QueryString["token"]);
|
user = await UserService.VerifyEmailAsync(user, PageState.QueryString["token"]);
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
await logger.LogInformation(LogFunction.Security, "Email Verified For For Username {Username}", _username);
|
await logger.LogInformation(LogFunction.Security, "Email Verified For For Username {Username}", _username);
|
||||||
AddModuleMessage(Localizer["Success.Account.Verified"], MessageType.Info);
|
AddModuleMessage(Localizer["Success.Account.Verified"], MessageType.Info);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await logger.LogError(LogFunction.Security, "Email Verification Failed For Username {Username}", _username);
|
await logger.LogError(LogFunction.Security, "Email Verification Failed For Username {Username}", _username);
|
||||||
AddModuleMessage(Localizer["Message.Account.NotVerified"], MessageType.Warning);
|
AddModuleMessage(Localizer["Message.Account.NotVerified"], MessageType.Warning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (PageState.QueryString.ContainsKey("status"))
|
if (PageState.QueryString.ContainsKey("status"))
|
||||||
{
|
{
|
||||||
AddModuleMessage(Localizer["ExternalLoginStatus." + PageState.QueryString["status"]], MessageType.Info);
|
AddModuleMessage(Localizer["ExternalLoginStatus." + PageState.QueryString["status"]], MessageType.Info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Loading Login {Error}", ex.Message);
|
await logger.LogError(ex, "Error Loading Login {Error}", ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.LoadLogin"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.LoadLogin"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
{
|
{
|
||||||
if (firstRender && PageState.User == null)
|
if (firstRender && PageState.User == null)
|
||||||
{
|
{
|
||||||
await username.FocusAsync();
|
await username.FocusAsync();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private async Task Login()
|
// redirect logged in user to specified page
|
||||||
{
|
if (PageState.User != null)
|
||||||
try
|
{
|
||||||
{
|
NavigationManager.NavigateTo(PageState.ReturnUrl);
|
||||||
validated = true;
|
}
|
||||||
var interop = new Interop(JSRuntime);
|
}
|
||||||
if (await interop.FormValid(login))
|
|
||||||
{
|
|
||||||
var hybrid = (PageState.Runtime == Shared.Runtime.Hybrid);
|
|
||||||
var user = new User { SiteId = PageState.Site.SiteId, Username = _username, Password = _password, LastIPAddress = SiteState.RemoteIPAddress};
|
|
||||||
|
|
||||||
if (!twofactor)
|
private async Task Login()
|
||||||
{
|
{
|
||||||
user = await UserService.LoginUserAsync(user, hybrid, _remember);
|
try
|
||||||
}
|
{
|
||||||
else
|
validated = true;
|
||||||
{
|
var interop = new Interop(JSRuntime);
|
||||||
user = await UserService.VerifyTwoFactorAsync(user, _code);
|
if (await interop.FormValid(login))
|
||||||
}
|
{
|
||||||
|
var hybrid = (PageState.Runtime == Shared.Runtime.Hybrid);
|
||||||
|
var user = new User { SiteId = PageState.Site.SiteId, Username = _username, Password = _password, LastIPAddress = SiteState.RemoteIPAddress};
|
||||||
|
|
||||||
if (user.IsAuthenticated)
|
if (!twofactor)
|
||||||
{
|
{
|
||||||
await logger.LogInformation(LogFunction.Security, "Login Successful For Username {Username}", _username);
|
user = await UserService.LoginUserAsync(user, hybrid, _remember);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
user = await UserService.VerifyTwoFactorAsync(user, _code);
|
||||||
|
}
|
||||||
|
|
||||||
if (hybrid)
|
if (user.IsAuthenticated)
|
||||||
{
|
{
|
||||||
// hybrid apps utilize an interactive login
|
await logger.LogInformation(LogFunction.Security, "Login Successful For Username {Username}", _username);
|
||||||
var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider
|
|
||||||
.GetService(typeof(IdentityAuthenticationStateProvider));
|
|
||||||
authstateprovider.NotifyAuthenticationChanged();
|
|
||||||
NavigationManager.NavigateTo(NavigateUrl(WebUtility.UrlDecode(_returnUrl), true));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// post back to the Login page so that the cookies are set correctly
|
|
||||||
var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, username = _username, password = _password, remember = _remember, returnurl = _returnUrl };
|
|
||||||
string url = Utilities.TenantUrl(PageState.Alias, "/pages/login/");
|
|
||||||
await interop.SubmitForm(url, fields);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((PageState.Site.Settings.ContainsKey("LoginOptions:TwoFactor") && PageState.Site.Settings["LoginOptions:TwoFactor"] == "required") || user.TwoFactorRequired)
|
|
||||||
{
|
|
||||||
twofactor = true;
|
|
||||||
validated = false;
|
|
||||||
AddModuleMessage(Localizer["Message.TwoFactor"], MessageType.Info);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!twofactor)
|
|
||||||
{
|
|
||||||
await logger.LogInformation(LogFunction.Security, "Login Failed For Username {Username}", _username);
|
|
||||||
AddModuleMessage(Localizer["Error.Login.Fail"], MessageType.Error);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await logger.LogInformation(LogFunction.Security, "Two Factor Verification Failed For Username {Username}", _username);
|
|
||||||
AddModuleMessage(Localizer["Error.TwoFactor.Fail"], MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddModuleMessage(Localizer["Message.Required.UserInfo"], MessageType.Warning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Performing Login {Error}", ex.Message);
|
|
||||||
AddModuleMessage(Localizer["Error.Login"], MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Cancel()
|
if (hybrid)
|
||||||
{
|
{
|
||||||
NavigationManager.NavigateTo(_returnUrl);
|
// hybrid apps utilize an interactive login
|
||||||
}
|
var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider
|
||||||
|
.GetService(typeof(IdentityAuthenticationStateProvider));
|
||||||
|
authstateprovider.NotifyAuthenticationChanged();
|
||||||
|
NavigationManager.NavigateTo(NavigateUrl(WebUtility.UrlDecode(_returnUrl), true));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// post back to the Login page so that the cookies are set correctly
|
||||||
|
var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, username = _username, password = _password, remember = _remember, returnurl = _returnUrl };
|
||||||
|
string url = Utilities.TenantUrl(PageState.Alias, "/pages/login/");
|
||||||
|
await interop.SubmitForm(url, fields);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((PageState.Site.Settings.ContainsKey("LoginOptions:TwoFactor") && PageState.Site.Settings["LoginOptions:TwoFactor"] == "required") || user.TwoFactorRequired)
|
||||||
|
{
|
||||||
|
twofactor = true;
|
||||||
|
validated = false;
|
||||||
|
AddModuleMessage(Localizer["Message.TwoFactor"], MessageType.Info);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!twofactor)
|
||||||
|
{
|
||||||
|
await logger.LogInformation(LogFunction.Security, "Login Failed For Username {Username}", _username);
|
||||||
|
AddModuleMessage(Localizer["Error.Login.Fail"], MessageType.Error);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await logger.LogInformation(LogFunction.Security, "Two Factor Verification Failed For Username {Username}", _username);
|
||||||
|
AddModuleMessage(Localizer["Error.TwoFactor.Fail"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.Required.UserInfo"], MessageType.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Performing Login {Error}", ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.Login"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task Forgot()
|
private void Cancel()
|
||||||
{
|
{
|
||||||
try
|
NavigationManager.NavigateTo(_returnUrl);
|
||||||
{
|
}
|
||||||
if (_username != string.Empty)
|
|
||||||
{
|
|
||||||
var user = await UserService.GetUserAsync(_username, PageState.Site.SiteId);
|
|
||||||
if (user != null)
|
|
||||||
{
|
|
||||||
await UserService.ForgotPasswordAsync(user);
|
|
||||||
await logger.LogInformation(LogFunction.Security, "Password Reset Notification Sent For Username {Username}", _username);
|
|
||||||
AddModuleMessage(Localizer["Message.ForgotUser"], MessageType.Info);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddModuleMessage(Localizer["Message.UserDoesNotExist"], MessageType.Warning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddModuleMessage(Localizer["Message.ForgotPassword"], MessageType.Info);
|
|
||||||
}
|
|
||||||
|
|
||||||
StateHasChanged();
|
private async Task Forgot()
|
||||||
}
|
{
|
||||||
catch (Exception ex)
|
try
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Resetting Password {Error}", ex.Message);
|
if (_username != string.Empty)
|
||||||
AddModuleMessage(Localizer["Error.ResetPassword"], MessageType.Error);
|
{
|
||||||
}
|
var user = await UserService.GetUserAsync(_username, PageState.Site.SiteId);
|
||||||
}
|
if (user != null)
|
||||||
|
{
|
||||||
|
await UserService.ForgotPasswordAsync(user);
|
||||||
|
await logger.LogInformation(LogFunction.Security, "Password Reset Notification Sent For Username {Username}", _username);
|
||||||
|
AddModuleMessage(Localizer["Message.ForgotUser"], MessageType.Info);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.UserDoesNotExist"], MessageType.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.ForgotPassword"], MessageType.Info);
|
||||||
|
}
|
||||||
|
|
||||||
private void Reset()
|
StateHasChanged();
|
||||||
{
|
}
|
||||||
twofactor = false;
|
catch (Exception ex)
|
||||||
_username = "";
|
{
|
||||||
_password = "";
|
await logger.LogError(ex, "Error Resetting Password {Error}", ex.Message);
|
||||||
ClearModuleMessage();
|
AddModuleMessage(Localizer["Error.ResetPassword"], MessageType.Error);
|
||||||
StateHasChanged();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task KeyPressed(KeyboardEventArgs e)
|
private void Reset()
|
||||||
{
|
{
|
||||||
if (e.Code == "Enter" || e.Code == "NumpadEnter")
|
twofactor = false;
|
||||||
{
|
_username = "";
|
||||||
await Login();
|
_password = "";
|
||||||
}
|
ClearModuleMessage();
|
||||||
}
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
private void TogglePassword()
|
private async Task KeyPressed(KeyboardEventArgs e)
|
||||||
{
|
{
|
||||||
if (_passwordtype == "password")
|
if (e.Code == "Enter" || e.Code == "NumpadEnter")
|
||||||
{
|
{
|
||||||
_passwordtype = "text";
|
await Login();
|
||||||
_togglepassword = SharedLocalizer["HidePassword"];
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
_passwordtype = "password";
|
|
||||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ExternalLogin()
|
private void TogglePassword()
|
||||||
{
|
{
|
||||||
|
if (_passwordtype == "password")
|
||||||
|
{
|
||||||
|
_passwordtype = "text";
|
||||||
|
_togglepassword = SharedLocalizer["HidePassword"];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_passwordtype = "password";
|
||||||
|
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExternalLogin()
|
||||||
|
{
|
||||||
NavigationManager.NavigateTo(Utilities.TenantUrl(PageState.Alias, "/pages/external?returnurl=" + _returnUrl), true);
|
NavigationManager.NavigateTo(Utilities.TenantUrl(PageState.Alias, "/pages/external?returnurl=" + _returnUrl), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,65 +10,110 @@
|
|||||||
<TabStrip>
|
<TabStrip>
|
||||||
<TabPanel Name="Download" ResourceKey="Download">
|
<TabPanel Name="Download" ResourceKey="Download">
|
||||||
<div class="row justify-content-center mb-3">
|
<div class="row justify-content-center mb-3">
|
||||||
<div class="col-sm-6">
|
<div class="text-center">
|
||||||
|
<div class="form-check form-check-inline">
|
||||||
|
<input id="free" class="form-check-input" type="radio" checked="@(_price == "free")" name="Price" @onchange="@(() => PriceChanged("free"))" />
|
||||||
|
<label class="form-check-label" for="free">@SharedLocalizer["Free"]</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check form-check-inline">
|
||||||
|
<input id="paid" class="form-check-input" type="radio" checked="@(_price == "paid")" name="Price" @onchange="@(() => PriceChanged("paid"))" />
|
||||||
|
<label class="form-check-label" for="paid">@SharedLocalizer["Paid"]</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row justify-content-center mb-3">
|
||||||
|
<div class="col">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<select id="price" class="form-select custom-select" @onchange="(e => PriceChanged(e))">
|
<span class="input-group-text">@Localizer["Product"]</span>
|
||||||
<option value="free">@SharedLocalizer["Free"]</option>
|
|
||||||
<option value="paid">@SharedLocalizer["Paid"]</option>
|
|
||||||
</select>
|
|
||||||
<input id="search" class="form-control" placeholder="@SharedLocalizer["Search.Hint"]" @bind="@_search" />
|
<input id="search" class="form-control" placeholder="@SharedLocalizer["Search.Hint"]" @bind="@_search" />
|
||||||
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>
|
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>
|
||||||
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button>
|
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-3">
|
||||||
@if (_packages != null)
|
<div class="col">
|
||||||
{
|
@if (_initialized)
|
||||||
if (_packages.Count > 0)
|
{
|
||||||
{
|
<br />
|
||||||
<Pager Items="@_packages">
|
<div class="row mb-3">
|
||||||
<Row>
|
<div class="col-sm-4">
|
||||||
<td>
|
<h3>@((_packages != null) ? _packages.Count : 0) @SharedLocalizer["Search.Results"]</h3>
|
||||||
<h3 style="display: inline;"><a href="@context.ProductUrl" target="_new">@context.Name</a></h3> by: <strong><a href="@context.OwnerUrl" target="new">@context.Owner</a></strong><br />
|
</div>
|
||||||
@(context.Description.Length > 400 ? (context.Description.Substring(0, 400) + "...") : context.Description)<br />
|
<div class="col-sm-4">
|
||||||
<strong>@(String.Format("{0:n0}", context.Downloads))</strong> @SharedLocalizer["Search.Downloads"] |
|
|
||||||
@SharedLocalizer["Search.Released"]: <strong>@context.ReleaseDate.ToString("MMM dd, yyyy")</strong> |
|
</div>
|
||||||
@SharedLocalizer["Search.Version"]: <strong>@context.Version</strong>
|
<div class="col-sm-4">
|
||||||
@((MarkupString)(!string.IsNullOrEmpty(context.PackageUrl) ? " | " + SharedLocalizer["Search.Source"] + ": <strong>" + new Uri(context.PackageUrl).Host + "</strong>" : ""))
|
<select class="form-select" value="@_sort" @onchange="(e => SortChanged(e))">
|
||||||
@((MarkupString)(context.TrialPeriod > 0 ? " | <strong>" + context.TrialPeriod + " " + @SharedLocalizer["Trial"] + "</strong>" : ""))
|
<option value="popularity">@SharedLocalizer["Search.Popularity"]</option>
|
||||||
</td>
|
<option value="alphabetical">@SharedLocalizer["Search.Alphabetical"]</option>
|
||||||
<td style="width: 1px; vertical-align: middle;">
|
<option value="downloads">@SharedLocalizer["Search.Downloads"]</option>
|
||||||
@if (context.Price != null && !string.IsNullOrEmpty(context.PackageUrl))
|
<option value="recent">@SharedLocalizer["Search.RecentlyReleased"]</option>
|
||||||
{
|
@if (_price == "paid")
|
||||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await GetPackage(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button>
|
{
|
||||||
}
|
<option value="price">@SharedLocalizer["Search.Price"]</option>
|
||||||
</td>
|
}
|
||||||
<td style="width: 1px; vertical-align: middle;">
|
</select>
|
||||||
@if (context.Price != null && !string.IsNullOrEmpty(context.PaymentUrl))
|
</div>
|
||||||
{
|
</div>
|
||||||
<a class="btn btn-primary" style="text-decoration: none !important" href="@context.PaymentUrl" target="_new">@context.Price.Value.ToString("$#,##0.00")</a>
|
<Pager Format="Grid" Items="@_packages" DisplayPages="1" PageSize="9" Toolbar="Both" Class="container-fluid px-0" RowClass="row g-0" ColumnClass="col-lg-4 col-md-6">
|
||||||
}
|
<Row>
|
||||||
else
|
<div class="m-2 p-2 d-flex justify-content-center">
|
||||||
{
|
<div class="container-fluid px-0">
|
||||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await GetPackage(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button>
|
<div class="row g-0">
|
||||||
}
|
<div class="col-6">
|
||||||
</td>
|
@if (context.LogoFileId != null)
|
||||||
</Row>
|
{
|
||||||
</Pager>
|
<img src="@GetLogo(context.LogoFileId.Value)" class="img-fluid" alt="@context.Name" />
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<br />
|
<img src="/package.png" class="img-fluid" alt="@context.Name" />
|
||||||
<div class="mx-auto text-center">
|
}
|
||||||
@Localizer["Search.NoResults"]
|
</div>
|
||||||
</div>
|
<div class="col-6 text-end">
|
||||||
}
|
<small>@SharedLocalizer["Search.Version"]:</small> <strong>@context.Version</strong>
|
||||||
}
|
<br /><small>@SharedLocalizer["Search.Downloads"]:</small> <strong>@(String.Format("{0:n0}", context.Downloads))</strong>
|
||||||
|
<br /><small>@SharedLocalizer["Search.Released"]:</small> <strong>@context.ReleaseDate.ToString("MM/dd/yyyy")</strong>
|
||||||
|
@if (!string.IsNullOrEmpty(context.PackageUrl))
|
||||||
|
{
|
||||||
|
<br /><small>@SharedLocalizer["Search.Source"]:</small> <strong>@(new Uri(context.PackageUrl).Host)</strong>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row g-0">
|
||||||
|
<div class="col">
|
||||||
|
<h3 style="display: inline;"><a href="@context.ProductUrl" target="_blank">@context.Name</a></h3><br />
|
||||||
|
<small>@SharedLocalizer["Search.By"]:</small> <strong><a href="@context.OwnerUrl" target="new">@context.Owner</a></strong><br />
|
||||||
|
@(context.Description.Length > 400 ? (context.Description.Substring(0, 400) + "...") : context.Description)<br />
|
||||||
|
@if (context.Price != null && !string.IsNullOrEmpty(context.PaymentUrl))
|
||||||
|
{
|
||||||
|
<small>@SharedLocalizer["Search.Price"]:</small> <strong>@context.Price.Value.ToString("$#,##0.00")</strong>
|
||||||
|
@((MarkupString)(context.TrialPeriod > 0 ? " <strong>(" + context.TrialPeriod + " Day Trial)</strong>" : ""))
|
||||||
|
}
|
||||||
|
<br />
|
||||||
|
@if (!string.IsNullOrEmpty(context.PackageUrl))
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-primary" @onclick=@(async () => await GetPackage(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button>
|
||||||
|
}
|
||||||
|
@if (context.Price != null && !string.IsNullOrEmpty(context.PaymentUrl))
|
||||||
|
{
|
||||||
|
<a class="btn btn-success ms-2" style="text-decoration: none !important" href="@context.PaymentUrl" target="_new">@SharedLocalizer["Buy"]</a>
|
||||||
|
}
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Row>
|
||||||
|
</Pager>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<ModuleMessage Type="MessageType.Info" Message="@SharedLocalizer["Oqtane.Marketplace"]" />
|
<ModuleMessage Type="MessageType.Info" Message="@SharedLocalizer["Oqtane.Marketplace"]" />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel Name="Upload" ResourceKey="Upload">
|
<TabPanel Name="Upload" ResourceKey="Upload" Heading="Upload">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" HelpText="Upload one or more module packages. Once they are uploaded click Install to complete the installation." ResourceKey="Module">Module: </Label>
|
<Label Class="col-sm-3" HelpText="Upload one or more module packages. Once they are uploaded click Install to complete the installation." ResourceKey="Module">Module: </Label>
|
||||||
@ -116,8 +161,10 @@
|
|||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
private bool _initialized = false;
|
||||||
private List<Package> _packages;
|
private List<Package> _packages;
|
||||||
private string _price = "free";
|
private string _price = "free";
|
||||||
|
private string _sort = "popularity";
|
||||||
private string _search = "";
|
private string _search = "";
|
||||||
private string _productname = "";
|
private string _productname = "";
|
||||||
private string _packageid = "";
|
private string _packageid = "";
|
||||||
@ -131,6 +178,7 @@
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await LoadModuleDefinitions();
|
await LoadModuleDefinitions();
|
||||||
|
_initialized = true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -141,8 +189,10 @@
|
|||||||
|
|
||||||
private async Task LoadModuleDefinitions()
|
private async Task LoadModuleDefinitions()
|
||||||
{
|
{
|
||||||
|
ShowProgressIndicator();
|
||||||
|
|
||||||
var moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
|
var moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
|
||||||
_packages = await PackageService.GetPackagesAsync("module", _search, _price, "");
|
_packages = await PackageService.GetPackagesAsync("module", _search, _price, "", _sort);
|
||||||
|
|
||||||
if (_packages != null)
|
if (_packages != null)
|
||||||
{
|
{
|
||||||
@ -154,21 +204,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HideProgressIndicator();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void PriceChanged(ChangeEventArgs e)
|
private string GetLogo(int fileid)
|
||||||
{
|
{
|
||||||
try
|
var url = ImageUrl(fileid, 100, 100);
|
||||||
{
|
url = (!string.IsNullOrEmpty(PageState.Alias.Path)) ? url.Substring(PageState.Alias.Path.Length + 1) : url;
|
||||||
_price = (string)e.Value;
|
return Constants.PackageRegistryUrl + url;
|
||||||
_search = "";
|
}
|
||||||
await LoadModuleDefinitions();
|
|
||||||
StateHasChanged();
|
private async void PriceChanged(string price)
|
||||||
}
|
{
|
||||||
catch (Exception ex)
|
_price = price;
|
||||||
{
|
await LoadModuleDefinitions();
|
||||||
await logger.LogError(ex, "Error On PriceChanged");
|
StateHasChanged();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Search()
|
private async Task Search()
|
||||||
@ -196,6 +247,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void SortChanged(ChangeEventArgs e)
|
||||||
|
{
|
||||||
|
_sort = (string)e.Value;
|
||||||
|
await LoadModuleDefinitions();
|
||||||
|
}
|
||||||
|
|
||||||
private void HideModal()
|
private void HideModal()
|
||||||
{
|
{
|
||||||
_productname = "";
|
_productname = "";
|
||||||
|
@ -80,7 +80,7 @@ else
|
|||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@((MarkupString)SupportLink(context.PackageName))
|
@((MarkupString)SupportLink(context.PackageName, context.Version))
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@((MarkupString)PurchaseLink(context.PackageName))
|
@((MarkupString)PurchaseLink(context.PackageName))
|
||||||
@ -145,7 +145,7 @@ else
|
|||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string SupportLink(string packagename)
|
private string SupportLink(string packagename, string version)
|
||||||
{
|
{
|
||||||
string link = "";
|
string link = "";
|
||||||
if (!string.IsNullOrEmpty(packagename) && _packages != null)
|
if (!string.IsNullOrEmpty(packagename) && _packages != null)
|
||||||
@ -153,7 +153,7 @@ else
|
|||||||
var package = _packages.Where(item => item.PackageId == packagename).FirstOrDefault();
|
var package = _packages.Where(item => item.PackageId == packagename).FirstOrDefault();
|
||||||
if (package != null && !string.IsNullOrEmpty(package.SupportUrl))
|
if (package != null && !string.IsNullOrEmpty(package.SupportUrl))
|
||||||
{
|
{
|
||||||
link += "<a class=\"btn btn-success\" style=\"text-decoration: none !important\" href=\"" + package.SupportUrl + "\" target=\"_new\">" + SharedLocalizer["Help"] + "</a>";
|
link += "<a class=\"btn btn-info\" style=\"text-decoration: none !important\" href=\"" + package.SupportUrl.Replace("{Version}", version) + "\" target=\"_new\">" + SharedLocalizer["Help"] + "</a>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return link;
|
return link;
|
||||||
|
@ -22,6 +22,11 @@
|
|||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||||
public override string Title => "Export Content";
|
public override string Title => "Export Content";
|
||||||
|
|
||||||
|
protected override void OnParametersSet()
|
||||||
|
{
|
||||||
|
base.OnParametersSet();
|
||||||
|
base.SetModuleTitle(Localizer["ModuleTitle.Text"]);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ExportModule()
|
private async Task ExportModule()
|
||||||
{
|
{
|
||||||
|
@ -28,6 +28,11 @@
|
|||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||||
public override string Title => "Import Content";
|
public override string Title => "Import Content";
|
||||||
|
|
||||||
|
protected override void OnParametersSet()
|
||||||
|
{
|
||||||
|
base.OnParametersSet();
|
||||||
|
base.SetModuleTitle(Localizer["ModuleTitle.Text"]);
|
||||||
|
}
|
||||||
private async Task ImportModule()
|
private async Task ImportModule()
|
||||||
{
|
{
|
||||||
validated = true;
|
validated = true;
|
||||||
|
@ -130,6 +130,11 @@
|
|||||||
private string modifiedby;
|
private string modifiedby;
|
||||||
private DateTime modifiedon;
|
private DateTime modifiedon;
|
||||||
|
|
||||||
|
protected override void OnParametersSet()
|
||||||
|
{
|
||||||
|
base.OnParametersSet();
|
||||||
|
base.SetModuleTitle(Localizer["ModuleTitle.Text"]);
|
||||||
|
}
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
_module = ModuleState.ModuleDefinition.Name;
|
_module = ModuleState.ModuleDefinition.Name;
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
{
|
{
|
||||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||||
<TabStrip Refresh="@_refresh">
|
<TabStrip Refresh="@_refresh">
|
||||||
<TabPanel Name="Settings" ResourceKey="Settings">
|
<TabPanel Name="Settings" ResourceKey="Settings" Heading="Settings">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="name" HelpText="Enter the page name" ResourceKey="Name">Name: </Label>
|
<Label Class="col-sm-3" For="name" HelpText="Enter the page name" ResourceKey="Name">Name: </Label>
|
||||||
@ -126,7 +126,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Section Name="Appearance" Heading="Appearance" ResourceKey="Appearance">
|
<Section Name="Appearance" ResourceKey="Appearance" Heading=@Localizer["Appearance.Name"]>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="title" HelpText="Optionally enter the page title. If you do not provide a page title, the page name will be used." ResourceKey="Title">Title: </Label>
|
<Label Class="col-sm-3" For="title" HelpText="Optionally enter the page title. If you do not provide a page title, the page name will be used." ResourceKey="Title">Title: </Label>
|
||||||
@ -158,7 +158,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
<Section Name="PageContent" Heading="Page Content" ResourceKey="PageContent">
|
<Section Name="PageContent" ResourceKey="PageContent" Heading=@Localizer["PageContent.Heading"]>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="headcontent" HelpText="Optionally enter content to be included in the page head (ie. meta, link, or script tags)" ResourceKey="HeadContent">Head Content: </Label>
|
<Label Class="col-sm-3" For="headcontent" HelpText="Optionally enter content to be included in the page head (ie. meta, link, or script tags)" ResourceKey="HeadContent">Head Content: </Label>
|
||||||
@ -175,7 +175,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel Name="Permissions" ResourceKey="Permissions">
|
<TabPanel Name="Permissions" ResourceKey="Permissions" Heading=@Localizer["Permissions.Heading"]>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<PermissionGrid EntityName="@EntityNames.Page" Permissions="@_permissions" @ref="_permissionGrid" />
|
<PermissionGrid EntityName="@EntityNames.Page" Permissions="@_permissions" @ref="_permissionGrid" />
|
||||||
@ -184,7 +184,7 @@
|
|||||||
</TabPanel>
|
</TabPanel>
|
||||||
@if (_themeSettingsType != null)
|
@if (_themeSettingsType != null)
|
||||||
{
|
{
|
||||||
<TabPanel Name="ThemeSettings" Heading="Theme Settings" ResourceKey="ThemeSettings">
|
<TabPanel Name="ThemeSettings" Heading=@Localizer["Theme.Heading"] ResourceKey="ThemeSettings">
|
||||||
@ThemeSettingsComponent
|
@ThemeSettingsComponent
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
@if (_page.UserId == null)
|
@if (_page.UserId == null)
|
||||||
{
|
{
|
||||||
<TabStrip Refresh="@_refresh">
|
<TabStrip Refresh="@_refresh">
|
||||||
<TabPanel Name="Settings" ResourceKey="Settings" Heading=@Localizer["Settings.Heading"]>
|
<TabPanel Name="Settings" ResourceKey="Settings" Heading="Settings">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="name" HelpText="Enter the page name" ResourceKey="Name">Name: </Label>
|
<Label Class="col-sm-3" For="name" HelpText="Enter the page name" ResourceKey="Name">Name: </Label>
|
||||||
@ -137,7 +137,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Section Name="Appearance" ResourceKey="Appearance">
|
<Section Name="Appearance" ResourceKey="Appearance" Heading="Appearance">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="title" HelpText="Optionally enter the page title. If you do not provide a page title, the page name will be used." ResourceKey="Title">Title: </Label>
|
<Label Class="col-sm-3" For="title" HelpText="Optionally enter the page title. If you do not provide a page title, the page name will be used." ResourceKey="Title">Title: </Label>
|
||||||
@ -189,7 +189,7 @@
|
|||||||
<br />
|
<br />
|
||||||
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon" DeletedBy="@_deletedby" DeletedOn="@_deletedon"></AuditInfo>
|
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon" DeletedBy="@_deletedby" DeletedOn="@_deletedon"></AuditInfo>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel Name="Permissions" ResourceKey="Permissions">
|
<TabPanel Name="Permissions" ResourceKey="Permissions" Heading="Permissions">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<PermissionGrid EntityName="@EntityNames.Page" PermissionList="@_permissions" @ref="_permissionGrid" />
|
<PermissionGrid EntityName="@EntityNames.Page" PermissionList="@_permissions" @ref="_permissionGrid" />
|
||||||
@ -224,7 +224,7 @@
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
<TabStrip Refresh="@_refresh">
|
<TabStrip Refresh="@_refresh">
|
||||||
<TabPanel Name="Settings" ResourceKey="Settings" Heading=@Localizer["Settings.Heading"]>
|
<TabPanel Name="Settings" ResourceKey="Settings" Heading="Settings">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="title" HelpText="Optionally enter the page title. If you do not provide a page title, the page name will be used." ResourceKey="Title">Title: </Label>
|
<Label Class="col-sm-3" For="title" HelpText="Optionally enter the page title. If you do not provide a page title, the page name will be used." ResourceKey="Title">Title: </Label>
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
<TabStrip>
|
<TabStrip>
|
||||||
<TabPanel Name="Pages" ResourceKey="Pages">
|
<TabPanel Name="Pages" ResourceKey="Pages" Heading="Pages">
|
||||||
@if (!_pages.Where(item => item.IsDeleted).Any())
|
@if (!_pages.Where(item => item.IsDeleted).Any())
|
||||||
{
|
{
|
||||||
<br />
|
<br />
|
||||||
@ -31,7 +31,7 @@ else
|
|||||||
<th>@Localizer["DeletedOn"]</th>
|
<th>@Localizer["DeletedOn"]</th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><button type="button" @onclick="@(() => RestorePage(context))" class="btn btn-success" title="Restore">Restore</button></td>
|
<td><button type="button" @onclick="@(() => RestorePage(context))" class="btn btn-success" title="Restore">@Localizer["Restore"]</button></td>
|
||||||
<td><ActionDialog Header="Delete Page" Message="@string.Format(Localizer["Confirm.Page.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeletePage(context))" ResourceKey="DeletePage" /></td>
|
<td><ActionDialog Header="Delete Page" Message="@string.Format(Localizer["Confirm.Page.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeletePage(context))" ResourceKey="DeletePage" /></td>
|
||||||
<td>@context.Name</td>
|
<td>@context.Name</td>
|
||||||
<td>@context.DeletedBy</td>
|
<td>@context.DeletedBy</td>
|
||||||
@ -42,7 +42,7 @@ else
|
|||||||
<ActionDialog Header="Remove All Deleted Pages" Message="Are You Sure You Wish To Permanently Remove All Deleted Pages?" Action="Remove All Deleted Pages" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllPages())" ResourceKey="DeleteAllPages" />
|
<ActionDialog Header="Remove All Deleted Pages" Message="Are You Sure You Wish To Permanently Remove All Deleted Pages?" Action="Remove All Deleted Pages" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllPages())" ResourceKey="DeleteAllPages" />
|
||||||
}
|
}
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel Name="Modules" ResourceKey="Modules">
|
<TabPanel Name="Modules" ResourceKey="Modules" Heading="Modules">
|
||||||
@if (!_modules.Where(item => item.IsDeleted).Any())
|
@if (!_modules.Where(item => item.IsDeleted).Any())
|
||||||
{
|
{
|
||||||
<br />
|
<br />
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
<Label Class="col-sm-3" For="homepage" HelpText="Select the home page for the site (to be used if there is no page with a path of '/')" ResourceKey="HomePage">Home Page: </Label>
|
<Label Class="col-sm-3" For="homepage" HelpText="Select the home page for the site (to be used if there is no page with a path of '/')" ResourceKey="HomePage">Home Page: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="homepage" class="form-select" @bind="@_homepageid" required>
|
<select id="homepage" class="form-select" @bind="@_homepageid" required>
|
||||||
<option value="-"><@Localizer["Not Specified"]></option>
|
<option value="-"><@SharedLocalizer["Not Specified"]></option>
|
||||||
@foreach (Page page in PageState.Pages)
|
@foreach (Page page in PageState.Pages)
|
||||||
{
|
{
|
||||||
if (UserSecurity.ContainsRole(page.PermissionList, PermissionNames.View, RoleNames.Everyone))
|
if (UserSecurity.ContainsRole(page.PermissionList, PermissionNames.View, RoleNames.Everyone))
|
||||||
@ -60,7 +60,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<Section Name="Appearance" ResourceKey="Appearance">
|
<Section Name="Appearance" Heading="Appearance" ResourceKey="Appearance">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="logo" HelpText="Specify a logo for the site" ResourceKey="Logo">Logo: </Label>
|
<Label Class="col-sm-3" For="logo" HelpText="Specify a logo for the site" ResourceKey="Logo">Logo: </Label>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
@if (_sites == null)
|
@if (_sites == null)
|
||||||
{
|
{
|
||||||
<p><em>Loading...</em></p>
|
<p><em>@SharedLocalizer["Loading"]</em></p>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -10,61 +10,108 @@
|
|||||||
<TabStrip>
|
<TabStrip>
|
||||||
<TabPanel Name="Download" ResourceKey="Download">
|
<TabPanel Name="Download" ResourceKey="Download">
|
||||||
<div class="row justify-content-center mb-3">
|
<div class="row justify-content-center mb-3">
|
||||||
<div class="col-sm-6">
|
<div class="text-center">
|
||||||
|
<div class="form-check form-check-inline">
|
||||||
|
<input id="free" class="form-check-input" type="radio" checked="@(_price == "free")" name="Price" @onchange="@(() => PriceChanged("free"))" />
|
||||||
|
<label class="form-check-label" for="free">@SharedLocalizer["Free"]</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check form-check-inline">
|
||||||
|
<input id="paid" class="form-check-input" type="radio" checked="@(_price == "paid")" name="Price" @onchange="@(() => PriceChanged("paid"))" />
|
||||||
|
<label class="form-check-label" for="paid">@SharedLocalizer["Paid"]</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row justify-content-center mb-3">
|
||||||
|
<div class="col">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<select id="price" class="form-select custom-select" @onchange="(e => PriceChanged(e))">
|
<span class="input-group-text">Product</span>
|
||||||
<option value="free">@SharedLocalizer["Free"]</option>
|
|
||||||
<option value="paid">@SharedLocalizer["Paid"]</option>
|
|
||||||
</select>
|
|
||||||
<input id="search" class="form-control" placeholder="@SharedLocalizer["Search.Hint"]" @bind="@_search" />
|
<input id="search" class="form-control" placeholder="@SharedLocalizer["Search.Hint"]" @bind="@_search" />
|
||||||
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>
|
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>
|
||||||
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button>
|
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col">
|
||||||
|
@if (_initialized)
|
||||||
|
{
|
||||||
|
<br />
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<h3>@((_packages != null) ? _packages.Count : 0) @SharedLocalizer["Search.Results"]</h3>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<select class="form-select" value="@_sort" @onchange="(e => SortChanged(e))">
|
||||||
|
<option value="popularity">@SharedLocalizer["Search.Popularity"]</option>
|
||||||
|
<option value="alphabetical">@SharedLocalizer["Search.Alphabetical"]</option>
|
||||||
|
<option value="downloads">@SharedLocalizer["Search.Downloads"]</option>
|
||||||
|
<option value="recent">@SharedLocalizer["Search.RecentlyReleased"]</option>
|
||||||
|
@if (_price == "paid")
|
||||||
|
{
|
||||||
|
<option value="price">@SharedLocalizer["Search.Price"]</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Pager Format="Grid" Items="@_packages" DisplayPages="1" PageSize="9" Toolbar="Both" Class="container-fluid px-0" RowClass="row g-0" ColumnClass="col-lg-4 col-md-6">
|
||||||
|
<Row>
|
||||||
|
<div class="m-2 p-2 d-flex justify-content-center">
|
||||||
|
<div class="container-fluid px-0">
|
||||||
|
<div class="row g-0">
|
||||||
|
<div class="col-6">
|
||||||
|
@if (context.LogoFileId != null)
|
||||||
|
{
|
||||||
|
<img src="@GetLogo(context.LogoFileId.Value)" class="img-fluid" alt="@context.Name" />
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<img src="/package.png" class="img-fluid" alt="@context.Name" />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div class="col-6 text-end">
|
||||||
|
<small>@SharedLocalizer["Search.Version"]:</small> <strong>@context.Version</strong>
|
||||||
|
<br /><small>@SharedLocalizer["Search.Downloads"]:</small> <strong>@(String.Format("{0:n0}", context.Downloads))</strong>
|
||||||
|
<br /><small>@SharedLocalizer["Search.Released"]:</small> <strong>@context.ReleaseDate.ToString("MM/dd/yyyy")</strong>
|
||||||
|
@if (!string.IsNullOrEmpty(context.PackageUrl))
|
||||||
|
{
|
||||||
|
<br />
|
||||||
|
|
||||||
@if (_packages != null)
|
<small>@SharedLocalizer["Search.Source"]:</small> <strong>@(new Uri(context.PackageUrl).Host)</strong>
|
||||||
{
|
}
|
||||||
if (_packages.Count > 0)
|
</div>
|
||||||
{
|
</div>
|
||||||
<Pager Items="@_packages">
|
<div class="row g-0">
|
||||||
<Row>
|
<div class="col">
|
||||||
<td>
|
<h3 style="display: inline;"><a href="@context.ProductUrl" target="_blank">@context.Name</a></h3><br />
|
||||||
<h3 style="display: inline;"><a href="@context.ProductUrl" target="_new">@context.Name</a></h3> @SharedLocalizer["Search.By"]: <strong><a href="@context.OwnerUrl" target="new">@context.Owner</a></strong><br />
|
<small>@SharedLocalizer["Search.By"]:</small> <strong><a href="@context.OwnerUrl" target="new">@context.Owner</a></strong><br />
|
||||||
@(context.Description.Length > 400 ? (context.Description.Substring(0, 400) + "...") : context.Description)<br />
|
@(context.Description.Length > 400 ? (context.Description.Substring(0, 400) + "...") : context.Description)<br />
|
||||||
<strong>@(String.Format("{0:n0}", context.Downloads))</strong> @SharedLocalizer["Search.Downloads"] |
|
@if (context.Price != null && !string.IsNullOrEmpty(context.PaymentUrl))
|
||||||
@SharedLocalizer["Search.Released"]: <strong>@context.ReleaseDate.ToString("MMM dd, yyyy")</strong> |
|
{
|
||||||
@SharedLocalizer["Search.Version"]: <strong>@context.Version</strong>
|
<small>@SharedLocalizer["Search.Price"]:</small> <strong>@context.Price.Value.ToString("$#,##0.00")</strong>
|
||||||
@((MarkupString)(!string.IsNullOrEmpty(context.PackageUrl) ? " | " + SharedLocalizer["Search.Source"] + ": <strong>" + new Uri(context.PackageUrl).Host + "</strong>" : ""))
|
@((MarkupString)(context.TrialPeriod > 0 ? " <strong>(" + context.TrialPeriod + " Day Trial)</strong>" : ""))
|
||||||
@((MarkupString)(context.TrialPeriod > 0 ? " | <strong>" + context.TrialPeriod + " " + @SharedLocalizer["Trial"] + "</strong>" : ""))
|
}
|
||||||
</td>
|
<br />
|
||||||
<td style="width: 1px; vertical-align: middle;">
|
@if (!string.IsNullOrEmpty(context.PackageUrl))
|
||||||
@if (context.Price != null && !string.IsNullOrEmpty(context.PackageUrl))
|
{
|
||||||
{
|
<button type="button" class="btn btn-primary" @onclick=@(async () => await GetPackage(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button>
|
||||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await GetPackage(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button>
|
}
|
||||||
}
|
@if (context.Price != null && !string.IsNullOrEmpty(context.PaymentUrl))
|
||||||
</td>
|
{
|
||||||
<td style="width: 1px; vertical-align: middle;">
|
<a class="btn btn-success ms-2" style="text-decoration: none !important" href="@context.PaymentUrl" target="_new">@SharedLocalizer["Buy"]</a>
|
||||||
@if (context.Price != null && !string.IsNullOrEmpty(context.PaymentUrl))
|
}
|
||||||
{
|
<br />
|
||||||
<a class="btn btn-primary" style="text-decoration: none !important" href="@context.PaymentUrl" target="_new">@context.Price.Value.ToString("$#,##0.00")</a>
|
</div>
|
||||||
}
|
</div>
|
||||||
else
|
</div>
|
||||||
{
|
</div>
|
||||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await GetPackage(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button>
|
</Row>
|
||||||
}
|
</Pager>
|
||||||
</td>
|
}
|
||||||
</Row>
|
</div>
|
||||||
</Pager>
|
</div>
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<br />
|
|
||||||
<div class="mx-auto text-center">
|
|
||||||
@Localizer["Search.NoResults"]
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
<br />
|
<br />
|
||||||
<ModuleMessage Type="MessageType.Info" Message="@SharedLocalizer["Oqtane.Marketplace"]" />
|
<ModuleMessage Type="MessageType.Info" Message="@SharedLocalizer["Oqtane.Marketplace"]" />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
@ -116,8 +163,10 @@
|
|||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
private bool _initialized = false;
|
||||||
private List<Package> _packages;
|
private List<Package> _packages;
|
||||||
private string _price = "free";
|
private string _price = "free";
|
||||||
|
private string _sort = "popularity";
|
||||||
private string _search = "";
|
private string _search = "";
|
||||||
private string _productname = "";
|
private string _productname = "";
|
||||||
private string _license = "";
|
private string _license = "";
|
||||||
@ -131,6 +180,7 @@
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await LoadThemes();
|
await LoadThemes();
|
||||||
|
_initialized = true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -141,8 +191,10 @@
|
|||||||
|
|
||||||
private async Task LoadThemes()
|
private async Task LoadThemes()
|
||||||
{
|
{
|
||||||
|
ShowProgressIndicator();
|
||||||
|
|
||||||
var themes = await ThemeService.GetThemesAsync();
|
var themes = await ThemeService.GetThemesAsync();
|
||||||
_packages = await PackageService.GetPackagesAsync("theme", _search, _price, "");
|
_packages = await PackageService.GetPackagesAsync("theme", _search, _price, "", _sort);
|
||||||
|
|
||||||
if (_packages != null)
|
if (_packages != null)
|
||||||
{
|
{
|
||||||
@ -154,21 +206,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HideProgressIndicator();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void PriceChanged(ChangeEventArgs e)
|
private string GetLogo(int fileid)
|
||||||
{
|
{
|
||||||
try
|
var url = ImageUrl(fileid, 100, 100);
|
||||||
{
|
url = (!string.IsNullOrEmpty(PageState.Alias.Path)) ? url.Substring(PageState.Alias.Path.Length + 1) : url;
|
||||||
_price = (string)e.Value;
|
return Constants.PackageRegistryUrl + url;
|
||||||
_search = "";
|
}
|
||||||
await LoadThemes();
|
|
||||||
StateHasChanged();
|
private async void PriceChanged(string price)
|
||||||
}
|
{
|
||||||
catch (Exception ex)
|
_price = price;
|
||||||
{
|
await LoadThemes();
|
||||||
await logger.LogError(ex, "Error On PriceChanged");
|
StateHasChanged();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Search()
|
private async Task Search()
|
||||||
@ -196,6 +249,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void SortChanged(ChangeEventArgs e)
|
||||||
|
{
|
||||||
|
_sort = (string)e.Value;
|
||||||
|
await LoadThemes();
|
||||||
|
}
|
||||||
|
|
||||||
private void HideModal()
|
private void HideModal()
|
||||||
{
|
{
|
||||||
_productname = "";
|
_productname = "";
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<Section Name="Information" ResourceKey="Information">
|
<Section Name="Information" ResourceKey="Information" Heading="Information">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="themename" HelpText="The internal name of the module" ResourceKey="InternalName">Internal Name: </Label>
|
<Label Class="col-sm-3" For="themename" HelpText="The internal name of the module" ResourceKey="InternalName">Internal Name: </Label>
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<ActionLink Action="Add" Text="Install Theme" />
|
<ActionLink Action="Add" Text="Install Theme" ResourceKey="InstallTheme" />
|
||||||
@((MarkupString)" ")
|
@((MarkupString)" ")
|
||||||
<ActionLink Action="Create" Text="Create Theme" ResourceKey="CreateTheme" Class="btn btn-secondary" />
|
<ActionLink Action="Create" Text="Create Theme" ResourceKey="CreateTheme" Class="btn btn-secondary" />
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ else
|
|||||||
}
|
}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@((MarkupString)SupportLink(context.PackageName))
|
@((MarkupString)SupportLink(context.PackageName, context.Version))
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@((MarkupString)PurchaseLink(context.PackageName))
|
@((MarkupString)PurchaseLink(context.PackageName))
|
||||||
@ -112,7 +112,7 @@ else
|
|||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string SupportLink(string packagename)
|
private string SupportLink(string packagename, string version)
|
||||||
{
|
{
|
||||||
string link = "";
|
string link = "";
|
||||||
if (!string.IsNullOrEmpty(packagename) && _packages != null)
|
if (!string.IsNullOrEmpty(packagename) && _packages != null)
|
||||||
@ -120,7 +120,7 @@ else
|
|||||||
var package = _packages.Where(item => item.PackageId == packagename).FirstOrDefault();
|
var package = _packages.Where(item => item.PackageId == packagename).FirstOrDefault();
|
||||||
if (package != null && !string.IsNullOrEmpty(package.SupportUrl))
|
if (package != null && !string.IsNullOrEmpty(package.SupportUrl))
|
||||||
{
|
{
|
||||||
link += "<a class=\"btn btn-success\" style=\"text-decoration: none !important\" href=\"" + package.SupportUrl + "\" target=\"_new\">" + SharedLocalizer["Help"] + "</a>";
|
link += "<a class=\"btn btn-info\" style=\"text-decoration: none !important\" href=\"" + package.SupportUrl.Replace("{Version}", version) + "\" target=\"_new\">" + SharedLocalizer["Help"] + "</a>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return link;
|
return link;
|
||||||
|
@ -17,11 +17,11 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<ModuleMessage Type="MessageType.Info" Message="Framework Is Already Up To Date"></ModuleMessage>
|
<ModuleMessage Type="MessageType.Info" Message=@Localizer["Message.Text"]></ModuleMessage>
|
||||||
}
|
}
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel Name="Upload" ResourceKey="Upload">
|
<TabPanel Name="Upload" ResourceKey="Upload">
|
||||||
<ModuleMessage Type="MessageType.Info" Message="Upload A Framework Package (Oqtane.Framework.version.nupkg) And Then Select Upgrade"></ModuleMessage>
|
<ModuleMessage Type="MessageType.Info" Message=@Localizer["MessgeUpgrade.Text"]></ModuleMessage>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" HelpText="Upload A Framework Package And Then Select Upgrade" ResourceKey="Framework">Framework: </Label>
|
<Label Class="col-sm-3" HelpText="Upload A Framework Package And Then Select Upgrade" ResourceKey="Framework">Framework: </Label>
|
||||||
|
@ -42,6 +42,12 @@
|
|||||||
|
|
||||||
public override string Title => "Send Notification";
|
public override string Title => "Send Notification";
|
||||||
|
|
||||||
|
protected override void OnParametersSet()
|
||||||
|
{
|
||||||
|
base.OnParametersSet();
|
||||||
|
base.SetModuleTitle(Localizer["ModuleTitle.Text"]);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task Send()
|
private async Task Send()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -110,6 +110,11 @@
|
|||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
|
||||||
public override string Title => "View Notification";
|
public override string Title => "View Notification";
|
||||||
|
|
||||||
|
protected override void OnParametersSet()
|
||||||
|
{
|
||||||
|
base.OnParametersSet();
|
||||||
|
base.SetModuleTitle(Localizer["ModuleTitle.Text"]);
|
||||||
|
}
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -140,34 +140,26 @@
|
|||||||
{
|
{
|
||||||
if (_password == confirm)
|
if (_password == confirm)
|
||||||
{
|
{
|
||||||
var user = await UserService.GetUserAsync(username, PageState.Site.SiteId);
|
var user = new User();
|
||||||
if (user == null)
|
user.SiteId = PageState.Site.SiteId;
|
||||||
|
user.Username = username;
|
||||||
|
user.Password = _password;
|
||||||
|
user.Email = email;
|
||||||
|
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
|
||||||
|
user.PhotoFileId = null;
|
||||||
|
|
||||||
|
user = await UserService.AddUserAsync(user);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
{
|
{
|
||||||
user = new User();
|
await SettingService.UpdateUserSettingsAsync(settings, user.UserId);
|
||||||
user.SiteId = PageState.Site.SiteId;
|
await logger.LogInformation("User Created {User}", user);
|
||||||
user.Username = username;
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
user.Password = _password;
|
|
||||||
user.Email = email;
|
|
||||||
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
|
|
||||||
user.PhotoFileId = null;
|
|
||||||
|
|
||||||
user = await UserService.AddUserAsync(user);
|
|
||||||
|
|
||||||
if (user != null)
|
|
||||||
{
|
|
||||||
await SettingService.UpdateUserSettingsAsync(settings, user.UserId);
|
|
||||||
await logger.LogInformation("User Created {User}", user);
|
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await logger.LogError("Error Adding User {Username} {Email}", username, email);
|
|
||||||
AddModuleMessage(Localizer["Error.User.AddCheckPass"], MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddModuleMessage(Localizer["Message.Username.Exists"], MessageType.Warning);
|
await logger.LogError("Error Adding User {Username} {Email}", username, email);
|
||||||
|
AddModuleMessage(Localizer["Error.User.AddCheckPass"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
@inherits LocalizableComponent
|
@inherits LocalizableComponent
|
||||||
|
|
||||||
<div class="app-autocomplete">
|
<div class="app-autocomplete">
|
||||||
<input class="form-control" value="@Value" @oninput="OnInput" @onkeyup="OnKeyUp" placeholder="@Placeholder" autocomplete="off" />
|
<input class="form-control" value="@Value" @oninput="OnInput" @onkeyup="OnKeyUp" placeholder="@Placeholder" autocomplete="off" @attributes="InputAttributes" />
|
||||||
@if (_results != null)
|
@if (_results != null)
|
||||||
{
|
{
|
||||||
<select class="form-select" style="position: relative;" value="@Value" size="@Rows" @onkeyup="OnKeyUp" @onchange="(e => OnChange(e))">
|
<select class="form-select" style="position: relative;" value="@Value" size="@Rows" @onkeyup="OnKeyUp" @onchange="(e => OnChange(e))">
|
||||||
@ -29,27 +29,48 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
Dictionary<string, string> _results;
|
Dictionary<string, string> _results;
|
||||||
|
Dictionary<string, object> InputAttributes { get; set; } = new();
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public Func<string, Task<Dictionary<string, string>>> OnSearch { get; set; } // required - an async delegate method which accepts a filter string parameter and returns a dictionary
|
public Func<string, Task<Dictionary<string, string>>> OnSearch { get; set; } // required - an async delegate method which accepts a filter string parameter and returns a dictionary
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public int Characters { get; set; } = 3; // optional - number of characters before search is initiated
|
public int Characters { get; set; } = 3; // optional - number of characters before search is initiated
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public int Rows { get; set; } = 3; // optional - number of result rows to display
|
public int Rows { get; set; } = 3; // optional - number of result rows to display
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Placeholder { get; set; } // optional - placeholder input text
|
public string Placeholder { get; set; } // optional - placeholder input text
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Value { get; set; } // value of item selected
|
public string Value { get; set; } // value of item selected
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Key { get; set; } // key of item selected
|
public string Key { get; set; } // key of item selected
|
||||||
|
|
||||||
private async Task OnInput(ChangeEventArgs e)
|
[Parameter]
|
||||||
|
public bool Required { get; set; } // optional - if the item is required
|
||||||
|
|
||||||
|
protected override void OnParametersSet()
|
||||||
|
{
|
||||||
|
if (Required)
|
||||||
|
{
|
||||||
|
if (!InputAttributes.ContainsKey(nameof(Required)))
|
||||||
|
{
|
||||||
|
InputAttributes.Add(nameof(Required), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (InputAttributes.ContainsKey(nameof(Required)))
|
||||||
|
{
|
||||||
|
InputAttributes.Remove(nameof(Required));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private async Task OnInput(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
Value = e.Value?.ToString();
|
Value = e.Value?.ToString();
|
||||||
if (Value?.Length >= Characters)
|
if (Value?.Length >= Characters)
|
||||||
|
@ -168,8 +168,6 @@
|
|||||||
ShowSuccess = true;
|
ShowSuccess = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_folders = await FolderService.GetFoldersAsync(ModuleState.SiteId);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Folder) && Folder != Constants.PackagesFolder)
|
if (!string.IsNullOrEmpty(Folder) && Folder != Constants.PackagesFolder)
|
||||||
{
|
{
|
||||||
Folder folder = await FolderService.GetFolderAsync(ModuleState.SiteId, Folder);
|
Folder folder = await FolderService.GetFolderAsync(ModuleState.SiteId, Folder);
|
||||||
@ -185,6 +183,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ShowFolders)
|
||||||
|
{
|
||||||
|
_folders = await FolderService.GetFoldersAsync(ModuleState.SiteId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (FolderId != -1)
|
||||||
|
{
|
||||||
|
var folder = await FolderService.GetFolderAsync(FolderId);
|
||||||
|
if (folder != null)
|
||||||
|
{
|
||||||
|
_folders = new List<Folder> { folder };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (FileId != -1)
|
if (FileId != -1)
|
||||||
{
|
{
|
||||||
File file = await FileService.GetFileAsync(FileId);
|
File file = await FileService.GetFileAsync(FileId);
|
||||||
@ -358,10 +372,21 @@
|
|||||||
attempts += 1;
|
attempts += 1;
|
||||||
Thread.Sleep(1000 * attempts); // progressive retry
|
Thread.Sleep(1000 * attempts); // progressive retry
|
||||||
|
|
||||||
var file = await FileService.GetFileAsync(int.Parse(folder), uploads[upload]);
|
if (Folder == Constants.PackagesFolder)
|
||||||
if (file != null)
|
|
||||||
{
|
{
|
||||||
success = true;
|
var files = await FileService.GetFilesAsync(folder);
|
||||||
|
if (files != null && files.Any(item => item.Name == uploads[upload]))
|
||||||
|
{
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var file = await FileService.GetFileAsync(int.Parse(folder), uploads[upload]);
|
||||||
|
if (file != null)
|
||||||
|
{
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (success)
|
if (success)
|
||||||
|
@ -42,6 +42,8 @@
|
|||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
|
base.OnParametersSet(); // must be included to call method in LocalizableComponent
|
||||||
|
|
||||||
_heading = !string.IsNullOrEmpty(Heading) ? Localize(nameof(Heading), Heading) : Localize(nameof(Name), Name);
|
_heading = !string.IsNullOrEmpty(Heading) ? Localize(nameof(Heading), Heading) : Localize(nameof(Name), Name);
|
||||||
_expanded = (!string.IsNullOrEmpty(Expanded)) ? Expanded.ToLower() : "false";
|
_expanded = (!string.IsNullOrEmpty(Expanded)) ? Expanded.ToLower() : "false";
|
||||||
if (_expanded == "true") { _show = "show"; }
|
if (_expanded == "true") { _show = "show"; }
|
||||||
|
@ -68,6 +68,12 @@
|
|||||||
private List<Models.HtmlText> _htmltexts;
|
private List<Models.HtmlText> _htmltexts;
|
||||||
private string _view = "";
|
private string _view = "";
|
||||||
|
|
||||||
|
protected override void OnParametersSet()
|
||||||
|
{
|
||||||
|
base.OnParametersSet();
|
||||||
|
base.SetModuleTitle(Localizer["ModuleTitle.Text"]);
|
||||||
|
}
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
<Version>4.0.1</Version>
|
<Version>4.0.2</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.1</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.2</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<RootNamespace>Oqtane</RootNamespace>
|
<RootNamespace>Oqtane</RootNamespace>
|
||||||
|
@ -1,19 +1,23 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.Loader;
|
using System.Runtime.Loader;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||||
using Microsoft.AspNetCore.Localization;
|
using Microsoft.AspNetCore.Localization;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.JSInterop;
|
using Microsoft.JSInterop;
|
||||||
using Oqtane.Documentation;
|
using Oqtane.Documentation;
|
||||||
|
using Oqtane.Models;
|
||||||
using Oqtane.Modules;
|
using Oqtane.Modules;
|
||||||
using Oqtane.Services;
|
using Oqtane.Services;
|
||||||
using Oqtane.UI;
|
using Oqtane.UI;
|
||||||
@ -65,6 +69,14 @@ namespace Oqtane.Client
|
|||||||
|
|
||||||
private static async Task LoadClientAssemblies(HttpClient http, IServiceProvider serviceProvider)
|
private static async Task LoadClientAssemblies(HttpClient http, IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
|
// get alias
|
||||||
|
var navigationManager = serviceProvider.GetRequiredService<NavigationManager>();
|
||||||
|
var urlpath = GetUrlPath(navigationManager.Uri);
|
||||||
|
var json = await http.GetStringAsync($"api/Installation/installed/?path={WebUtility.UrlEncode(urlpath)}");
|
||||||
|
var installation = JsonSerializer.Deserialize<Installation>(json, new JsonSerializerOptions(JsonSerializerDefaults.Web));
|
||||||
|
urlpath = installation.Alias.Path;
|
||||||
|
urlpath = (!string.IsNullOrEmpty(urlpath)) ? urlpath + "/" : urlpath;
|
||||||
|
|
||||||
var dlls = new Dictionary<string, byte[]>();
|
var dlls = new Dictionary<string, byte[]>();
|
||||||
var pdbs = new Dictionary<string, byte[]>();
|
var pdbs = new Dictionary<string, byte[]>();
|
||||||
var list = new List<string>();
|
var list = new List<string>();
|
||||||
@ -76,7 +88,7 @@ namespace Oqtane.Client
|
|||||||
if (files.Count() != 0)
|
if (files.Count() != 0)
|
||||||
{
|
{
|
||||||
// get list of assemblies from server
|
// get list of assemblies from server
|
||||||
var json = await http.GetStringAsync("/api/Installation/list");
|
json = await http.GetStringAsync($"{urlpath}api/Installation/list");
|
||||||
var assemblies = JsonSerializer.Deserialize<List<string>>(json);
|
var assemblies = JsonSerializer.Deserialize<List<string>>(json);
|
||||||
|
|
||||||
// determine which assemblies need to be downloaded
|
// determine which assemblies need to be downloaded
|
||||||
@ -138,7 +150,7 @@ namespace Oqtane.Client
|
|||||||
if (list.Count != 0)
|
if (list.Count != 0)
|
||||||
{
|
{
|
||||||
// get assemblies from server and load into client app domain
|
// get assemblies from server and load into client app domain
|
||||||
var zip = await http.GetByteArrayAsync($"/api/Installation/load?list=" + string.Join(",", list));
|
var zip = await http.GetByteArrayAsync($"{urlpath}api/Installation/load?list=" + string.Join(",", list));
|
||||||
|
|
||||||
// asemblies and debug symbols are packaged in a zip file
|
// asemblies and debug symbols are packaged in a zip file
|
||||||
using (ZipArchive archive = new ZipArchive(new MemoryStream(zip)))
|
using (ZipArchive archive = new ZipArchive(new MemoryStream(zip)))
|
||||||
@ -254,5 +266,10 @@ namespace Oqtane.Client
|
|||||||
CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
|
CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
|
||||||
CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;
|
CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GetUrlPath(string url)
|
||||||
|
{
|
||||||
|
return new Uri(url).AbsolutePath.Substring(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,4 +162,7 @@
|
|||||||
<data name="Name.Text" xml:space="preserve">
|
<data name="Name.Text" xml:space="preserve">
|
||||||
<value>Name:</value>
|
<value>Name:</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="DownloadFiles.Heading" xml:space="preserve">
|
||||||
|
<value>Download Files</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -150,4 +150,7 @@
|
|||||||
<data name="Description.Text" xml:space="preserve">
|
<data name="Description.Text" xml:space="preserve">
|
||||||
<value>Description:</value>
|
<value>Description:</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ModuleTitle.Text" xml:space="preserve">
|
||||||
|
<value>File Management</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -183,4 +183,16 @@
|
|||||||
<data name="ImageSizes.Text" xml:space="preserve">
|
<data name="ImageSizes.Text" xml:space="preserve">
|
||||||
<value>Image Sizes:</value>
|
<value>Image Sizes:</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="FolderManagement.Title" xml:space="preserve">
|
||||||
|
<value>Folder Management!</value>
|
||||||
|
</data>
|
||||||
|
<data name="Private" xml:space="preserve">
|
||||||
|
<value>Private</value>
|
||||||
|
</data>
|
||||||
|
<data name="Public" xml:space="preserve">
|
||||||
|
<value>Public</value>
|
||||||
|
</data>
|
||||||
|
<data name="ModuleTitle.Text" xml:space="preserve">
|
||||||
|
<value>Folder Management</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -195,4 +195,7 @@
|
|||||||
<data name="Message.NoJobs" xml:space="preserve">
|
<data name="Message.NoJobs" xml:space="preserve">
|
||||||
<value>Please Note That After An Initial Installation You Must <a href={0}>Restart</a> The Application In Order To Activate The Default Scheduled Jobs.</value>
|
<value>Please Note That After An Initial Installation You Must <a href={0}>Restart</a> The Application In Order To Activate The Default Scheduled Jobs.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Refresh.Text" xml:space="preserve">
|
||||||
|
<value>Refresh</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -136,9 +136,12 @@
|
|||||||
<value>No Modules Match The Criteria Provided Or Package Service Is Disabled</value>
|
<value>No Modules Match The Criteria Provided Or Package Service Is Disabled</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Download.Heading" xml:space="preserve">
|
<data name="Download.Heading" xml:space="preserve">
|
||||||
<value>Download</value>
|
<value>Marketplace</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Upload.Heading" xml:space="preserve">
|
<data name="Upload.Heading" xml:space="preserve">
|
||||||
<value>Upload</value>
|
<value>Upload</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Product.Text" xml:space="preserve">
|
||||||
|
<value>Product</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -144,6 +144,9 @@
|
|||||||
<data name="DeleteModule.Header" xml:space="preserve">
|
<data name="DeleteModule.Header" xml:space="preserve">
|
||||||
<value>Delete Module</value>
|
<value>Delete Module</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="DeleteModule.Text" xml:space="preserve">
|
||||||
|
<value>Delete</value>
|
||||||
|
</data>
|
||||||
<data name="InUse" xml:space="preserve">
|
<data name="InUse" xml:space="preserve">
|
||||||
<value>In Use?</value>
|
<value>In Use?</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -132,4 +132,7 @@
|
|||||||
<data name="Success.Content.Export" xml:space="preserve">
|
<data name="Success.Content.Export" xml:space="preserve">
|
||||||
<value>Content Exported Successfully</value>
|
<value>Content Exported Successfully</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ModuleTitle.Text" xml:space="preserve">
|
||||||
|
<value>Export Content</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -138,4 +138,7 @@
|
|||||||
<data name="Message.Required.ImportContent" xml:space="preserve">
|
<data name="Message.Required.ImportContent" xml:space="preserve">
|
||||||
<value>You Must Enter Some Content To Import</value>
|
<value>You Must Enter Some Content To Import</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ModuleTitle.Text" xml:space="preserve">
|
||||||
|
<value>Import Content</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -156,4 +156,7 @@
|
|||||||
<data name="Module.Text" xml:space="preserve">
|
<data name="Module.Text" xml:space="preserve">
|
||||||
<value>Module:</value>
|
<value>Module:</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ModuleTitle.Text" xml:space="preserve">
|
||||||
|
<value>Module Settings</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -249,4 +249,10 @@
|
|||||||
<data name="ThemeChanged.Message" xml:space="preserve">
|
<data name="ThemeChanged.Message" xml:space="preserve">
|
||||||
<value>Please Note That Overriding The Default Site Theme With An Unrelated Page Theme May Result In Compatibility Issues For Your Site</value>
|
<value>Please Note That Overriding The Default Site Theme With An Unrelated Page Theme May Result In Compatibility Issues For Your Site</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Permissions.Heading" xml:space="preserve">
|
||||||
|
<value>Permissions</value>
|
||||||
|
</data>
|
||||||
|
<data name="Theme.Heading" xml:space="preserve">
|
||||||
|
<value>Theme Settings</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -120,9 +120,15 @@
|
|||||||
<data name="DeleteModule.Header" xml:space="preserve">
|
<data name="DeleteModule.Header" xml:space="preserve">
|
||||||
<value>Delete Module</value>
|
<value>Delete Module</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="DeleteModule.Text" xml:space="preserve">
|
||||||
|
<value>Delete</value>
|
||||||
|
</data>
|
||||||
<data name="DeletePage.Header" xml:space="preserve">
|
<data name="DeletePage.Header" xml:space="preserve">
|
||||||
<value>Delete Page</value>
|
<value>Delete Page</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="DeletePage.Text" xml:space="preserve">
|
||||||
|
<value>Delete</value>
|
||||||
|
</data>
|
||||||
<data name="NoPage.Deleted" xml:space="preserve">
|
<data name="NoPage.Deleted" xml:space="preserve">
|
||||||
<value>No Deleted Pages</value>
|
<value>No Deleted Pages</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -135,4 +135,10 @@
|
|||||||
<data name="Search.NoResults" xml:space="preserve">
|
<data name="Search.NoResults" xml:space="preserve">
|
||||||
<value>No Themes Match The Criteria Provided Or Package Service Is Disabled</value>
|
<value>No Themes Match The Criteria Provided Or Package Service Is Disabled</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Download.Heading" xml:space="preserve">
|
||||||
|
<value>Marketplace</value>
|
||||||
|
</data>
|
||||||
|
<data name="Upload.Heading" xml:space="preserve">
|
||||||
|
<value>Upload</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -141,6 +141,9 @@
|
|||||||
<data name="CreateTheme.Text" xml:space="preserve">
|
<data name="CreateTheme.Text" xml:space="preserve">
|
||||||
<value>Create Theme</value>
|
<value>Create Theme</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="InstallTheme.Text" xml:space="preserve">
|
||||||
|
<value>Install Theme</value>
|
||||||
|
</data>
|
||||||
<data name="ViewTheme.Text" xml:space="preserve">
|
<data name="ViewTheme.Text" xml:space="preserve">
|
||||||
<value>View</value>
|
<value>View</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -141,4 +141,10 @@
|
|||||||
<data name="Upload.Heading" xml:space="preserve">
|
<data name="Upload.Heading" xml:space="preserve">
|
||||||
<value>Upload</value>
|
<value>Upload</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Message.Text" xml:space="preserve">
|
||||||
|
<value>Framework Is Already Up To Date</value>
|
||||||
|
</data>
|
||||||
|
<data name="MessgeUpgrade.Text" xml:space="preserve">
|
||||||
|
<value>Upload A Framework Package (Oqtane.Framework.version.nupkg) And Then Select Upgrade</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -141,4 +141,7 @@
|
|||||||
<data name="Subject.Text" xml:space="preserve">
|
<data name="Subject.Text" xml:space="preserve">
|
||||||
<value>Subject: </value>
|
<value>Subject: </value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ModuleTitle.Text" xml:space="preserve">
|
||||||
|
<value>Send Notification</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -144,4 +144,7 @@
|
|||||||
<data name="OriginalMessage" xml:space="preserve">
|
<data name="OriginalMessage" xml:space="preserve">
|
||||||
<value>Original Message</value>
|
<value>Original Message</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ModuleTitle.Text" xml:space="preserve">
|
||||||
|
<value>View Notification</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -156,6 +156,9 @@
|
|||||||
<data name="Message.Content.Restored" xml:space="preserve">
|
<data name="Message.Content.Restored" xml:space="preserve">
|
||||||
<value>Version Restored</value>
|
<value>Version Restored</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ModuleTitle.Text" xml:space="preserve">
|
||||||
|
<value>Edit Html/Text</value>
|
||||||
|
</data>
|
||||||
<data name="Restore.Header" xml:space="preserve">
|
<data name="Restore.Header" xml:space="preserve">
|
||||||
<value>Restore Version</value>
|
<value>Restore Version</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -223,13 +223,13 @@
|
|||||||
<value>by</value>
|
<value>by</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Search.Downloads" xml:space="preserve">
|
<data name="Search.Downloads" xml:space="preserve">
|
||||||
<value>downloads</value>
|
<value>Downloads</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Search.Released" xml:space="preserve">
|
<data name="Search.Released" xml:space="preserve">
|
||||||
<value>released</value>
|
<value>Released</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Search.Version" xml:space="preserve">
|
<data name="Search.Version" xml:space="preserve">
|
||||||
<value>version</value>
|
<value>Version</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Edit" xml:space="preserve">
|
<data name="Edit" xml:space="preserve">
|
||||||
<value>Edit</value>
|
<value>Edit</value>
|
||||||
@ -277,19 +277,19 @@
|
|||||||
<value>Installed Version</value>
|
<value>Installed Version</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Search.Source" xml:space="preserve">
|
<data name="Search.Source" xml:space="preserve">
|
||||||
<value>source</value>
|
<value>Source</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.InfoRequired" xml:space="preserve">
|
<data name="Message.InfoRequired" xml:space="preserve">
|
||||||
<value>Please Provide All Required Information</value>
|
<value>Please Provide All Required Information</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Free" xml:space="preserve">
|
<data name="Free" xml:space="preserve">
|
||||||
<value>Free</value>
|
<value>Open Source</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Paid" xml:space="preserve">
|
<data name="Paid" xml:space="preserve">
|
||||||
<value>Paid</value>
|
<value>Commercial</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Search.Price" xml:space="preserve">
|
<data name="Search.Price" xml:space="preserve">
|
||||||
<value>price</value>
|
<value>Price</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Accept" xml:space="preserve">
|
<data name="Accept" xml:space="preserve">
|
||||||
<value>Accept</value>
|
<value>Accept</value>
|
||||||
@ -390,4 +390,19 @@
|
|||||||
<data name="Support" xml:space="preserve">
|
<data name="Support" xml:space="preserve">
|
||||||
<value>Support</value>
|
<value>Support</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Search.Alphabetical" xml:space="preserve">
|
||||||
|
<value>Alphabetical</value>
|
||||||
|
</data>
|
||||||
|
<data name="Buy" xml:space="preserve">
|
||||||
|
<value>Buy Now</value>
|
||||||
|
</data>
|
||||||
|
<data name="Search.Popularity" xml:space="preserve">
|
||||||
|
<value>Popularity</value>
|
||||||
|
</data>
|
||||||
|
<data name="Search.Results" xml:space="preserve">
|
||||||
|
<value>Results</value>
|
||||||
|
</data>
|
||||||
|
<data name="Search.RecentlyReleased" xml:space="preserve">
|
||||||
|
<value>Recently Released</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -22,7 +22,7 @@ namespace Oqtane.Services
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<List<Alias>> GetAliasesAsync()
|
public async Task<List<Alias>> GetAliasesAsync()
|
||||||
{
|
{
|
||||||
List<Alias> aliases = await GetJsonAsync<List<Alias>>(ApiUrl);
|
List<Alias> aliases = await GetJsonAsync<List<Alias>>(ApiUrl, Enumerable.Empty<Alias>().ToList());
|
||||||
return aliases.OrderBy(item => item.Name).ToList();
|
return aliases.OrderBy(item => item.Name).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ using Oqtane.Shared;
|
|||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using System;
|
using System;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Oqtane.Services
|
namespace Oqtane.Services
|
||||||
{
|
{
|
||||||
@ -14,11 +15,13 @@ namespace Oqtane.Services
|
|||||||
{
|
{
|
||||||
private readonly NavigationManager _navigationManager;
|
private readonly NavigationManager _navigationManager;
|
||||||
private readonly SiteState _siteState;
|
private readonly SiteState _siteState;
|
||||||
|
private readonly HttpClient _http;
|
||||||
|
|
||||||
public InstallationService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http, siteState)
|
public InstallationService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http, siteState)
|
||||||
{
|
{
|
||||||
_navigationManager = navigationManager;
|
_navigationManager = navigationManager;
|
||||||
_siteState = siteState;
|
_siteState = siteState;
|
||||||
|
_http = http;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ApiUrl => (_siteState.Alias == null)
|
private string ApiUrl => (_siteState.Alias == null)
|
||||||
@ -27,7 +30,15 @@ namespace Oqtane.Services
|
|||||||
|
|
||||||
public async Task<Installation> IsInstalled()
|
public async Task<Installation> IsInstalled()
|
||||||
{
|
{
|
||||||
var path = new Uri(_navigationManager.Uri).LocalPath.Substring(1);
|
var path = "";
|
||||||
|
if (_http.DefaultRequestHeaders.UserAgent.ToString().Contains(Constants.MauiUserAgent))
|
||||||
|
{
|
||||||
|
path = _http.DefaultRequestHeaders.GetValues(Constants.MauiAliasPath).First();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
path = new Uri(_navigationManager.Uri).LocalPath.Substring(1);
|
||||||
|
}
|
||||||
return await GetJsonAsync<Installation>($"{ApiUrl}/installed/?path={WebUtility.UrlEncode(path)}");
|
return await GetJsonAsync<Installation>($"{ApiUrl}/installed/?path={WebUtility.UrlEncode(path)}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,6 @@ namespace Oqtane.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="lastSyncDate"></param>
|
/// <param name="lastSyncDate"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<Sync> GetSyncAsync(DateTime lastSyncDate);
|
Task<Sync> GetSyncEventsAsync(DateTime lastSyncDate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,10 +145,19 @@ namespace Oqtane.Services
|
|||||||
{
|
{
|
||||||
return await response.Content.ReadFromJsonAsync<T>();
|
return await response.Content.ReadFromJsonAsync<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected async Task<T> GetJsonAsync<T>(string uri, T defaultResult)
|
||||||
|
{
|
||||||
|
var response = await GetHttpClient().GetAsync(uri, HttpCompletionOption.ResponseHeadersRead, CancellationToken.None);
|
||||||
|
if (await CheckResponse(response, uri) && ValidateJsonContent(response.Content))
|
||||||
|
{
|
||||||
|
return await response.Content.ReadFromJsonAsync<T>();
|
||||||
|
}
|
||||||
|
return defaultResult;
|
||||||
|
}
|
||||||
|
|
||||||
protected async Task PutAsync(string uri)
|
protected async Task PutAsync(string uri)
|
||||||
{
|
{
|
||||||
var response = await GetHttpClient().PutAsync(uri, null);
|
var response = await GetHttpClient().PutAsync(uri, null);
|
||||||
@ -202,17 +211,27 @@ namespace Oqtane.Services
|
|||||||
|
|
||||||
private async Task<bool> CheckResponse(HttpResponseMessage response, string uri)
|
private async Task<bool> CheckResponse(HttpResponseMessage response, string uri)
|
||||||
{
|
{
|
||||||
if (response.IsSuccessStatusCode && uri.Contains("/api/") && !response.RequestMessage.RequestUri.AbsolutePath.Contains("/api/"))
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
await Log(uri, response.RequestMessage.Method.ToString(), response.StatusCode.ToString(), "Request {Uri} Not Mapped To An API Controller Method", uri);
|
// if response from api call is not from an api url then the route was not mapped correctly
|
||||||
|
if (uri.Contains("/api/") && !response.RequestMessage.RequestUri.AbsolutePath.Contains("/api/"))
|
||||||
|
{
|
||||||
|
await Log(uri, response.RequestMessage.Method.ToString(), response.StatusCode.ToString(), "Request {Uri} Not Mapped To An API Controller Method", uri);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (response.StatusCode != HttpStatusCode.NoContent && response.StatusCode != HttpStatusCode.NotFound)
|
||||||
|
{
|
||||||
|
await Log(uri, response.RequestMessage.Method.ToString(), response.StatusCode.ToString(), "Request {Uri} Failed With Status {StatusCode} - {ReasonPhrase}", uri, response.StatusCode, response.ReasonPhrase);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (response.IsSuccessStatusCode) return true;
|
|
||||||
if (response.StatusCode != HttpStatusCode.NoContent && response.StatusCode != HttpStatusCode.NotFound)
|
|
||||||
{
|
|
||||||
await Log(uri, response.RequestMessage.Method.ToString(), response.StatusCode.ToString(), "Request {Uri} Failed With Status {StatusCode} - {ReasonPhrase}", uri, response.StatusCode, response.ReasonPhrase);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool ValidateJsonContent(HttpContent content)
|
private static bool ValidateJsonContent(HttpContent content)
|
||||||
|
@ -16,7 +16,7 @@ namespace Oqtane.Services
|
|||||||
private string ApiUrl => CreateApiUrl("Sync");
|
private string ApiUrl => CreateApiUrl("Sync");
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<Sync> GetSyncAsync(DateTime lastSyncDate)
|
public async Task<Sync> GetSyncEventsAsync(DateTime lastSyncDate)
|
||||||
{
|
{
|
||||||
return await GetJsonAsync<Sync>($"{ApiUrl}/{lastSyncDate.ToString("yyyyMMddHHmmssfff")}");
|
return await GetJsonAsync<Sync>($"{ApiUrl}/{lastSyncDate.ToString("yyyyMMddHHmmssfff")}");
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
@namespace Oqtane.Themes.Controls
|
@namespace Oqtane.Themes.Controls
|
||||||
@inherits ContainerBase
|
@inherits ContainerBase
|
||||||
@attribute [OqtaneIgnore]
|
@attribute [OqtaneIgnore]
|
||||||
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
<span class="app-moduletitle">
|
<span class="app-moduletitle">
|
||||||
@((MarkupString)title)
|
@((MarkupString)title)
|
||||||
@ -23,7 +24,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
title = ModuleState.Title;
|
title = SharedLocalizer[ModuleState.Title];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,12 +93,12 @@
|
|||||||
[SuppressMessage("ReSharper", "StringIndexOfIsCultureSpecific.1")]
|
[SuppressMessage("ReSharper", "StringIndexOfIsCultureSpecific.1")]
|
||||||
private async Task Refresh()
|
private async Task Refresh()
|
||||||
{
|
{
|
||||||
Site site;
|
Site site = null;
|
||||||
Page page;
|
Page page = null;
|
||||||
User user = null;
|
User user = null;
|
||||||
var editmode = false;
|
var editmode = false;
|
||||||
var refresh = false;
|
var refresh = false;
|
||||||
var lastsyncdate = DateTime.UtcNow.AddHours(-1);
|
var lastsyncdate = DateTime.MinValue;
|
||||||
var runtime = (Shared.Runtime)Enum.Parse(typeof(Shared.Runtime), Runtime);
|
var runtime = (Shared.Runtime)Enum.Parse(typeof(Shared.Runtime), Runtime);
|
||||||
_error = "";
|
_error = "";
|
||||||
|
|
||||||
@ -112,8 +112,8 @@
|
|||||||
returnurl = WebUtility.UrlDecode(querystring["returnurl"]);
|
returnurl = WebUtility.UrlDecode(querystring["returnurl"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// reload the client application from the server if there is a forced reload or the user navigated to a site with a different alias
|
// reload the client application from the server if there is a forced reload
|
||||||
if (querystring.ContainsKey("reload") || (!NavigationManager.ToBaseRelativePath(_absoluteUri).ToLower().StartsWith(SiteState.Alias.Path.ToLower()) && !string.IsNullOrEmpty(SiteState.Alias.Path)))
|
if (querystring.ContainsKey("reload"))
|
||||||
{
|
{
|
||||||
if (querystring.ContainsKey("reload") && querystring["reload"] == "post")
|
if (querystring.ContainsKey("reload") && querystring["reload"] == "post")
|
||||||
{
|
{
|
||||||
@ -126,7 +126,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NavigationManager.NavigateTo(_absoluteUri.Replace("?reload", ""), true);
|
NavigationManager.NavigateTo(_absoluteUri.Replace("?reload", "").Replace("&reload", ""), true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,28 +166,36 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// process any sync events
|
// process any sync events
|
||||||
var sync = await SyncService.GetSyncAsync(lastsyncdate);
|
var sync = await SyncService.GetSyncEventsAsync(lastsyncdate);
|
||||||
lastsyncdate = sync.SyncDate;
|
lastsyncdate = sync.SyncDate;
|
||||||
if (sync.SyncEvents.Any())
|
if (sync.SyncEvents.Any())
|
||||||
{
|
{
|
||||||
// reload client application if server was restarted or site runtime/rendermode was modified
|
// reload client application if server was restarted
|
||||||
if (PageState != null && sync.SyncEvents.Exists(item => (item.Action == SyncEventActions.Reload)))
|
if (sync.SyncEvents.Exists(item => item.Action == SyncEventActions.Reload && item.EntityName == EntityNames.Host))
|
||||||
{
|
{
|
||||||
NavigationManager.NavigateTo(_absoluteUri, true);
|
NavigationManager.NavigateTo(_absoluteUri, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// when site information has changed the PageState needs to be refreshed
|
// reload client application if site runtime/rendermode was modified
|
||||||
if (sync.SyncEvents.Exists(item => item.EntityName == EntityNames.Site && item.EntityId == SiteState.Alias.SiteId))
|
if (sync.SyncEvents.Exists(item => item.Action == SyncEventActions.Reload && item.EntityName == EntityNames.Site && item.EntityId == SiteState.Alias.SiteId))
|
||||||
{
|
{
|
||||||
refresh = true;
|
NavigationManager.NavigateTo(_absoluteUri, true);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
// when user information has changed the PageState needs to be refreshed as the list of pages/modules may have changed
|
// reload client application if current user auth information has changed
|
||||||
if (user != null && sync.SyncEvents.Exists(item => item.EntityName == EntityNames.User && item.EntityId == user.UserId))
|
if (user != null && sync.SyncEvents.Exists(item => item.Action == SyncEventActions.Reload && item.EntityName == EntityNames.User && item.EntityId == user.UserId))
|
||||||
|
{
|
||||||
|
NavigationManager.NavigateTo(_absoluteUri, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// refresh PageState when site information has changed
|
||||||
|
if (sync.SyncEvents.Exists(item => item.Action == SyncEventActions.Refresh && item.EntityName == EntityNames.Site && item.EntityId == SiteState.Alias.SiteId))
|
||||||
{
|
{
|
||||||
refresh = true;
|
refresh = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get site
|
||||||
if (PageState == null || refresh || PageState.Alias.SiteId != SiteState.Alias.SiteId)
|
if (PageState == null || refresh || PageState.Alias.SiteId != SiteState.Alias.SiteId)
|
||||||
{
|
{
|
||||||
site = await SiteService.GetSiteAsync(SiteState.Alias.SiteId);
|
site = await SiteService.GetSiteAsync(SiteState.Alias.SiteId);
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
var elements = (">" + content.Replace("\n", "") + "<").Split("><");
|
var elements = (">" + content.Replace("\n", "") + "<").Split("><");
|
||||||
foreach (var element in elements)
|
foreach (var element in elements)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(element) && !element.Contains("script"))
|
if (!string.IsNullOrEmpty(element) && !element.ToLower().StartsWith("script"))
|
||||||
{
|
{
|
||||||
if (!headcontent.Contains("<" + element + ">"))
|
if (!headcontent.Contains("<" + element + ">"))
|
||||||
{
|
{
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<Version>4.0.1</Version>
|
<Version>4.0.2</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.1</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.2</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Database.MySQL</id>
|
<id>Oqtane.Database.MySQL</id>
|
||||||
<version>4.0.1</version>
|
<version>4.0.2</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane MySQL Provider</title>
|
<title>Oqtane MySQL Provider</title>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.1</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.2</releaseNotes>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<Version>4.0.1</Version>
|
<Version>4.0.2</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.1</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.2</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Database.PostgreSQL</id>
|
<id>Oqtane.Database.PostgreSQL</id>
|
||||||
<version>4.0.1</version>
|
<version>4.0.2</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane PostgreSQL Provider</title>
|
<title>Oqtane PostgreSQL Provider</title>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.1</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.2</releaseNotes>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<Version>4.0.1</Version>
|
<Version>4.0.2</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.1</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.2</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Database.SqlServer</id>
|
<id>Oqtane.Database.SqlServer</id>
|
||||||
<version>4.0.1</version>
|
<version>4.0.2</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane SQL Server Provider</title>
|
<title>Oqtane SQL Server Provider</title>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.1</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.2</releaseNotes>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<Version>4.0.1</Version>
|
<Version>4.0.2</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.1</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.2</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Database.Sqlite</id>
|
<id>Oqtane.Database.Sqlite</id>
|
||||||
<version>4.0.1</version>
|
<version>4.0.2</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane SQLite Provider</title>
|
<title>Oqtane SQLite Provider</title>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.1</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.2</releaseNotes>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
@ -1,18 +1,52 @@
|
|||||||
<DynamicComponent Type="@ComponentType" Parameters="@Parameters"></DynamicComponent>
|
@using System.Text.Json;
|
||||||
|
@using System.Text.Json.Nodes;
|
||||||
|
|
||||||
@code {
|
@if (string.IsNullOrEmpty(message))
|
||||||
Type ComponentType = Type.GetType("Oqtane.App, Oqtane.Client");
|
{
|
||||||
private IDictionary<string, object> Parameters { get; set; }
|
<DynamicComponent Type="@ComponentType" Parameters="@Parameters"></DynamicComponent>
|
||||||
|
}
|
||||||
protected override void OnInitialized()
|
else
|
||||||
{
|
{
|
||||||
Parameters = new Dictionary<string, object>();
|
<br /><br /><center>@message</center>
|
||||||
Parameters.Add(new KeyValuePair<string, object>("AntiForgeryToken", ""));
|
}
|
||||||
Parameters.Add(new KeyValuePair<string, object>("Runtime", "Hybrid"));
|
|
||||||
Parameters.Add(new KeyValuePair<string, object>("RenderMode", "Hybrid"));
|
@code {
|
||||||
Parameters.Add(new KeyValuePair<string, object>("VisitorId", -1));
|
Type ComponentType = Type.GetType("Oqtane.App, Oqtane.Client");
|
||||||
Parameters.Add(new KeyValuePair<string, object>("RemoteIPAddress", ""));
|
private IDictionary<string, object> Parameters { get; set; }
|
||||||
Parameters.Add(new KeyValuePair<string, object>("AuthorizationToken", ""));
|
private string message = "";
|
||||||
}
|
|
||||||
|
protected override void OnInitialized()
|
||||||
|
{
|
||||||
|
Parameters = new Dictionary<string, object>();
|
||||||
|
Parameters.Add(new KeyValuePair<string, object>("AntiForgeryToken", ""));
|
||||||
|
Parameters.Add(new KeyValuePair<string, object>("Runtime", "Hybrid"));
|
||||||
|
Parameters.Add(new KeyValuePair<string, object>("RenderMode", "Hybrid"));
|
||||||
|
Parameters.Add(new KeyValuePair<string, object>("VisitorId", -1));
|
||||||
|
Parameters.Add(new KeyValuePair<string, object>("RemoteIPAddress", ""));
|
||||||
|
Parameters.Add(new KeyValuePair<string, object>("AuthorizationToken", ""));
|
||||||
|
|
||||||
|
if (MauiConstants.UseAppSettings)
|
||||||
|
{
|
||||||
|
string file = Path.Combine(FileSystem.Current.AppDataDirectory, "appsettings.json");
|
||||||
|
if (File.Exists(file))
|
||||||
|
{
|
||||||
|
using FileStream stream = File.OpenRead(file);
|
||||||
|
using StreamReader reader = new StreamReader(stream);
|
||||||
|
var content = reader.ReadToEnd();
|
||||||
|
var obj = JsonSerializer.Deserialize<JsonObject>(content)!;
|
||||||
|
if (string.IsNullOrEmpty((string)obj["Url"]) && string.IsNullOrEmpty(MauiConstants.ApiUrl))
|
||||||
|
{
|
||||||
|
message = "You Must Set The Url In Either MauiConstants.cs Or " + file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(MauiConstants.ApiUrl))
|
||||||
|
{
|
||||||
|
message = "You Must Set The Url In MauiConstants.cs";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
13
Oqtane.Maui/MauiConstants.cs
Normal file
13
Oqtane.Maui/MauiConstants.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace Oqtane.Maui;
|
||||||
|
|
||||||
|
public static class MauiConstants
|
||||||
|
{
|
||||||
|
// the API service url (used as fallback if not set in appsettings.json)
|
||||||
|
public static string ApiUrl = "";
|
||||||
|
//public static string ApiUrl = "http://localhost:44357/"; // for local development (Oqtane.Server must be already running for MAUI client to connect)
|
||||||
|
//public static string apiurl = "http://localhost:44357/sitename/"; // local microsite example
|
||||||
|
//public static string apiurl = "https://www.dnfprojects.com/"; // for testing remote site
|
||||||
|
|
||||||
|
// specify if you wish to allow users to override the url via appsettings.json in the AppDataDirectory
|
||||||
|
public static bool UseAppSettings = true;
|
||||||
|
}
|
@ -6,20 +6,16 @@ using Oqtane.Modules;
|
|||||||
using Oqtane.Services;
|
using Oqtane.Services;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
|
||||||
namespace Oqtane.Maui;
|
namespace Oqtane.Maui;
|
||||||
|
|
||||||
public static class MauiProgram
|
public static class MauiProgram
|
||||||
{
|
{
|
||||||
// the API service url
|
|
||||||
//static string apiurl = "https://www.dnfprojects.com"; // for testing
|
|
||||||
static string apiurl = "http://localhost:44357"; // for local development (Oqtane.Server must be already running for MAUI client to connect)
|
|
||||||
|
|
||||||
public static MauiApp CreateMauiApp()
|
public static MauiApp CreateMauiApp()
|
||||||
{
|
{
|
||||||
var builder = MauiApp.CreateBuilder();
|
var builder = MauiApp.CreateBuilder();
|
||||||
builder
|
builder.UseMauiApp<App>()
|
||||||
.UseMauiApp<App>()
|
|
||||||
.ConfigureFonts(fonts =>
|
.ConfigureFonts(fonts =>
|
||||||
{
|
{
|
||||||
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
|
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
|
||||||
@ -28,15 +24,21 @@ public static class MauiProgram
|
|||||||
builder.Services.AddMauiBlazorWebView();
|
builder.Services.AddMauiBlazorWebView();
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
builder.Services.AddBlazorWebViewDeveloperTools();
|
builder.Services.AddBlazorWebViewDeveloperTools();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
var httpClient = new HttpClient { BaseAddress = new Uri(apiurl) };
|
var apiurl = LoadAppSettings();
|
||||||
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(Shared.Constants.MauiUserAgent);
|
|
||||||
builder.Services.AddSingleton(httpClient);
|
|
||||||
builder.Services.AddHttpClient(); // IHttpClientFactory for calling remote services via RemoteServiceBase
|
|
||||||
|
|
||||||
// dynamically load client assemblies
|
if (!string.IsNullOrEmpty(apiurl))
|
||||||
LoadClientAssemblies(httpClient);
|
{
|
||||||
|
var httpClient = new HttpClient { BaseAddress = new Uri(GetBaseUrl(apiurl)) };
|
||||||
|
httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(Shared.Constants.MauiUserAgent);
|
||||||
|
httpClient.DefaultRequestHeaders.Add(Shared.Constants.MauiAliasPath, GetUrlPath(apiurl).Replace("/", ""));
|
||||||
|
builder.Services.AddSingleton(httpClient);
|
||||||
|
builder.Services.AddHttpClient(); // IHttpClientFactory for calling remote services via RemoteServiceBase
|
||||||
|
|
||||||
|
// dynamically load client assemblies
|
||||||
|
LoadClientAssemblies(httpClient, apiurl);
|
||||||
|
}
|
||||||
|
|
||||||
// register localization services
|
// register localization services
|
||||||
builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");
|
builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");
|
||||||
@ -60,7 +62,37 @@ public static class MauiProgram
|
|||||||
return builder.Build();
|
return builder.Build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void LoadClientAssemblies(HttpClient http)
|
|
||||||
|
private static string LoadAppSettings()
|
||||||
|
{
|
||||||
|
var url = MauiConstants.ApiUrl;
|
||||||
|
if (MauiConstants.UseAppSettings)
|
||||||
|
{
|
||||||
|
string file = Path.Combine(FileSystem.Current.AppDataDirectory, "appsettings.json");
|
||||||
|
if (File.Exists(file))
|
||||||
|
{
|
||||||
|
using FileStream stream = File.OpenRead(file);
|
||||||
|
using StreamReader reader = new StreamReader(stream);
|
||||||
|
var content = reader.ReadToEnd();
|
||||||
|
var obj = JsonSerializer.Deserialize<JsonObject>(content)!;
|
||||||
|
if (!string.IsNullOrEmpty((string)obj["Url"]))
|
||||||
|
{
|
||||||
|
url = (string)obj["Url"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// create template appsettings.json file
|
||||||
|
using (StreamWriter writer = File.CreateText(file))
|
||||||
|
{
|
||||||
|
writer.WriteLine("{ \"Url\": \"\" }");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void LoadClientAssemblies(HttpClient http, string apiurl)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -84,7 +116,7 @@ public static class MauiProgram
|
|||||||
if (files.Count() != 0)
|
if (files.Count() != 0)
|
||||||
{
|
{
|
||||||
// get list of assemblies from server
|
// get list of assemblies from server
|
||||||
var json = Task.Run(() => http.GetStringAsync("/api/Installation/list")).GetAwaiter().GetResult();
|
var json = Task.Run(() => http.GetStringAsync($"{GetUrlPath(apiurl)}api/Installation/list")).GetAwaiter().GetResult();
|
||||||
var assemblies = JsonSerializer.Deserialize<List<string>>(json);
|
var assemblies = JsonSerializer.Deserialize<List<string>>(json);
|
||||||
|
|
||||||
// determine which assemblies need to be downloaded
|
// determine which assemblies need to be downloaded
|
||||||
@ -148,7 +180,7 @@ public static class MauiProgram
|
|||||||
if (list.Count != 0)
|
if (list.Count != 0)
|
||||||
{
|
{
|
||||||
// get assemblies from server
|
// get assemblies from server
|
||||||
var zip = Task.Run(() => http.GetByteArrayAsync("/api/Installation/load?list=" + string.Join(",", list))).GetAwaiter().GetResult();
|
var zip = Task.Run(() => http.GetByteArrayAsync($"{GetUrlPath(apiurl)}api/Installation/load?list=" + string.Join(",", list))).GetAwaiter().GetResult();
|
||||||
|
|
||||||
// asemblies and debug symbols are packaged in a zip file
|
// asemblies and debug symbols are packaged in a zip file
|
||||||
using (ZipArchive archive = new ZipArchive(new MemoryStream(zip)))
|
using (ZipArchive archive = new ZipArchive(new MemoryStream(zip)))
|
||||||
@ -199,7 +231,7 @@ public static class MauiProgram
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Debug.WriteLine($"Oqtane Error: Loading Client Assemblies {ex}");
|
Debug.WriteLine($"Error Loading Client Assemblies From {apiurl} - {ex}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,4 +277,17 @@ public static class MauiProgram
|
|||||||
// could not interrogate assembly - likely missing dependencies
|
// could not interrogate assembly - likely missing dependencies
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GetBaseUrl(string url)
|
||||||
|
{
|
||||||
|
var uri = new Uri(url);
|
||||||
|
return uri.Scheme + "://"+ uri.Authority + "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetUrlPath(string url)
|
||||||
|
{
|
||||||
|
var path = new Uri(url).AbsolutePath.Substring(1);
|
||||||
|
path = (!string.IsNullOrEmpty(path) && !path.EndsWith("/")) ? path + "/" : path;
|
||||||
|
return path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<!-- <TargetFrameworks>net7.0-android;net7.0-ios;net7.0-maccatalyst</TargetFrameworks> -->
|
<!-- <TargetFrameworks>net7.0-android;net7.0-ios;net7.0-maccatalyst</TargetFrameworks> -->
|
||||||
<!-- <TargetFrameworks>$(TargetFrameworks);net7.0-tizen</TargetFrameworks> -->
|
<!-- <TargetFrameworks>$(TargetFrameworks);net7.0-tizen</TargetFrameworks> -->
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<Version>4.0.1</Version>
|
<Version>4.0.2</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -14,7 +14,7 @@
|
|||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.1</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.2</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<RootNamespace>Oqtane.Maui</RootNamespace>
|
<RootNamespace>Oqtane.Maui</RootNamespace>
|
||||||
@ -31,7 +31,7 @@
|
|||||||
<ApplicationIdGuid>0E29FC31-1B83-48ED-B6E0-9F3C67B775D4</ApplicationIdGuid>
|
<ApplicationIdGuid>0E29FC31-1B83-48ED-B6E0-9F3C67B775D4</ApplicationIdGuid>
|
||||||
|
|
||||||
<!-- Versions -->
|
<!-- Versions -->
|
||||||
<ApplicationDisplayVersion>4.0.1</ApplicationDisplayVersion>
|
<ApplicationDisplayVersion>4.0.2</ApplicationDisplayVersion>
|
||||||
<ApplicationVersion>1</ApplicationVersion>
|
<ApplicationVersion>1</ApplicationVersion>
|
||||||
|
|
||||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">14.2</SupportedOSPlatformVersion>
|
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">14.2</SupportedOSPlatformVersion>
|
||||||
@ -44,7 +44,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<!-- App Icon -->
|
<!-- App Icon -->
|
||||||
<MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4" />
|
<MauiIcon Include="Resources\AppIcon\appicon.svg" />
|
||||||
|
|
||||||
<!-- Splash Screen -->
|
<!-- Splash Screen -->
|
||||||
<MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#512BD4" BaseSize="128,128" />
|
<MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#512BD4" BaseSize="128,128" />
|
||||||
|
@ -1,4 +1,19 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" standalone="no"?>
|
||||||
<svg width="456" height="456" viewBox="0 0 456 456" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||||
<rect x="0" y="0" width="456" height="456" fill="#512BD4" />
|
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||||
|
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="200.000000pt" height="200.000000pt" viewBox="0 0 200.000000 200.000000"
|
||||||
|
preserveAspectRatio="xMidYMid meet">
|
||||||
|
|
||||||
|
<g transform="translate(0.000000,200.000000) scale(0.100000,-0.100000)"
|
||||||
|
fill="#000000" stroke="none">
|
||||||
|
<path d="M994 1922 c-6 -4 -25 -50 -44 -102 -80 -218 -210 -455 -391 -712 -49
|
||||||
|
-70 -100 -151 -114 -180 -105 -226 -53 -507 126 -686 190 -188 468 -234 709
|
||||||
|
-116 104 51 223 170 274 274 84 172 86 367 7 532 -16 35 -72 122 -123 193 -52
|
||||||
|
72 -111 161 -133 198 -21 37 -42 67 -46 67 -3 0 -46 -61 -94 -136 l-88 -136
|
||||||
|
106 -156 c57 -87 110 -172 116 -191 16 -50 13 -150 -6 -207 -23 -69 -110 -155
|
||||||
|
-182 -179 -68 -22 -144 -22 -212 0 -74 25 -159 110 -183 183 -19 57 -22 148
|
||||||
|
-7 200 6 19 116 193 246 387 129 195 235 358 235 363 0 5 -22 56 -49 113 -27
|
||||||
|
57 -64 145 -81 196 -31 88 -46 109 -66 95z"/>
|
||||||
|
</g>
|
||||||
</svg>
|
</svg>
|
Before Width: | Height: | Size: 228 B After Width: | Height: | Size: 1008 B |
@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Client</id>
|
<id>Oqtane.Client</id>
|
||||||
<version>4.0.1</version>
|
<version>4.0.2</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.1</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.2</releaseNotes>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Framework</id>
|
<id>Oqtane.Framework</id>
|
||||||
<version>4.0.1</version>
|
<version>4.0.2</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
@ -11,8 +11,8 @@
|
|||||||
<copyright>.NET Foundation</copyright>
|
<copyright>.NET Foundation</copyright>
|
||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v4.0.1/Oqtane.Framework.4.0.1.Upgrade.zip</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v4.0.2/Oqtane.Framework.4.0.2.Upgrade.zip</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.1</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.2</releaseNotes>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane framework</tags>
|
<tags>oqtane framework</tags>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Server</id>
|
<id>Oqtane.Server</id>
|
||||||
<version>4.0.1</version>
|
<version>4.0.2</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.1</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.2</releaseNotes>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Shared</id>
|
<id>Oqtane.Shared</id>
|
||||||
<version>4.0.1</version>
|
<version>4.0.2</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.1</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.2</releaseNotes>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Updater</id>
|
<id>Oqtane.Updater</id>
|
||||||
<version>4.0.1</version>
|
<version>4.0.2</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane Framework</title>
|
<title>Oqtane Framework</title>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.1</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.2</releaseNotes>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
@ -1 +1 @@
|
|||||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net7.0\publish\*" -DestinationPath "Oqtane.Framework.4.0.1.Install.zip" -Force
|
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net7.0\publish\*" -DestinationPath "Oqtane.Framework.4.0.2.Install.zip" -Force
|
@ -14,7 +14,7 @@ dotnet publish ..\Oqtane.Server\Oqtane.Server.csproj /p:Configuration=Release
|
|||||||
del /F/Q/S "..\Oqtane.Server\bin\Release\net7.0\publish\wwwroot\Content" > NUL
|
del /F/Q/S "..\Oqtane.Server\bin\Release\net7.0\publish\wwwroot\Content" > NUL
|
||||||
rmdir /Q/S "..\Oqtane.Server\bin\Release\net7.0\publish\wwwroot\Content"
|
rmdir /Q/S "..\Oqtane.Server\bin\Release\net7.0\publish\wwwroot\Content"
|
||||||
setlocal ENABLEDELAYEDEXPANSION
|
setlocal ENABLEDELAYEDEXPANSION
|
||||||
set retain=Oqtane.Modules.Admin.Login,Oqtane.Modules.HtmlText,Templates
|
set retain=Oqtane.Modules.Admin.Login,Oqtane.Modules.HtmlText
|
||||||
for /D %%i in ("..\Oqtane.Server\bin\Release\net7.0\publish\wwwroot\Modules\*") do (
|
for /D %%i in ("..\Oqtane.Server\bin\Release\net7.0\publish\wwwroot\Modules\*") do (
|
||||||
set /A found=0
|
set /A found=0
|
||||||
for %%j in (%retain%) do (
|
for %%j in (%retain%) do (
|
||||||
@ -22,7 +22,7 @@ if "%%~nxi" == "%%j" set /A found=1
|
|||||||
)
|
)
|
||||||
if not !found! == 1 rmdir /Q/S "%%i"
|
if not !found! == 1 rmdir /Q/S "%%i"
|
||||||
)
|
)
|
||||||
set retain=Oqtane.Themes.BlazorTheme,Oqtane.Themes.OqtaneTheme,Templates
|
set retain=Oqtane.Themes.BlazorTheme,Oqtane.Themes.OqtaneTheme
|
||||||
for /D %%i in ("..\Oqtane.Server\bin\Release\net7.0\publish\wwwroot\Themes\*") do (
|
for /D %%i in ("..\Oqtane.Server\bin\Release\net7.0\publish\wwwroot\Themes\*") do (
|
||||||
set /A found=0
|
set /A found=0
|
||||||
for %%j in (%retain%) do (
|
for %%j in (%retain%) do (
|
||||||
|
@ -1 +1 @@
|
|||||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net7.0\publish\*" -DestinationPath "Oqtane.Framework.4.0.1.Upgrade.zip" -Force
|
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net7.0\publish\*" -DestinationPath "Oqtane.Framework.4.0.2.Upgrade.zip" -Force
|
@ -572,7 +572,7 @@ namespace Oqtane.Controllers
|
|||||||
// validation
|
// validation
|
||||||
if (!Enum.TryParse(mode, true, out ResizeMode _)) mode = "crop";
|
if (!Enum.TryParse(mode, true, out ResizeMode _)) mode = "crop";
|
||||||
if (!Enum.TryParse(position, true, out AnchorPositionMode _)) position = "center";
|
if (!Enum.TryParse(position, true, out AnchorPositionMode _)) position = "center";
|
||||||
if (!Color.TryParseHex("#" + background, out _)) background = "000000";
|
if (!Color.TryParseHex("#" + background, out _)) background = "transparent";
|
||||||
if (!int.TryParse(rotate, out _)) rotate = "0";
|
if (!int.TryParse(rotate, out _)) rotate = "0";
|
||||||
rotate = (int.Parse(rotate) < 0 || int.Parse(rotate) > 360) ? "0" : rotate;
|
rotate = (int.Parse(rotate) < 0 || int.Parse(rotate) > 360) ? "0" : rotate;
|
||||||
if (!bool.TryParse(recreate, out _)) recreate = "false";
|
if (!bool.TryParse(recreate, out _)) recreate = "false";
|
||||||
@ -644,10 +644,23 @@ namespace Oqtane.Controllers
|
|||||||
Mode = resizemode,
|
Mode = resizemode,
|
||||||
Position = anchorpositionmode,
|
Position = anchorpositionmode,
|
||||||
Size = new Size(width, height)
|
Size = new Size(width, height)
|
||||||
})
|
}));
|
||||||
.BackgroundColor(Color.ParseHex("#" + background)));
|
|
||||||
|
|
||||||
image.Save(imagepath, new PngEncoder());
|
if (background != "transparent")
|
||||||
|
{
|
||||||
|
image.Mutate(x => x
|
||||||
|
.BackgroundColor(Color.ParseHex("#" + background)));
|
||||||
|
}
|
||||||
|
|
||||||
|
PngEncoder encoder = new PngEncoder
|
||||||
|
{
|
||||||
|
ColorType = PngColorType.RgbWithAlpha,
|
||||||
|
TransparentColorMode = PngTransparentColorMode.Preserve,
|
||||||
|
BitDepth = PngBitDepth.Bit8,
|
||||||
|
CompressionLevel = PngCompressionLevel.BestSpeed
|
||||||
|
};
|
||||||
|
|
||||||
|
image.Save(imagepath, encoder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -677,7 +690,14 @@ namespace Oqtane.Controllers
|
|||||||
path = Utilities.PathCombine(path, folder, Path.DirectorySeparatorChar.ToString());
|
path = Utilities.PathCombine(path, folder, Path.DirectorySeparatorChar.ToString());
|
||||||
if (!Directory.Exists(path))
|
if (!Directory.Exists(path))
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(path);
|
try
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(path);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Create, ex, "Unable To Create Folder {Folder}", path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,8 @@ namespace Oqtane.Controllers
|
|||||||
{
|
{
|
||||||
foreach (Folder folder in _folders.GetFolders(SiteId))
|
foreach (Folder folder in _folders.GetFolders(SiteId))
|
||||||
{
|
{
|
||||||
if (_userPermissions.IsAuthorized(User, PermissionNames.View, folder.PermissionList))
|
// note that Browse permission is used for this method
|
||||||
|
if (_userPermissions.IsAuthorized(User, PermissionNames.Browse, folder.PermissionList))
|
||||||
{
|
{
|
||||||
folders.Add(folder);
|
folders.Add(folder);
|
||||||
}
|
}
|
||||||
@ -87,6 +88,7 @@ namespace Oqtane.Controllers
|
|||||||
public Folder GetByPath(int siteId, string path)
|
public Folder GetByPath(int siteId, string path)
|
||||||
{
|
{
|
||||||
var folderPath = WebUtility.UrlDecode(path).Replace("\\", "/");
|
var folderPath = WebUtility.UrlDecode(path).Replace("\\", "/");
|
||||||
|
folderPath = (folderPath == "/") ? "" : folderPath;
|
||||||
if (!folderPath.EndsWith("/") && folderPath != "")
|
if (!folderPath.EndsWith("/") && folderPath != "")
|
||||||
{
|
{
|
||||||
folderPath += "/";
|
folderPath += "/";
|
||||||
|
@ -34,9 +34,9 @@ namespace Oqtane.Controllers
|
|||||||
private readonly IAliasRepository _aliases;
|
private readonly IAliasRepository _aliases;
|
||||||
private readonly ILogger<InstallationController> _filelogger;
|
private readonly ILogger<InstallationController> _filelogger;
|
||||||
private readonly ITenantManager _tenantManager;
|
private readonly ITenantManager _tenantManager;
|
||||||
private readonly ServerStateManager _serverState;
|
private readonly IServerStateManager _serverState;
|
||||||
|
|
||||||
public InstallationController(IConfigManager configManager, IInstallationManager installationManager, IDatabaseManager databaseManager, ILocalizationManager localizationManager, IMemoryCache cache, IHttpContextAccessor accessor, IAliasRepository aliases, ILogger<InstallationController> filelogger, ITenantManager tenantManager, ServerStateManager serverState)
|
public InstallationController(IConfigManager configManager, IInstallationManager installationManager, IDatabaseManager databaseManager, ILocalizationManager localizationManager, IMemoryCache cache, IHttpContextAccessor accessor, IAliasRepository aliases, ILogger<InstallationController> filelogger, ITenantManager tenantManager, IServerStateManager serverState)
|
||||||
{
|
{
|
||||||
_configManager = configManager;
|
_configManager = configManager;
|
||||||
_installationManager = installationManager;
|
_installationManager = installationManager;
|
||||||
@ -119,9 +119,9 @@ namespace Oqtane.Controllers
|
|||||||
|
|
||||||
private List<ClientAssembly> GetAssemblyList()
|
private List<ClientAssembly> GetAssemblyList()
|
||||||
{
|
{
|
||||||
int siteId = _tenantManager.GetAlias().SiteId;
|
var siteKey = _tenantManager.GetAlias().SiteKey;
|
||||||
|
|
||||||
return _cache.GetOrCreate($"assemblieslist:{siteId}", entry =>
|
return _cache.GetOrCreate($"assemblieslist:{siteKey}", entry =>
|
||||||
{
|
{
|
||||||
var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
||||||
var assemblyList = new List<ClientAssembly>();
|
var assemblyList = new List<ClientAssembly>();
|
||||||
@ -134,7 +134,7 @@ namespace Oqtane.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get site assemblies which should be downloaded to client
|
// get site assemblies which should be downloaded to client
|
||||||
var assemblies = _serverState.GetServerState(siteId).Assemblies;
|
var assemblies = _serverState.GetServerState(siteKey).Assemblies;
|
||||||
|
|
||||||
// populate assembly list
|
// populate assembly list
|
||||||
foreach (var assembly in assemblies)
|
foreach (var assembly in assemblies)
|
||||||
@ -179,9 +179,11 @@ namespace Oqtane.Controllers
|
|||||||
|
|
||||||
private byte[] GetAssemblies(string list)
|
private byte[] GetAssemblies(string list)
|
||||||
{
|
{
|
||||||
|
var siteKey = _tenantManager.GetAlias().SiteKey;
|
||||||
|
|
||||||
if (list == "*")
|
if (list == "*")
|
||||||
{
|
{
|
||||||
return _cache.GetOrCreate("assemblies", entry =>
|
return _cache.GetOrCreate($"assemblies:{siteKey}", entry =>
|
||||||
{
|
{
|
||||||
return GetZIP(list);
|
return GetZIP(list);
|
||||||
});
|
});
|
||||||
|
@ -283,23 +283,26 @@ namespace Oqtane.Controllers
|
|||||||
var templates = new List<Template>();
|
var templates = new List<Template>();
|
||||||
var root = Directory.GetParent(_environment.ContentRootPath);
|
var root = Directory.GetParent(_environment.ContentRootPath);
|
||||||
string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Modules", "Templates", Path.DirectorySeparatorChar.ToString());
|
string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Modules", "Templates", Path.DirectorySeparatorChar.ToString());
|
||||||
foreach (string directory in Directory.GetDirectories(templatePath))
|
if (Directory.Exists(templatePath))
|
||||||
{
|
{
|
||||||
string name = directory.Replace(templatePath, "");
|
foreach (string directory in Directory.GetDirectories(templatePath))
|
||||||
if (System.IO.File.Exists(Path.Combine(directory, "template.json")))
|
|
||||||
{
|
{
|
||||||
var template = JsonSerializer.Deserialize<Template>(System.IO.File.ReadAllText(Path.Combine(directory, "template.json")));
|
string name = directory.Replace(templatePath, "");
|
||||||
template.Name = name;
|
if (System.IO.File.Exists(Path.Combine(directory, "template.json")))
|
||||||
template.Location = "";
|
|
||||||
if (template.Type.ToLower() != "internal")
|
|
||||||
{
|
{
|
||||||
template.Location = Utilities.PathCombine(root.Parent.ToString(), Path.DirectorySeparatorChar.ToString());
|
var template = JsonSerializer.Deserialize<Template>(System.IO.File.ReadAllText(Path.Combine(directory, "template.json")));
|
||||||
|
template.Name = name;
|
||||||
|
template.Location = "";
|
||||||
|
if (template.Type.ToLower() != "internal")
|
||||||
|
{
|
||||||
|
template.Location = Utilities.PathCombine(root.Parent.ToString(), Path.DirectorySeparatorChar.ToString());
|
||||||
|
}
|
||||||
|
templates.Add(template);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
templates.Add(new Template { Name = name, Title = name, Type = "External", Version = "", Location = Utilities.PathCombine(root.Parent.ToString(), Path.DirectorySeparatorChar.ToString()) });
|
||||||
}
|
}
|
||||||
templates.Add(template);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
templates.Add(new Template { Name = name, Title = name, Type = "External", Version = "", Location = Utilities.PathCombine(root.Parent.ToString(), Path.DirectorySeparatorChar.ToString()) });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return templates;
|
return templates;
|
||||||
|
@ -23,10 +23,16 @@ namespace Oqtane.Controllers
|
|||||||
[HttpGet("{lastSyncDate}")]
|
[HttpGet("{lastSyncDate}")]
|
||||||
public Sync Get(string lastSyncDate)
|
public Sync Get(string lastSyncDate)
|
||||||
{
|
{
|
||||||
|
DateTime currentdate = DateTime.UtcNow;
|
||||||
|
DateTime lastdate = DateTime.ParseExact(lastSyncDate, "yyyyMMddHHmmssfff", CultureInfo.InvariantCulture);
|
||||||
|
if (lastdate == DateTime.MinValue)
|
||||||
|
{
|
||||||
|
lastdate = currentdate;
|
||||||
|
}
|
||||||
Sync sync = new Sync
|
Sync sync = new Sync
|
||||||
{
|
{
|
||||||
SyncDate = DateTime.UtcNow,
|
SyncDate = currentdate,
|
||||||
SyncEvents = _syncManager.GetSyncEvents(_alias.TenantId, DateTime.ParseExact(lastSyncDate, "yyyyMMddHHmmssfff", CultureInfo.InvariantCulture))
|
SyncEvents = _syncManager.GetSyncEvents(_alias.TenantId, lastdate)
|
||||||
};
|
};
|
||||||
return sync;
|
return sync;
|
||||||
}
|
}
|
||||||
|
@ -137,23 +137,26 @@ namespace Oqtane.Controllers
|
|||||||
var templates = new List<Template>();
|
var templates = new List<Template>();
|
||||||
var root = Directory.GetParent(_environment.ContentRootPath);
|
var root = Directory.GetParent(_environment.ContentRootPath);
|
||||||
string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Themes", "Templates", Path.DirectorySeparatorChar.ToString());
|
string templatePath = Utilities.PathCombine(_environment.WebRootPath, "Themes", "Templates", Path.DirectorySeparatorChar.ToString());
|
||||||
foreach (string directory in Directory.GetDirectories(templatePath))
|
if (Directory.Exists(templatePath))
|
||||||
{
|
{
|
||||||
string name = directory.Replace(templatePath, "");
|
foreach (string directory in Directory.GetDirectories(templatePath))
|
||||||
if (System.IO.File.Exists(Path.Combine(directory, "template.json")))
|
|
||||||
{
|
{
|
||||||
var template = JsonSerializer.Deserialize<Template>(System.IO.File.ReadAllText(Path.Combine(directory, "template.json")));
|
string name = directory.Replace(templatePath, "");
|
||||||
template.Name = name;
|
if (System.IO.File.Exists(Path.Combine(directory, "template.json")))
|
||||||
template.Location = "";
|
|
||||||
if (template.Type.ToLower() != "internal")
|
|
||||||
{
|
{
|
||||||
template.Location = Utilities.PathCombine(root.Parent.ToString(), Path.DirectorySeparatorChar.ToString());
|
var template = JsonSerializer.Deserialize<Template>(System.IO.File.ReadAllText(Path.Combine(directory, "template.json")));
|
||||||
|
template.Name = name;
|
||||||
|
template.Location = "";
|
||||||
|
if (template.Type.ToLower() != "internal")
|
||||||
|
{
|
||||||
|
template.Location = Utilities.PathCombine(root.Parent.ToString(), Path.DirectorySeparatorChar.ToString());
|
||||||
|
}
|
||||||
|
templates.Add(template);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
templates.Add(new Template { Name = name, Title = name, Type = "External", Version = "", Location = Utilities.PathCombine(root.Parent.ToString(), Path.DirectorySeparatorChar.ToString()) });
|
||||||
}
|
}
|
||||||
templates.Add(template);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
templates.Add(new Template { Name = name, Title = name, Type = "External", Version = "", Location = Utilities.PathCombine(root.Parent.ToString(), Path.DirectorySeparatorChar.ToString()) });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return templates;
|
return templates;
|
||||||
|
@ -2,7 +2,6 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using Microsoft.AspNetCore.Identity;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
@ -22,23 +21,17 @@ namespace Oqtane.Controllers
|
|||||||
public class UserController : Controller
|
public class UserController : Controller
|
||||||
{
|
{
|
||||||
private readonly IUserRepository _users;
|
private readonly IUserRepository _users;
|
||||||
private readonly UserManager<IdentityUser> _identityUserManager;
|
|
||||||
private readonly SignInManager<IdentityUser> _identitySignInManager;
|
|
||||||
private readonly ITenantManager _tenantManager;
|
private readonly ITenantManager _tenantManager;
|
||||||
private readonly INotificationRepository _notifications;
|
|
||||||
private readonly IUserManager _userManager;
|
private readonly IUserManager _userManager;
|
||||||
private readonly ISiteRepository _sites;
|
private readonly ISiteRepository _sites;
|
||||||
private readonly IUserPermissions _userPermissions;
|
private readonly IUserPermissions _userPermissions;
|
||||||
private readonly IJwtManager _jwtManager;
|
private readonly IJwtManager _jwtManager;
|
||||||
private readonly ILogManager _logger;
|
private readonly ILogManager _logger;
|
||||||
|
|
||||||
public UserController(IUserRepository users, UserManager<IdentityUser> identityUserManager, SignInManager<IdentityUser> identitySignInManager, ITenantManager tenantManager, INotificationRepository notifications, IUserManager userManager, ISiteRepository sites, IUserPermissions userPermissions, IJwtManager jwtManager, ILogManager logger)
|
public UserController(IUserRepository users, ITenantManager tenantManager, IUserManager userManager, ISiteRepository sites, IUserPermissions userPermissions, IJwtManager jwtManager, ILogManager logger)
|
||||||
{
|
{
|
||||||
_users = users;
|
_users = users;
|
||||||
_identityUserManager = identityUserManager;
|
|
||||||
_identitySignInManager = identitySignInManager;
|
|
||||||
_tenantManager = tenantManager;
|
_tenantManager = tenantManager;
|
||||||
_notifications = notifications;
|
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_sites = sites;
|
_sites = sites;
|
||||||
_userPermissions = userPermissions;
|
_userPermissions = userPermissions;
|
||||||
|
@ -131,9 +131,8 @@ namespace Oqtane.Controllers
|
|||||||
{
|
{
|
||||||
userRole = _userRoles.AddUserRole(userRole);
|
userRole = _userRoles.AddUserRole(userRole);
|
||||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.UserRole, userRole.UserRoleId, SyncEventActions.Create);
|
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.UserRole, userRole.UserRoleId, SyncEventActions.Create);
|
||||||
|
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userRole.UserId, SyncEventActions.Reload);
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "User Role Added {UserRole}", userRole);
|
_logger.Log(LogLevel.Information, this, LogFunction.Create, "User Role Added {UserRole}", userRole);
|
||||||
|
|
||||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userRole.UserId, SyncEventActions.Refresh);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -154,7 +153,7 @@ namespace Oqtane.Controllers
|
|||||||
{
|
{
|
||||||
userRole = _userRoles.UpdateUserRole(userRole);
|
userRole = _userRoles.UpdateUserRole(userRole);
|
||||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.UserRole, userRole.UserRoleId, SyncEventActions.Update);
|
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.UserRole, userRole.UserRoleId, SyncEventActions.Update);
|
||||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userRole.UserId, SyncEventActions.Refresh);
|
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userRole.UserId, SyncEventActions.Reload);
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "User Role Updated {UserRole}", userRole);
|
_logger.Log(LogLevel.Information, this, LogFunction.Update, "User Role Updated {UserRole}", userRole);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -171,25 +170,24 @@ namespace Oqtane.Controllers
|
|||||||
[Authorize(Policy = $"{EntityNames.UserRole}:{PermissionNames.Write}:{RoleNames.Admin}")]
|
[Authorize(Policy = $"{EntityNames.UserRole}:{PermissionNames.Write}:{RoleNames.Admin}")]
|
||||||
public void Delete(int id)
|
public void Delete(int id)
|
||||||
{
|
{
|
||||||
UserRole userrole = _userRoles.GetUserRole(id);
|
UserRole userRole = _userRoles.GetUserRole(id);
|
||||||
if (userrole != null && SiteValid(userrole.Role.SiteId) && RoleValid(userrole.Role.Name))
|
if (userRole != null && SiteValid(userRole.Role.SiteId) && RoleValid(userRole.Role.Name))
|
||||||
{
|
{
|
||||||
_userRoles.DeleteUserRole(id);
|
_userRoles.DeleteUserRole(id);
|
||||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.UserRole, userrole.UserRoleId, SyncEventActions.Delete);
|
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.UserRole, userRole.UserRoleId, SyncEventActions.Delete);
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Role Deleted {UserRole}", userrole);
|
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userRole.UserId, SyncEventActions.Reload);
|
||||||
|
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Role Deleted {UserRole}", userRole);
|
||||||
|
|
||||||
if (userrole.Role.Name == RoleNames.Host)
|
if (userRole.Role.Name == RoleNames.Host)
|
||||||
{
|
{
|
||||||
// add site specific user roles to preserve user access
|
// add site specific user roles to preserve user access
|
||||||
var role = _roles.GetRoles(_alias.SiteId).FirstOrDefault(item => item.Name == RoleNames.Registered);
|
var role = _roles.GetRoles(_alias.SiteId).FirstOrDefault(item => item.Name == RoleNames.Registered);
|
||||||
userrole = _userRoles.AddUserRole(new UserRole { UserId = userrole.UserId, RoleId = role.RoleId, EffectiveDate = null, ExpiryDate = null });
|
userRole = _userRoles.AddUserRole(new UserRole { UserId = userRole.UserId, RoleId = role.RoleId, EffectiveDate = null, ExpiryDate = null });
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "User Role Added {UserRole}", userrole);
|
_logger.Log(LogLevel.Information, this, LogFunction.Create, "User Role Added {UserRole}", userRole);
|
||||||
role = _roles.GetRoles(_alias.SiteId).FirstOrDefault(item => item.Name == RoleNames.Admin);
|
role = _roles.GetRoles(_alias.SiteId).FirstOrDefault(item => item.Name == RoleNames.Admin);
|
||||||
userrole = _userRoles.AddUserRole(new UserRole { UserId = userrole.UserId, RoleId = role.RoleId, EffectiveDate = null, ExpiryDate = null });
|
userRole = _userRoles.AddUserRole(new UserRole { UserId = userRole.UserId, RoleId = role.RoleId, EffectiveDate = null, ExpiryDate = null });
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "User Role Added {UserRole}", userrole);
|
_logger.Log(LogLevel.Information, this, LogFunction.Create, "User Role Added {UserRole}", userRole);
|
||||||
}
|
}
|
||||||
|
|
||||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userrole.UserId, SyncEventActions.Refresh);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -62,7 +62,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||||||
services.AddSingleton<ILoggerProvider, FileLoggerProvider>();
|
services.AddSingleton<ILoggerProvider, FileLoggerProvider>();
|
||||||
services.AddSingleton<AutoValidateAntiforgeryTokenFilter>();
|
services.AddSingleton<AutoValidateAntiforgeryTokenFilter>();
|
||||||
services.AddSingleton<IAuthorizationPolicyProvider, AuthorizationPolicyProvider>();
|
services.AddSingleton<IAuthorizationPolicyProvider, AuthorizationPolicyProvider>();
|
||||||
services.AddSingleton<ServerStateManager>();
|
services.AddSingleton<IServerStateManager, ServerStateManager>();
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
namespace Oqtane.Infrastructure
|
||||||
|
{
|
||||||
|
public interface IServerStateManager
|
||||||
|
{
|
||||||
|
ServerState GetServerState(string siteKey);
|
||||||
|
}
|
||||||
|
}
|
@ -40,9 +40,13 @@ namespace Oqtane.Infrastructure
|
|||||||
public string[] GetInstalledCultures()
|
public string[] GetInstalledCultures()
|
||||||
{
|
{
|
||||||
var cultures = new List<string>();
|
var cultures = new List<string>();
|
||||||
foreach (var file in Directory.EnumerateFiles(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), $"{Constants.ClientId}{Constants.SatelliteAssemblyExtension}", SearchOption.AllDirectories))
|
foreach (var file in Directory.EnumerateFiles(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), $"*{Constants.SatelliteAssemblyExtension}", SearchOption.AllDirectories))
|
||||||
{
|
{
|
||||||
cultures.Add(Path.GetFileName(Path.GetDirectoryName(file)));
|
var culture = Path.GetFileName(Path.GetDirectoryName(file));
|
||||||
|
if (!cultures.Contains(culture))
|
||||||
|
{
|
||||||
|
cultures.Add(culture);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return cultures.OrderBy(c => c).ToArray();
|
return cultures.OrderBy(c => c).ToArray();
|
||||||
}
|
}
|
||||||
|
@ -37,20 +37,46 @@ namespace Oqtane.Infrastructure
|
|||||||
var identity = jwtManager.ValidateToken(token, secret, sitesettings.GetValue("JwtOptions:Issuer", ""), sitesettings.GetValue("JwtOptions:Audience", ""));
|
var identity = jwtManager.ValidateToken(token, secret, sitesettings.GetValue("JwtOptions:Issuer", ""), sitesettings.GetValue("JwtOptions:Audience", ""));
|
||||||
if (identity != null && identity.Claims.Any())
|
if (identity != null && identity.Claims.Any())
|
||||||
{
|
{
|
||||||
// create user identity using jwt claims (note the difference in claimtype names)
|
var idclaim = "nameid";
|
||||||
var user = new User
|
var nameclaim = "unique_name";
|
||||||
|
var legacynameclaim = "name"; // this was a breaking change in System.IdentityModel.Tokens.Jwt in .NET 7
|
||||||
|
|
||||||
|
// get jwt claims for userid and username
|
||||||
|
var userid = identity.Claims.FirstOrDefault(item => item.Type == idclaim)?.Value;
|
||||||
|
if (userid != null)
|
||||||
{
|
{
|
||||||
UserId = int.Parse(identity.Claims.FirstOrDefault(item => item.Type == "nameid")?.Value),
|
if (!int.TryParse(userid, out _))
|
||||||
Username = identity.Claims.FirstOrDefault(item => item.Type == "name")?.Value
|
{
|
||||||
};
|
userid = null;
|
||||||
// jwt already contains the roles - we are reloading to ensure most accurate permissions
|
}
|
||||||
var _userRoles = context.RequestServices.GetService(typeof(IUserRoleRepository)) as IUserRoleRepository;
|
}
|
||||||
|
var username = identity.Claims.FirstOrDefault(item => item.Type == nameclaim)?.Value;
|
||||||
|
if (username == null)
|
||||||
|
{
|
||||||
|
// fallback for legacy clients
|
||||||
|
username = identity.Claims.FirstOrDefault(item => item.Type == legacynameclaim)?.Value;
|
||||||
|
}
|
||||||
|
|
||||||
// set claims identity
|
if (userid != null && username != null)
|
||||||
var claimsidentity = UserSecurity.CreateClaimsIdentity(alias, user, _userRoles.GetUserRoles(user.UserId, alias.SiteId).ToList());
|
{
|
||||||
context.User = new ClaimsPrincipal(claimsidentity);
|
// create user identity
|
||||||
|
var user = new User
|
||||||
|
{
|
||||||
|
UserId = int.Parse(userid),
|
||||||
|
Username = username
|
||||||
|
};
|
||||||
|
|
||||||
logger.Log(alias.SiteId, LogLevel.Information, "TokenValidation", Enums.LogFunction.Security, "Token Validated For User {Username}", user.Username);
|
// set claims identity (note jwt already contains the roles - we are reloading to ensure most accurate permissions)
|
||||||
|
var _userRoles = context.RequestServices.GetService(typeof(IUserRoleRepository)) as IUserRoleRepository;
|
||||||
|
var claimsidentity = UserSecurity.CreateClaimsIdentity(alias, user, _userRoles.GetUserRoles(user.UserId, alias.SiteId).ToList());
|
||||||
|
context.User = new ClaimsPrincipal(claimsidentity);
|
||||||
|
|
||||||
|
logger.Log(alias.SiteId, LogLevel.Information, "TokenValidation", Enums.LogFunction.Security, "Token Validated For UserId {UserId} And Username {Username}", user.UserId, user.Username);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.Log(alias.SiteId, LogLevel.Error, "TokenValidation", Enums.LogFunction.Security, "Token Validated But Could Not Locate UserId Or Username In Claims {Claims}", identity.Claims.ToString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -22,6 +22,7 @@ namespace Oqtane.Infrastructure
|
|||||||
var config = context.RequestServices.GetService(typeof(IConfigManager)) as IConfigManager;
|
var config = context.RequestServices.GetService(typeof(IConfigManager)) as IConfigManager;
|
||||||
string path = context.Request.Path.ToString();
|
string path = context.Request.Path.ToString();
|
||||||
|
|
||||||
|
|
||||||
if (config.IsInstalled() && !path.StartsWith("/_blazor"))
|
if (config.IsInstalled() && !path.StartsWith("/_blazor"))
|
||||||
{
|
{
|
||||||
// get alias (note that this also sets SiteState.Alias)
|
// get alias (note that this also sets SiteState.Alias)
|
||||||
@ -43,6 +44,14 @@ namespace Oqtane.Infrastructure
|
|||||||
});
|
});
|
||||||
context.Items.Add(Constants.HttpContextSiteSettingsKey, sitesettings);
|
context.Items.Add(Constants.HttpContextSiteSettingsKey, sitesettings);
|
||||||
|
|
||||||
|
// handle first request to site
|
||||||
|
var serverState = context.RequestServices.GetService(typeof(IServerStateManager)) as IServerStateManager;
|
||||||
|
if (!serverState.GetServerState(alias.SiteKey).IsInitialized)
|
||||||
|
{
|
||||||
|
var sites = context.RequestServices.GetService(typeof(ISiteRepository)) as ISiteRepository;
|
||||||
|
sites.InitializeSite(alias);
|
||||||
|
}
|
||||||
|
|
||||||
// rewrite path by removing alias path prefix from reserved route (api,pages,files) requests for consistent routes
|
// rewrite path by removing alias path prefix from reserved route (api,pages,files) requests for consistent routes
|
||||||
if (!string.IsNullOrEmpty(alias.Path))
|
if (!string.IsNullOrEmpty(alias.Path))
|
||||||
{
|
{
|
||||||
|
@ -5,9 +5,9 @@ namespace Oqtane.Infrastructure
|
|||||||
{
|
{
|
||||||
public class ServerState
|
public class ServerState
|
||||||
{
|
{
|
||||||
public int SiteId { get; set; }
|
public string SiteKey { get; set; }
|
||||||
public List<string> Assemblies { get; set; } = new List<string>();
|
public List<string> Assemblies { get; set; } = new List<string>();
|
||||||
public List<Resource>Scripts { get; set; } = new List<Resource>();
|
public List<Resource>Scripts { get; set; } = new List<Resource>();
|
||||||
public bool IsMigrated { get; set; } = false;
|
public bool IsInitialized { get; set; } = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ using Oqtane.Models;
|
|||||||
namespace Oqtane.Infrastructure
|
namespace Oqtane.Infrastructure
|
||||||
{
|
{
|
||||||
// singleton
|
// singleton
|
||||||
public class ServerStateManager
|
public class ServerStateManager : IServerStateManager
|
||||||
{
|
{
|
||||||
private List<ServerState> _serverStates { get; set; }
|
private List<ServerState> _serverStates { get; set; }
|
||||||
|
|
||||||
@ -14,36 +14,19 @@ namespace Oqtane.Infrastructure
|
|||||||
_serverStates = new List<ServerState>();
|
_serverStates = new List<ServerState>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServerState GetServerState(int siteId)
|
public ServerState GetServerState(string siteKey)
|
||||||
{
|
{
|
||||||
var serverState = _serverStates.FirstOrDefault(item => item.SiteId == siteId);
|
var serverState = _serverStates.FirstOrDefault(item => item.SiteKey == siteKey);
|
||||||
if (serverState == null)
|
if (serverState == null)
|
||||||
{
|
{
|
||||||
serverState = new ServerState();
|
serverState = new ServerState();
|
||||||
serverState.SiteId = siteId;
|
serverState.SiteKey = siteKey;
|
||||||
serverState.Assemblies = new List<string>();
|
serverState.Assemblies = new List<string>();
|
||||||
serverState.Scripts = new List<Resource>();
|
serverState.Scripts = new List<Resource>();
|
||||||
return serverState;
|
serverState.IsInitialized = false;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return serverState;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetServerState(int siteId, ServerState serverState)
|
|
||||||
{
|
|
||||||
var serverstate = _serverStates.FirstOrDefault(item => item.SiteId == siteId);
|
|
||||||
if (serverstate == null)
|
|
||||||
{
|
|
||||||
serverState.SiteId = siteId;
|
|
||||||
_serverStates.Add(serverState);
|
_serverStates.Add(serverState);
|
||||||
}
|
}
|
||||||
else
|
return serverState;
|
||||||
{
|
|
||||||
serverstate.Assemblies = serverState.Assemblies;
|
|
||||||
serverstate.Scripts = serverState.Scripts;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,35 +133,6 @@ namespace Oqtane.SiteTemplates
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
_pageTemplates.Add(new PageTemplate
|
|
||||||
{
|
|
||||||
Name = "Develop",
|
|
||||||
Parent = "",
|
|
||||||
Order = 7,
|
|
||||||
Path = "develop",
|
|
||||||
Icon = "oi oi-wrench",
|
|
||||||
IsNavigation = true,
|
|
||||||
IsPersonalizable = false,
|
|
||||||
PermissionList = new List<Permission> {
|
|
||||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
|
||||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
|
||||||
},
|
|
||||||
PageTemplateModules = new List<PageTemplateModule> {
|
|
||||||
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Software Development", Pane = PaneNames.Default,
|
|
||||||
PermissionList = new List<Permission> {
|
|
||||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
|
||||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
|
||||||
},
|
|
||||||
Content = "<p>Oqtane offers a Module Creator which allows you to create new modules to extend the framework with additional capabilities. Simply provide some basic information and the system will scaffold a completely functional module which includes all of the necessary code files and assets to get you up and running as quickly as possible.</p>"
|
|
||||||
},
|
|
||||||
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.ModuleCreator, Oqtane.Client", Title = "Module Creator", Pane = PaneNames.Default,
|
|
||||||
PermissionList = new List<Permission> {
|
|
||||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
|
||||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (System.IO.File.Exists(Path.Combine(_environment.WebRootPath, "images", "logo-white.png")))
|
if (System.IO.File.Exists(Path.Combine(_environment.WebRootPath, "images", "logo-white.png")))
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
@ -57,7 +58,7 @@ namespace Oqtane.Infrastructure
|
|||||||
alias.BaseUrl = "";
|
alias.BaseUrl = "";
|
||||||
if (httpcontext.Request.Headers.ContainsKey("User-Agent") && httpcontext.Request.Headers["User-Agent"] == Shared.Constants.MauiUserAgent)
|
if (httpcontext.Request.Headers.ContainsKey("User-Agent") && httpcontext.Request.Headers["User-Agent"] == Shared.Constants.MauiUserAgent)
|
||||||
{
|
{
|
||||||
alias.BaseUrl = alias.Protocol + alias.Name;
|
alias.BaseUrl = alias.Protocol + alias.Name.Replace("/" + alias.Path, "");
|
||||||
}
|
}
|
||||||
_siteState.Alias = alias;
|
_siteState.Alias = alias;
|
||||||
}
|
}
|
||||||
|
@ -231,7 +231,7 @@ namespace Oqtane.Infrastructure
|
|||||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||||
},
|
},
|
||||||
Content = "<p>The page you requested does not exist.</p>"
|
Content = "<p>The page you requested does not exist or you do not have sufficient rights to view it.</p>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -130,14 +130,14 @@ namespace Oqtane.Managers
|
|||||||
if (!user.EmailConfirmed)
|
if (!user.EmailConfirmed)
|
||||||
{
|
{
|
||||||
string token = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
|
string token = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
|
||||||
string url = alias.Protocol + "://" + alias.Name + "/login?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token);
|
string url = alias.Protocol + alias.Name + "/login?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token);
|
||||||
string body = "Dear " + user.DisplayName + ",\n\nIn Order To Complete The Registration Of Your User Account Please Click The Link Displayed Below:\n\n" + url + "\n\nThank You!";
|
string body = "Dear " + user.DisplayName + ",\n\nIn Order To Complete The Registration Of Your User Account Please Click The Link Displayed Below:\n\n" + url + "\n\nThank You!";
|
||||||
var notification = new Notification(user.SiteId, User, "User Account Verification", body);
|
var notification = new Notification(user.SiteId, User, "User Account Verification", body);
|
||||||
_notifications.AddNotification(notification);
|
_notifications.AddNotification(notification);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string url = alias.Protocol + "://" + alias.Name;
|
string url = alias.Protocol + alias.Name;
|
||||||
string body = "Dear " + user.DisplayName + ",\n\nA User Account Has Been Successfully Created For You. Please Use The Following Link To Access The Site:\n\n" + url + "\n\nThank You!";
|
string body = "Dear " + user.DisplayName + ",\n\nA User Account Has Been Successfully Created For You. Please Use The Following Link To Access The Site:\n\n" + url + "\n\nThank You!";
|
||||||
var notification = new Notification(user.SiteId, User, "User Account Notification", body);
|
var notification = new Notification(user.SiteId, User, "User Account Notification", body);
|
||||||
_notifications.AddNotification(notification);
|
_notifications.AddNotification(notification);
|
||||||
@ -178,7 +178,7 @@ namespace Oqtane.Managers
|
|||||||
|
|
||||||
user = _users.UpdateUser(user);
|
user = _users.UpdateUser(user);
|
||||||
_syncManager.AddSyncEvent(_tenantManager.GetAlias().TenantId, EntityNames.User, user.UserId, SyncEventActions.Update);
|
_syncManager.AddSyncEvent(_tenantManager.GetAlias().TenantId, EntityNames.User, user.UserId, SyncEventActions.Update);
|
||||||
_syncManager.AddSyncEvent(_tenantManager.GetAlias().TenantId, EntityNames.User, user.UserId, SyncEventActions.Refresh);
|
_syncManager.AddSyncEvent(_tenantManager.GetAlias().TenantId, EntityNames.User, user.UserId, SyncEventActions.Reload);
|
||||||
user.Password = ""; // remove sensitive information
|
user.Password = ""; // remove sensitive information
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "User Updated {User}", user);
|
_logger.Log(LogLevel.Information, this, LogFunction.Update, "User Updated {User}", user);
|
||||||
}
|
}
|
||||||
@ -228,6 +228,7 @@ namespace Oqtane.Managers
|
|||||||
// delete user
|
// delete user
|
||||||
_users.DeleteUser(userid);
|
_users.DeleteUser(userid);
|
||||||
_syncManager.AddSyncEvent(_tenantManager.GetAlias().TenantId, EntityNames.User, userid, SyncEventActions.Delete);
|
_syncManager.AddSyncEvent(_tenantManager.GetAlias().TenantId, EntityNames.User, userid, SyncEventActions.Delete);
|
||||||
|
_syncManager.AddSyncEvent(_tenantManager.GetAlias().TenantId, EntityNames.User, userid, SyncEventActions.Reload);
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Deleted {UserId}", userid, result.ToString());
|
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Deleted {UserId}", userid, result.ToString());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -299,7 +300,7 @@ namespace Oqtane.Managers
|
|||||||
var alias = _tenantManager.GetAlias();
|
var alias = _tenantManager.GetAlias();
|
||||||
user = _users.GetUser(user.Username);
|
user = _users.GetUser(user.Username);
|
||||||
string token = await _identityUserManager.GeneratePasswordResetTokenAsync(identityuser);
|
string token = await _identityUserManager.GeneratePasswordResetTokenAsync(identityuser);
|
||||||
string url = alias.Protocol + "://" + alias.Name + "/reset?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token);
|
string url = alias.Protocol + alias.Name + "/reset?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token);
|
||||||
string body = "Dear " + user.DisplayName + ",\n\nYou attempted multiple times unsuccessfully to log in to your account and it is now locked out. Please wait a few minutes and then try again... or use the link below to reset your password:\n\n" + url +
|
string body = "Dear " + user.DisplayName + ",\n\nYou attempted multiple times unsuccessfully to log in to your account and it is now locked out. Please wait a few minutes and then try again... or use the link below to reset your password:\n\n" + url +
|
||||||
"\n\nPlease note that the link is only valid for 24 hours so if you are unable to take action within that time period, you should initiate another password reset on the site." +
|
"\n\nPlease note that the link is only valid for 24 hours so if you are unable to take action within that time period, you should initiate another password reset on the site." +
|
||||||
"\n\nThank You!";
|
"\n\nThank You!";
|
||||||
@ -348,7 +349,7 @@ namespace Oqtane.Managers
|
|||||||
var alias = _tenantManager.GetAlias();
|
var alias = _tenantManager.GetAlias();
|
||||||
user = _users.GetUser(user.Username);
|
user = _users.GetUser(user.Username);
|
||||||
string token = await _identityUserManager.GeneratePasswordResetTokenAsync(identityuser);
|
string token = await _identityUserManager.GeneratePasswordResetTokenAsync(identityuser);
|
||||||
string url = alias.Protocol + "://" + alias.Name + "/reset?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token);
|
string url = alias.Protocol + alias.Name + "/reset?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token);
|
||||||
string body = "Dear " + user.DisplayName + ",\n\nYou recently requested to reset your password. Please use the link below to complete the process:\n\n" + url +
|
string body = "Dear " + user.DisplayName + ",\n\nYou recently requested to reset your password. Please use the link below to complete the process:\n\n" + url +
|
||||||
"\n\nPlease note that the link is only valid for 24 hours so if you are unable to take action within that time period, you should initiate another password reset on the site." +
|
"\n\nPlease note that the link is only valid for 24 hours so if you are unable to take action within that time period, you should initiate another password reset on the site." +
|
||||||
"\n\nIf you did not request to reset your password you can safely ignore this message." +
|
"\n\nIf you did not request to reset your password you can safely ignore this message." +
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
<Version>4.0.1</Version>
|
<Version>4.0.2</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -11,7 +11,7 @@
|
|||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.1</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.2</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<RootNamespace>Oqtane</RootNamespace>
|
<RootNamespace>Oqtane</RootNamespace>
|
||||||
|
@ -3,6 +3,9 @@ using Microsoft.AspNetCore.Authentication;
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
using Oqtane.Extensions;
|
||||||
|
using Oqtane.Infrastructure;
|
||||||
|
using Oqtane.Managers;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
|
|
||||||
namespace Oqtane.Pages
|
namespace Oqtane.Pages
|
||||||
@ -10,9 +13,28 @@ namespace Oqtane.Pages
|
|||||||
[Authorize]
|
[Authorize]
|
||||||
public class LogoutModel : PageModel
|
public class LogoutModel : PageModel
|
||||||
{
|
{
|
||||||
|
private readonly IUserManager _userManager;
|
||||||
|
private readonly ISyncManager _syncManager;
|
||||||
|
|
||||||
|
public LogoutModel(IUserManager userManager, ISyncManager syncManager)
|
||||||
|
{
|
||||||
|
_userManager = userManager;
|
||||||
|
_syncManager = syncManager;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<IActionResult> OnPostAsync(string returnurl)
|
public async Task<IActionResult> OnPostAsync(string returnurl)
|
||||||
{
|
{
|
||||||
await HttpContext.SignOutAsync(Constants.AuthenticationScheme);
|
if (HttpContext.User != null)
|
||||||
|
{
|
||||||
|
var alias = HttpContext.GetAlias();
|
||||||
|
var user = _userManager.GetUser(HttpContext.User.Identity.Name, alias.SiteId);
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
_syncManager.AddSyncEvent(alias.TenantId, EntityNames.User, user.UserId, SyncEventActions.Reload);
|
||||||
|
}
|
||||||
|
|
||||||
|
await HttpContext.SignOutAsync(Constants.AuthenticationScheme);
|
||||||
|
}
|
||||||
|
|
||||||
returnurl = (returnurl == null) ? "/" : returnurl;
|
returnurl = (returnurl == null) ? "/" : returnurl;
|
||||||
returnurl = (!returnurl.StartsWith("/")) ? "/" + returnurl : returnurl;
|
returnurl = (!returnurl.StartsWith("/")) ? "/" + returnurl : returnurl;
|
||||||
|
@ -4,7 +4,6 @@ using Oqtane.Shared;
|
|||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
|
||||||
using Oqtane.Repository;
|
using Oqtane.Repository;
|
||||||
using Microsoft.AspNetCore.Localization;
|
using Microsoft.AspNetCore.Localization;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
@ -38,10 +37,11 @@ namespace Oqtane.Pages
|
|||||||
private readonly IVisitorRepository _visitors;
|
private readonly IVisitorRepository _visitors;
|
||||||
private readonly IAliasRepository _aliases;
|
private readonly IAliasRepository _aliases;
|
||||||
private readonly ISettingRepository _settings;
|
private readonly ISettingRepository _settings;
|
||||||
private readonly ServerStateManager _serverState;
|
private readonly IThemeRepository _themes;
|
||||||
|
private readonly IServerStateManager _serverState;
|
||||||
private readonly ILogManager _logger;
|
private readonly ILogManager _logger;
|
||||||
|
|
||||||
public HostModel(IConfigManager configuration, ITenantManager tenantManager, ILocalizationManager localizationManager, ILanguageRepository languages, IAntiforgery antiforgery, IJwtManager jwtManager, ISiteRepository sites, IPageRepository pages, IUrlMappingRepository urlMappings, IVisitorRepository visitors, IAliasRepository aliases, ISettingRepository settings, ServerStateManager serverState, ILogManager logger)
|
public HostModel(IConfigManager configuration, ITenantManager tenantManager, ILocalizationManager localizationManager, ILanguageRepository languages, IAntiforgery antiforgery, IJwtManager jwtManager, ISiteRepository sites, IPageRepository pages, IUrlMappingRepository urlMappings, IVisitorRepository visitors, IAliasRepository aliases, ISettingRepository settings, IThemeRepository themes, IServerStateManager serverState, ILogManager logger)
|
||||||
{
|
{
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_tenantManager = tenantManager;
|
_tenantManager = tenantManager;
|
||||||
@ -55,6 +55,7 @@ namespace Oqtane.Pages
|
|||||||
_visitors = visitors;
|
_visitors = visitors;
|
||||||
_aliases = aliases;
|
_aliases = aliases;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
|
_themes = themes;
|
||||||
_serverState = serverState;
|
_serverState = serverState;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
@ -113,7 +114,7 @@ namespace Oqtane.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var site = _sites.InitializeSite(alias);
|
var site = _sites.GetSite(alias.SiteId);
|
||||||
if (site != null && (!site.IsDeleted || url.Contains("admin/site")) && site.Runtime != "Hybrid")
|
if (site != null && (!site.IsDeleted || url.Contains("admin/site")) && site.Runtime != "Hybrid")
|
||||||
{
|
{
|
||||||
Route route = new Route(url, alias.Path);
|
Route route = new Route(url, alias.Path);
|
||||||
@ -167,12 +168,13 @@ namespace Oqtane.Pages
|
|||||||
}
|
}
|
||||||
|
|
||||||
// stylesheets
|
// stylesheets
|
||||||
|
var themes = _themes.GetThemes().ToList();
|
||||||
var resources = new List<Resource>();
|
var resources = new List<Resource>();
|
||||||
if (string.IsNullOrEmpty(page.ThemeType))
|
if (string.IsNullOrEmpty(page.ThemeType))
|
||||||
{
|
{
|
||||||
page.ThemeType = site.DefaultThemeType;
|
page.ThemeType = site.DefaultThemeType;
|
||||||
}
|
}
|
||||||
var theme = site.Themes.FirstOrDefault(item => item.Themes.Any(item => item.TypeName == page.ThemeType));
|
var theme = themes.FirstOrDefault(item => item.Themes.Any(item => item.TypeName == page.ThemeType));
|
||||||
if (theme?.Resources != null)
|
if (theme?.Resources != null)
|
||||||
{
|
{
|
||||||
resources.AddRange(theme.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet).ToList());
|
resources.AddRange(theme.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet).ToList());
|
||||||
@ -199,7 +201,7 @@ namespace Oqtane.Pages
|
|||||||
}
|
}
|
||||||
HeadResources += ParseScripts(site.HeadContent);
|
HeadResources += ParseScripts(site.HeadContent);
|
||||||
BodyResources += ParseScripts(site.BodyContent);
|
BodyResources += ParseScripts(site.BodyContent);
|
||||||
var scripts = _serverState.GetServerState(site.SiteId).Scripts;
|
var scripts = _serverState.GetServerState(alias.SiteKey).Scripts;
|
||||||
foreach (var script in scripts)
|
foreach (var script in scripts)
|
||||||
{
|
{
|
||||||
AddScript(script, alias);
|
AddScript(script, alias);
|
||||||
|
@ -11,7 +11,7 @@ namespace Oqtane.Repository
|
|||||||
Site GetSite(int siteId);
|
Site GetSite(int siteId);
|
||||||
Site GetSite(int siteId, bool tracking);
|
Site GetSite(int siteId, bool tracking);
|
||||||
void DeleteSite(int siteId);
|
void DeleteSite(int siteId);
|
||||||
Site InitializeSite(Alias alias);
|
void InitializeSite(Alias alias);
|
||||||
void CreatePages(Site site, List<PageTemplate> pageTemplates, Alias alias);
|
void CreatePages(Site site, List<PageTemplate> pageTemplates, Alias alias);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,10 +21,10 @@ namespace Oqtane.Repository
|
|||||||
private readonly IPermissionRepository _permissions;
|
private readonly IPermissionRepository _permissions;
|
||||||
private readonly ITenantManager _tenants;
|
private readonly ITenantManager _tenants;
|
||||||
private readonly ISettingRepository _settings;
|
private readonly ISettingRepository _settings;
|
||||||
private readonly ServerStateManager _serverState;
|
private readonly IServerStateManager _serverState;
|
||||||
private readonly string settingprefix = "SiteEnabled:";
|
private readonly string settingprefix = "SiteEnabled:";
|
||||||
|
|
||||||
public ModuleDefinitionRepository(MasterDBContext context, IMemoryCache cache, IPermissionRepository permissions, ITenantManager tenants, ISettingRepository settings, ServerStateManager serverState)
|
public ModuleDefinitionRepository(MasterDBContext context, IMemoryCache cache, IPermissionRepository permissions, ITenantManager tenants, ISettingRepository settings, IServerStateManager serverState)
|
||||||
{
|
{
|
||||||
_db = context;
|
_db = context;
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
@ -179,6 +179,8 @@ namespace Oqtane.Repository
|
|||||||
|
|
||||||
if (siteId != -1)
|
if (siteId != -1)
|
||||||
{
|
{
|
||||||
|
var siteKey = _tenants.GetAlias().SiteKey;
|
||||||
|
|
||||||
// get all module definition permissions for site
|
// get all module definition permissions for site
|
||||||
List<Permission> permissions = _permissions.GetPermissions(siteId, EntityNames.ModuleDefinition).ToList();
|
List<Permission> permissions = _permissions.GetPermissions(siteId, EntityNames.ModuleDefinition).ToList();
|
||||||
|
|
||||||
@ -186,7 +188,7 @@ namespace Oqtane.Repository
|
|||||||
var settings = _settings.GetSettings(EntityNames.ModuleDefinition).ToList();
|
var settings = _settings.GetSettings(EntityNames.ModuleDefinition).ToList();
|
||||||
|
|
||||||
// populate module definition site settings and permissions
|
// populate module definition site settings and permissions
|
||||||
var serverState = _serverState.GetServerState(siteId);
|
var serverState = _serverState.GetServerState(siteKey);
|
||||||
foreach (ModuleDefinition moduledefinition in ModuleDefinitions)
|
foreach (ModuleDefinition moduledefinition in ModuleDefinitions)
|
||||||
{
|
{
|
||||||
moduledefinition.SiteId = siteId;
|
moduledefinition.SiteId = siteId;
|
||||||
@ -212,9 +214,9 @@ namespace Oqtane.Repository
|
|||||||
{
|
{
|
||||||
foreach (var assembly in moduledefinition.Dependencies.Replace(".dll", "").Split(',', StringSplitOptions.RemoveEmptyEntries).Reverse())
|
foreach (var assembly in moduledefinition.Dependencies.Replace(".dll", "").Split(',', StringSplitOptions.RemoveEmptyEntries).Reverse())
|
||||||
{
|
{
|
||||||
if (!serverState.Assemblies.Contains(assembly))
|
if (!serverState.Assemblies.Contains(assembly.Trim()))
|
||||||
{
|
{
|
||||||
serverState.Assemblies.Insert(0, assembly);
|
serverState.Assemblies.Insert(0, assembly.Trim());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -251,7 +253,6 @@ namespace Oqtane.Repository
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_serverState.SetServerState(siteId, serverState);
|
|
||||||
|
|
||||||
// clean up any orphaned permissions
|
// clean up any orphaned permissions
|
||||||
var ids = new HashSet<int>(ModuleDefinitions.Select(item => item.ModuleDefinitionId));
|
var ids = new HashSet<int>(ModuleDefinitions.Select(item => item.ModuleDefinitionId));
|
||||||
|
@ -27,13 +27,13 @@ namespace Oqtane.Repository
|
|||||||
private readonly IThemeRepository _themeRepository;
|
private readonly IThemeRepository _themeRepository;
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
private readonly IConfigurationRoot _config;
|
private readonly IConfigurationRoot _config;
|
||||||
private readonly ServerStateManager _serverState;
|
private readonly IServerStateManager _serverState;
|
||||||
private readonly ILogManager _logger;
|
private readonly ILogManager _logger;
|
||||||
private static readonly object _lock = new object();
|
private static readonly object _lock = new object();
|
||||||
|
|
||||||
public SiteRepository(TenantDBContext context, IRoleRepository roleRepository, IProfileRepository profileRepository, IFolderRepository folderRepository, IPageRepository pageRepository,
|
public SiteRepository(TenantDBContext context, IRoleRepository roleRepository, IProfileRepository profileRepository, IFolderRepository folderRepository, IPageRepository pageRepository,
|
||||||
IModuleRepository moduleRepository, IPageModuleRepository pageModuleRepository, IModuleDefinitionRepository moduleDefinitionRepository, IThemeRepository themeRepository, IServiceProvider serviceProvider,
|
IModuleRepository moduleRepository, IPageModuleRepository pageModuleRepository, IModuleDefinitionRepository moduleDefinitionRepository, IThemeRepository themeRepository, IServiceProvider serviceProvider,
|
||||||
IConfigurationRoot config, ServerStateManager serverState, ILogManager logger)
|
IConfigurationRoot config, IServerStateManager serverState, ILogManager logger)
|
||||||
{
|
{
|
||||||
_db = context;
|
_db = context;
|
||||||
_roleRepository = roleRepository;
|
_roleRepository = roleRepository;
|
||||||
@ -95,23 +95,25 @@ namespace Oqtane.Repository
|
|||||||
_db.SaveChanges();
|
_db.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Site InitializeSite(Alias alias)
|
public void InitializeSite(Alias alias)
|
||||||
{
|
{
|
||||||
var site = GetSite(alias.SiteId);
|
var serverstate = _serverState.GetServerState(alias.SiteKey);
|
||||||
|
if (!serverstate.IsInitialized)
|
||||||
// load themes and module definitions
|
|
||||||
site.Themes = _themeRepository.GetThemes().ToList();
|
|
||||||
var moduleDefinitions = _moduleDefinitionRepository.GetModuleDefinitions(alias.SiteId);
|
|
||||||
|
|
||||||
// site migrations
|
|
||||||
var serverstate = _serverState.GetServerState(alias.SiteId);
|
|
||||||
if (!serverstate.IsMigrated)
|
|
||||||
{
|
{
|
||||||
// ensure migrations are only executed once
|
// ensure site initialization is only executed once
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
if (!serverstate.IsMigrated)
|
if (!serverstate.IsInitialized)
|
||||||
{
|
{
|
||||||
|
var site = GetSite(alias.SiteId);
|
||||||
|
|
||||||
|
// initialize theme Assemblies and Scripts
|
||||||
|
site.Themes = _themeRepository.GetThemes().ToList();
|
||||||
|
|
||||||
|
// initialize module Assemblies and Scripts
|
||||||
|
var moduleDefinitions = _moduleDefinitionRepository.GetModuleDefinitions(alias.SiteId);
|
||||||
|
|
||||||
|
// execute migrations
|
||||||
var version = ProcessSiteMigrations(alias, site);
|
var version = ProcessSiteMigrations(alias, site);
|
||||||
version = ProcessPageTemplates(alias, site, moduleDefinitions, version);
|
version = ProcessPageTemplates(alias, site, moduleDefinitions, version);
|
||||||
if (site.Version != version)
|
if (site.Version != version)
|
||||||
@ -119,13 +121,11 @@ namespace Oqtane.Repository
|
|||||||
site.Version = version;
|
site.Version = version;
|
||||||
UpdateSite(site);
|
UpdateSite(site);
|
||||||
}
|
}
|
||||||
serverstate.IsMigrated = true;
|
|
||||||
_serverState.SetServerState(alias.SiteId, serverstate);
|
serverstate.IsInitialized = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return site;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ProcessSiteMigrations(Alias alias, Site site)
|
private string ProcessSiteMigrations(Alias alias, Site site)
|
||||||
@ -640,7 +640,7 @@ namespace Oqtane.Repository
|
|||||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||||
},
|
},
|
||||||
Content = "<p>The page you requested does not exist.</p>"
|
Content = "<p>The page you requested does not exist or you do not have sufficient rights to view it.</p>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user