Compare commits
167 Commits
Author | SHA1 | Date | |
---|---|---|---|
8b80f72313 | |||
06ebce31ca | |||
59db8ba997 | |||
df37d4aa7f | |||
fd9935c800 | |||
c057430488 | |||
767fa78e22 | |||
a0e289dcd6 | |||
c62d147254 | |||
f739bee353 | |||
db4dfb69fb | |||
9729a5ef16 | |||
6f12818352 | |||
75fc318da0 | |||
acf71cc2c2 | |||
42efe10473 | |||
b77e72880b | |||
297c1524b4 | |||
6140743769 | |||
d5ca700828 | |||
a7e1fe76c3 | |||
f6c55279d1 | |||
826f4835bb | |||
119a28def1 | |||
c1ffb8bc33 | |||
60cc9d14af | |||
7cf4f8fdaa | |||
1b84e83061 | |||
b0d2ee8760 | |||
2022432d35 | |||
c0ed335d84 | |||
4964562866 | |||
f78dc443ad | |||
56b47db778 | |||
2d4bf17b28 | |||
3b1819c68d | |||
575bbdb53b | |||
2fa7482028 | |||
e5062317e2 | |||
543f4fa3c2 | |||
49cdf69815 | |||
04196a1a19 | |||
b8622b8708 | |||
a2feca0ba3 | |||
ae6c6a75b2 | |||
bd987e9531 | |||
24d69fd820 | |||
9e2fa8d7f1 | |||
74ba2f7283 | |||
7603b5c63f | |||
03566afe66 | |||
3c2e314e2d | |||
1fcf08b5cd | |||
c13db89ed4 | |||
e68ae9e8a6 | |||
fb252d6db3 | |||
df959353d6 | |||
fbc443483d | |||
00f1dbc3dd | |||
c6021ff012 | |||
7a8cfcee35 | |||
c15586a1c4 | |||
be1d124e78 | |||
6fabf84d05 | |||
3299275da2 | |||
5539243bf3 | |||
c3d330f500 | |||
8c9e886136 | |||
cfde9944f8 | |||
b35d778abe | |||
1e9ee81df3 | |||
545d5730b6 | |||
28e645f9ca | |||
5b5c8a4beb | |||
6178be974a | |||
7771c3159b | |||
fc1e9c5d71 | |||
359de5b85e | |||
68dc4904cf | |||
057fd02e26 | |||
5c86ef6682 | |||
7c14bd799f | |||
edac046fcd | |||
8b23b386f7 | |||
e9bed59032 | |||
54077be32c | |||
30ad442dd1 | |||
b0c677d5a7 | |||
abe1b93e3c | |||
fd699cbb73 | |||
6f93ca11de | |||
916663b493 | |||
dbf2cddd87 | |||
d3c248cf5c | |||
bd93a94bb7 | |||
a46836e2a6 | |||
a1d88b4faa | |||
29741c0ec8 | |||
0b5fb92452 | |||
65782e87c1 | |||
6403df3330 | |||
c6a8f5305a | |||
d354e63267 | |||
836b174d15 | |||
4435f25ee6 | |||
4ab4bf4a3a | |||
d2f1d3c86c | |||
98257de005 | |||
5ea5c6ff7d | |||
441324d354 | |||
44f093b2fa | |||
38a16d1ae2 | |||
6b9de40442 | |||
d9c9eb9799 | |||
e88c8eee0f | |||
a6ca843ced | |||
6967a5cc14 | |||
e0ebf70907 | |||
53d0202f3b | |||
8daf38654d | |||
17337440f2 | |||
8e5e79a799 | |||
5c1cf14303 | |||
f2ad796104 | |||
886df69058 | |||
703aa95e60 | |||
7919e14d90 | |||
c8ef191660 | |||
840b656d1c | |||
d28516b6b1 | |||
5797bf549c | |||
e1ea721ea9 | |||
5ed1284baf | |||
e507023a03 | |||
2b328b9bb2 | |||
d155e13399 | |||
6993d4782d | |||
9267efce01 | |||
8c88cec863 | |||
b4b9976567 | |||
3cbd820d9c | |||
edd77b0222 | |||
c0991df9a2 | |||
26921c899e | |||
a1e5912d37 | |||
037f1ec887 | |||
89ab44590b | |||
4a20be8b34 | |||
32a401ba67 | |||
138c01aef8 | |||
3e54bc9c77 | |||
9966fc4651 | |||
c9ed5ec98f | |||
1f4ae5dbfb | |||
d0d3cc8faa | |||
7513ae28f0 | |||
c151c6f55a | |||
d491aeeba6 | |||
ab93d0acea | |||
f40f3f934f | |||
4d57adb393 | |||
e91db18677 | |||
9a88d65ff7 | |||
211d8c7f19 | |||
763cdca114 | |||
0d56d35646 | |||
d1e80cb86a |
@ -12,11 +12,12 @@
|
|||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||||
{
|
{
|
||||||
string url = NavigateUrl(p.Path);
|
string url = NavigateUrl(p.Path);
|
||||||
<div class="col-md-2 mx-auto text-center mb-3">
|
<p class="col-md-2 mx-auto text-center mb-3">
|
||||||
<NavLink class="nav-link text-primary" href="@url" Match="NavLinkMatch.All">
|
<NavLink class="nav-link text-primary" href="@url" Match="NavLinkMatch.All">
|
||||||
<h2><span class="@p.Icon" aria-hidden="true"></span></h2>@SharedLocalizer[p.Name]
|
<h2><span class="@p.Icon" aria-hidden="true"></span></h2>
|
||||||
|
<p class="lead">@((MarkupString)SharedLocalizer[p.Name].ToString().Replace(" ", "<br />"))</p>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</p>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
@ -67,6 +67,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
<br /><br />
|
||||||
|
|
||||||
@if (!_isSystem)
|
@if (!_isSystem)
|
||||||
{
|
{
|
||||||
@ -79,8 +80,7 @@
|
|||||||
@((MarkupString)" ")
|
@((MarkupString)" ")
|
||||||
<ActionDialog Header="Delete Folder" Message="Are You Sure You Wish To Delete This Folder?" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteFolder())" ResourceKey="DeleteFolder" />
|
<ActionDialog Header="Delete Folder" Message="Are You Sure You Wish To Delete This Folder?" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteFolder())" ResourceKey="DeleteFolder" />
|
||||||
}
|
}
|
||||||
<br />
|
<br /><br />
|
||||||
<br />
|
|
||||||
@if (PageState.QueryString.ContainsKey("id"))
|
@if (PageState.QueryString.ContainsKey("id"))
|
||||||
{
|
{
|
||||||
<AuditInfo CreatedBy="@_createdBy" CreatedOn="@_createdOn" ModifiedBy="@_modifiedBy" ModifiedOn="@_modifiedOn"></AuditInfo>
|
<AuditInfo CreatedBy="@_createdBy" CreatedOn="@_createdOn" ModifiedBy="@_modifiedBy" ModifiedOn="@_modifiedOn"></AuditInfo>
|
||||||
|
@ -8,27 +8,28 @@
|
|||||||
|
|
||||||
@if (_files != null)
|
@if (_files != null)
|
||||||
{
|
{
|
||||||
<div class="container">
|
<div class="row">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="col-md mb-1">
|
||||||
<div class="col-sm-2">
|
<ActionLink Action="Edit" Text="Add Folder" Class="btn btn-secondary" ResourceKey="AddFolder" />
|
||||||
<label class="control-label">@Localizer["Folder"] </label>
|
</div>
|
||||||
</div>
|
<div class="col-md-8 mb-1">
|
||||||
<div class="col-sm-6">
|
<div class="input-group">
|
||||||
|
<span class="input-group-text">@Localizer["Folder"]:</span>
|
||||||
<select class="form-select" @onchange="(e => FolderChanged(e))">
|
<select class="form-select" @onchange="(e => FolderChanged(e))">
|
||||||
@foreach (Folder folder in _folders)
|
@foreach (Folder folder in _folders)
|
||||||
{
|
{
|
||||||
<option value="@(folder.FolderId)">@(new string('-', folder.Level * 2))@(folder.Name)</option>
|
<option value="@(folder.FolderId)">@(new string('-', folder.Level * 2))@(folder.Name)</option>
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
|
||||||
<div class="col-sm-4">
|
|
||||||
<ActionLink Action="Edit" Text="Edit Folder" Class="btn btn-secondary" Parameters="@($"id=" + _folderId.ToString())" ResourceKey="EditFolder" />
|
<ActionLink Action="Edit" Text="Edit Folder" Class="btn btn-secondary" Parameters="@($"id=" + _folderId.ToString())" ResourceKey="EditFolder" />
|
||||||
<ActionLink Action="Edit" Text="Add Folder" Class="btn btn-secondary" ResourceKey="AddFolder" />
|
|
||||||
<ActionLink Action="Add" Text="Upload Files" Parameters="@($"id=" + _folderId.ToString())" ResourceKey="UploadFiles" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md mb-1 text-end">
|
||||||
|
<ActionLink Action="Add" Text="Upload Files" Parameters="@($"id=" + _folderId.ToString())" ResourceKey="UploadFiles" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Pager Items="@_files">
|
|
||||||
|
<Pager Items="@_files" SearchProperties="Name">
|
||||||
<Header>
|
<Header>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
|
@ -15,7 +15,7 @@ else
|
|||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<Pager Items="@_jobs">
|
<Pager Items="@_jobs" SearchProperties="Name">
|
||||||
<Header>
|
<Header>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
|
@ -14,7 +14,7 @@ else
|
|||||||
{
|
{
|
||||||
<ActionLink Action="Add" Text="Add Language" ResourceKey="AddLanguage" />
|
<ActionLink Action="Add" Text="Add Language" ResourceKey="AddLanguage" />
|
||||||
|
|
||||||
<Pager Items="@_languages">
|
<Pager Items="@_languages" SearchProperties="Name,Code">
|
||||||
<Header>
|
<Header>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th>@SharedLocalizer["Name"]</th>
|
<th>@SharedLocalizer["Name"]</th>
|
||||||
@ -146,7 +146,7 @@ else
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_package = await PackageService.GetPackageAsync(Constants.PackageId + "." + code, version);
|
_package = await PackageService.GetPackageAsync(Constants.PackageId + "." + code, version, false);
|
||||||
if (_package != null)
|
if (_package != null)
|
||||||
{
|
{
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
@ -168,7 +168,7 @@ else
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await PackageService.DownloadPackageAsync(_package.PackageId, _package.Version, Constants.PackagesFolder);
|
await PackageService.DownloadPackageAsync(_package.PackageId, _package.Version);
|
||||||
await logger.LogInformation("Language Package {Name} {Version} Downloaded Successfully", _package.PackageId, _package.Version);
|
await logger.LogInformation("Language Package {Name} {Version} Downloaded Successfully", _package.PackageId, _package.Version);
|
||||||
AddModuleMessage(string.Format(Localizer["Success.Language.Download"], NavigateUrl("admin/system")), MessageType.Success);
|
AddModuleMessage(string.Format(Localizer["Success.Language.Download"], NavigateUrl("admin/system")), MessageType.Success);
|
||||||
_package = null;
|
_package = null;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject IUserService UserService
|
@inject IUserService UserService
|
||||||
|
@inject ISettingService SettingService
|
||||||
@inject IServiceProvider ServiceProvider
|
@inject IServiceProvider ServiceProvider
|
||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
@ -92,23 +93,23 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
|
||||||
|
|
||||||
if (PageState.Site.Settings.ContainsKey("LoginOptions:AllowSiteLogin") && !string.IsNullOrEmpty(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"]))
|
|
||||||
{
|
|
||||||
_allowexternallogin = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PageState.QueryString.ContainsKey("returnurl"))
|
if (PageState.QueryString.ContainsKey("returnurl"))
|
||||||
{
|
{
|
||||||
_returnUrl = PageState.QueryString["returnurl"];
|
_returnUrl = PageState.QueryString["returnurl"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_allowexternallogin = (SettingService.GetSetting(PageState.Site.Settings, "ExternalLogin:ProviderType", "") != "") ? true : false;
|
||||||
|
_allowsitelogin = bool.Parse(SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:AllowSiteLogin", "true"));
|
||||||
|
|
||||||
|
if (_allowexternallogin && !_allowsitelogin)
|
||||||
|
{
|
||||||
|
// redirect to external login
|
||||||
|
NavigationManager.NavigateTo(Utilities.TenantUrl(PageState.Alias, "/pages/external?returnurl=" + _returnUrl), true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||||
|
|
||||||
if (PageState.QueryString.ContainsKey("name"))
|
if (PageState.QueryString.ContainsKey("name"))
|
||||||
{
|
{
|
||||||
_username = PageState.QueryString["name"];
|
_username = PageState.QueryString["name"];
|
||||||
@ -167,7 +168,7 @@
|
|||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
{
|
{
|
||||||
if (firstRender && PageState.User == null)
|
if (firstRender && PageState.User == null && _allowsitelogin)
|
||||||
{
|
{
|
||||||
await username.FocusAsync();
|
await username.FocusAsync();
|
||||||
}
|
}
|
||||||
@ -206,8 +207,7 @@
|
|||||||
if (hybrid)
|
if (hybrid)
|
||||||
{
|
{
|
||||||
// hybrid apps utilize an interactive login
|
// hybrid apps utilize an interactive login
|
||||||
var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider
|
var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider));
|
||||||
.GetService(typeof(IdentityAuthenticationStateProvider));
|
|
||||||
authstateprovider.NotifyAuthenticationChanged();
|
authstateprovider.NotifyAuthenticationChanged();
|
||||||
NavigationManager.NavigateTo(NavigateUrl(WebUtility.UrlDecode(_returnUrl), true));
|
NavigationManager.NavigateTo(NavigateUrl(WebUtility.UrlDecode(_returnUrl), true));
|
||||||
}
|
}
|
||||||
@ -221,7 +221,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((PageState.Site.Settings.ContainsKey("LoginOptions:TwoFactor") && PageState.Site.Settings["LoginOptions:TwoFactor"] == "required") || user.TwoFactorRequired)
|
if (SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:TwoFactor", "false") == "required" || user.TwoFactorRequired)
|
||||||
{
|
{
|
||||||
twofactor = true;
|
twofactor = true;
|
||||||
validated = false;
|
validated = false;
|
||||||
|
@ -48,7 +48,10 @@
|
|||||||
<select class="form-select" value="@_sort" @onchange="(e => SortChanged(e))">
|
<select class="form-select" value="@_sort" @onchange="(e => SortChanged(e))">
|
||||||
<option value="popularity">@SharedLocalizer["Search.Popularity"]</option>
|
<option value="popularity">@SharedLocalizer["Search.Popularity"]</option>
|
||||||
<option value="alphabetical">@SharedLocalizer["Search.Alphabetical"]</option>
|
<option value="alphabetical">@SharedLocalizer["Search.Alphabetical"]</option>
|
||||||
<option value="downloads">@SharedLocalizer["Search.Downloads"]</option>
|
@if (_price == "free")
|
||||||
|
{
|
||||||
|
<option value="downloads">@SharedLocalizer["Search.Downloads"]</option>
|
||||||
|
}
|
||||||
<option value="recent">@SharedLocalizer["Search.RecentlyReleased"]</option>
|
<option value="recent">@SharedLocalizer["Search.RecentlyReleased"]</option>
|
||||||
@if (_price == "paid")
|
@if (_price == "paid")
|
||||||
{
|
{
|
||||||
@ -63,6 +66,7 @@
|
|||||||
<div class="container-fluid px-0">
|
<div class="container-fluid px-0">
|
||||||
<div class="row g-0 mb-2">
|
<div class="row g-0 mb-2">
|
||||||
<div class="col-4">
|
<div class="col-4">
|
||||||
|
<a href="@context.ProductUrl" target="_blank">
|
||||||
@if (context.LogoUrl != null)
|
@if (context.LogoUrl != null)
|
||||||
{
|
{
|
||||||
<img src="@context.LogoUrl" class="img-fluid" alt="@context.Name" />
|
<img src="@context.LogoUrl" class="img-fluid" alt="@context.Name" />
|
||||||
@ -71,15 +75,24 @@
|
|||||||
{
|
{
|
||||||
<img src="/package.png" class="img-fluid" alt="@context.Name" />
|
<img src="/package.png" class="img-fluid" alt="@context.Name" />
|
||||||
}
|
}
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-8 text-end">
|
<div class="col-8 text-end">
|
||||||
<small>@SharedLocalizer["Search.Version"]:</small> <strong>@context.Version</strong>
|
<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>
|
<br /><small>@SharedLocalizer["Search.Released"]:</small> <strong>@context.ReleaseDate.ToString("MM/dd/yyyy")</strong>
|
||||||
@if (!string.IsNullOrEmpty(context.PackageUrl))
|
@if (!string.IsNullOrEmpty(context.PackageUrl))
|
||||||
{
|
{
|
||||||
<br /><small>@SharedLocalizer["Search.Source"]:</small> <strong>@(new Uri(context.PackageUrl).Host)</strong>
|
<br /><small>@SharedLocalizer["Search.Source"]:</small> <strong>@(new Uri(context.PackageUrl).Host)</strong>
|
||||||
}
|
}
|
||||||
|
@if (context.Price == null)
|
||||||
|
{
|
||||||
|
<br /><small>@SharedLocalizer["Search.Downloads"]:</small> <strong>@(String.Format("{0:n0}", context.Downloads))</strong>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<br /><small>@SharedLocalizer["From"]:</small> <strong>@context.Price.Value.ToString("$#,##0.00")</strong>
|
||||||
|
@((MarkupString)(context.TrialPeriod > 0 ? " <strong>(" + context.TrialPeriod + " Day Trial)</strong>" : ""))
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row g-0">
|
<div class="row g-0">
|
||||||
@ -87,17 +100,12 @@
|
|||||||
<h3 style="display: inline;"><a href="@context.ProductUrl" target="_blank">@context.Name</a></h3><br />
|
<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 />
|
<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 />
|
||||||
@if (context.Price != null && !string.IsNullOrEmpty(context.PaymentUrl))
|
|
||||||
{
|
|
||||||
<small>@SharedLocalizer["From"]:</small> <strong>@context.Price.Value.ToString("$#,##0.00")</strong>
|
|
||||||
@((MarkupString)(context.TrialPeriod > 0 ? " <strong>(" + context.TrialPeriod + " Day Trial)</strong>" : ""))
|
|
||||||
}
|
|
||||||
<br />
|
<br />
|
||||||
@if (!string.IsNullOrEmpty(context.PackageUrl))
|
@if (!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) && string.IsNullOrEmpty(context.PackageUrl))
|
@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>
|
<a class="btn btn-success ms-2" style="text-decoration: none !important" href="@context.PaymentUrl" target="_new">@SharedLocalizer["Buy"]</a>
|
||||||
}
|
}
|
||||||
@ -213,6 +221,7 @@
|
|||||||
private async void PriceChanged(string price)
|
private async void PriceChanged(string price)
|
||||||
{
|
{
|
||||||
_price = price;
|
_price = price;
|
||||||
|
_sort = "popularity";
|
||||||
await LoadModuleDefinitions();
|
await LoadModuleDefinitions();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
@ -256,7 +265,7 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var package = await PackageService.GetPackageAsync(packageid, version);
|
var package = await PackageService.GetPackageAsync(packageid, version, false);
|
||||||
if (package != null)
|
if (package != null)
|
||||||
{
|
{
|
||||||
_productname = package.Name;
|
_productname = package.Name;
|
||||||
@ -285,7 +294,7 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await PackageService.DownloadPackageAsync(_packageid, _packageversion, Constants.PackagesFolder);
|
await PackageService.DownloadPackageAsync(_packageid, _packageversion);
|
||||||
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _packageid, _packageversion);
|
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _packageid, _packageversion);
|
||||||
AddModuleMessage(string.Format(Localizer["Success.Module.Download"], NavigateUrl("admin/system")), MessageType.Success);
|
AddModuleMessage(string.Format(Localizer["Success.Module.Download"], NavigateUrl("admin/system")), MessageType.Success);
|
||||||
_productname = "";
|
_productname = "";
|
||||||
|
@ -89,7 +89,10 @@
|
|||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
AddModuleMessage(Localizer["Info.Module.Development"], MessageType.Info);
|
if (!NavigationManager.BaseUri.Contains("localhost:"))
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Info.Module.Development"], MessageType.Info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
@ -115,11 +118,18 @@
|
|||||||
{
|
{
|
||||||
if (IsValid(_owner) && IsValid(_module) && _owner != _module && _template != "-")
|
if (IsValid(_owner) && IsValid(_module) && _owner != _module && _template != "-")
|
||||||
{
|
{
|
||||||
var template = _templates.FirstOrDefault(item => item.Name == _template);
|
if (IsValidXML(_description))
|
||||||
var moduleDefinition = new ModuleDefinition { Owner = _owner, Name = _module, Description = _description, Template = _template, Version = _reference, ModuleDefinitionName = template.Namespace };
|
{
|
||||||
moduleDefinition = await ModuleDefinitionService.CreateModuleDefinitionAsync(moduleDefinition);
|
var template = _templates.FirstOrDefault(item => item.Name == _template);
|
||||||
GetLocation();
|
var moduleDefinition = new ModuleDefinition { Owner = _owner, Name = _module, Description = _description, Template = _template, Version = _reference, ModuleDefinitionName = template.Namespace };
|
||||||
AddModuleMessage(string.Format(Localizer["Success.Module.Create"], NavigateUrl("admin/system")), MessageType.Success);
|
moduleDefinition = await ModuleDefinitionService.CreateModuleDefinitionAsync(moduleDefinition);
|
||||||
|
GetLocation();
|
||||||
|
AddModuleMessage(string.Format(Localizer["Success.Module.Create"], NavigateUrl("admin/system")), MessageType.Success);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.Require.ValidDescription"], MessageType.Warning);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -143,6 +153,12 @@
|
|||||||
return !string.IsNullOrEmpty(name) && name.ToLower() != "module" && !name.ToLower().Contains("oqtane") && Regex.IsMatch(name, "^[A-Za-z_][A-Za-z0-9_]*$");
|
return !string.IsNullOrEmpty(name) && name.ToLower() != "module" && !name.ToLower().Contains("oqtane") && Regex.IsMatch(name, "^[A-Za-z_][A-Za-z0-9_]*$");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsValidXML(string description)
|
||||||
|
{
|
||||||
|
// must contain letters, digits, or spaces
|
||||||
|
return Regex.IsMatch(description, "^[A-Za-z0-9 .,!?]+$");
|
||||||
|
}
|
||||||
|
|
||||||
private void TemplateChanged(ChangeEventArgs e)
|
private void TemplateChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
_template = (string)e.Value;
|
_template = (string)e.Value;
|
||||||
|
@ -59,9 +59,26 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="packagename" HelpText="The unique name of the package from which this module was installed" ResourceKey="PackageName">Package Name: </Label>
|
<Label Class="col-sm-3" For="packagename" HelpText="The unique name of the package from which this module was installed. This value must be specified within the module's IModule interface specification." ResourceKey="PackageName">Package Name: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
|
@if (!string.IsNullOrEmpty(_packagename))
|
||||||
|
{
|
||||||
|
<div class="input-group">
|
||||||
|
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
|
||||||
|
@if (string.IsNullOrEmpty(_packageurl))
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="ValidatePackage">@Localizer["Validate"]</button>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<a href="@_packageurl" target="_blank" class="btn btn-primary">@SharedLocalizer["Download"]</a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -191,7 +208,7 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-success" @onclick="DownloadPackage">@SharedLocalizer["Accept"]</button>
|
<button type="button" class="btn btn-success" @onclick="DownloadTranslation">@SharedLocalizer["Accept"]</button>
|
||||||
<button type="button" class="btn btn-secondary" @onclick="HideModal">@SharedLocalizer["Cancel"]</button>
|
<button type="button" class="btn btn-secondary" @onclick="HideModal">@SharedLocalizer["Cancel"]</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -213,6 +230,7 @@
|
|||||||
private string _moduledefinitionname = "";
|
private string _moduledefinitionname = "";
|
||||||
private string _version;
|
private string _version;
|
||||||
private string _packagename = "";
|
private string _packagename = "";
|
||||||
|
private string _packageurl = "";
|
||||||
private string _owner = "";
|
private string _owner = "";
|
||||||
private string _url = "";
|
private string _url = "";
|
||||||
private string _contact = "";
|
private string _contact = "";
|
||||||
@ -364,7 +382,7 @@
|
|||||||
var version = _packages.Where(item => item.PackageId == packagename).FirstOrDefault().Version;
|
var version = _packages.Where(item => item.PackageId == packagename).FirstOrDefault().Version;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_package = await PackageService.GetPackageAsync(packagename, version);
|
_package = await PackageService.GetPackageAsync(packagename, version, false);
|
||||||
if (_package != null)
|
if (_package != null)
|
||||||
{
|
{
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
@ -382,11 +400,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DownloadPackage()
|
private async Task DownloadTranslation()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await PackageService.DownloadPackageAsync(_package.PackageId, _package.Version, Constants.PackagesFolder);
|
await PackageService.DownloadPackageAsync(_package.PackageId, _package.Version);
|
||||||
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _package.PackageId, _package.Version);
|
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _package.PackageId, _package.Version);
|
||||||
AddModuleMessage(string.Format(Localizer["Success.Translation.Download"], NavigateUrl("admin/system")), MessageType.Success);
|
AddModuleMessage(string.Format(Localizer["Success.Translation.Download"], NavigateUrl("admin/system")), MessageType.Success);
|
||||||
_package = null;
|
_package = null;
|
||||||
@ -398,4 +416,28 @@
|
|||||||
AddModuleMessage(Localizer["Error.Translation.Download"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Translation.Download"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task ValidatePackage()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var package = await PackageService.GetPackageAsync(_packagename, _version, true);
|
||||||
|
if (package == null || string.IsNullOrEmpty(package.PackageUrl))
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.Validate"], MessageType.Warning);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_packageurl = package.PackageUrl;
|
||||||
|
AddModuleMessage(Localizer["Message.Download"], MessageType.Info);
|
||||||
|
}
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Downloading Package {PackageId} {Version}", _packagename, _version);
|
||||||
|
AddModuleMessage(Localizer["Error.Validate"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -128,8 +128,7 @@ else
|
|||||||
private async Task LoadModuleDefinitions()
|
private async Task LoadModuleDefinitions()
|
||||||
{
|
{
|
||||||
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(_category)).ToList();
|
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(_category)).ToList();
|
||||||
var list = _moduleDefinitions.Where(item => !string.IsNullOrEmpty(item.PackageName)).Select(item => item.PackageName).Distinct().ToList();
|
_packages = await PackageService.GetPackageUpdatesAsync("module");
|
||||||
_packages = await PackageService.GetPackagesAsync(list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string PurchaseLink(string packagename)
|
private string PurchaseLink(string packagename)
|
||||||
@ -187,7 +186,7 @@ else
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await PackageService.DownloadPackageAsync(packagename, version, Constants.PackagesFolder);
|
await PackageService.DownloadPackageAsync(packagename, version);
|
||||||
await logger.LogInformation("Module Downloaded {ModuleDefinitionName} {Version}", packagename, version);
|
await logger.LogInformation("Module Downloaded {ModuleDefinitionName} {Version}", packagename, version);
|
||||||
AddModuleMessage(string.Format(Localizer["Success.Module.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
AddModuleMessage(string.Format(Localizer["Success.Module.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,17 @@
|
|||||||
<input id="title" type="text" class="form-control" @bind="@_title" required />
|
<input id="title" type="text" class="form-control" @bind="@_title" required />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="pane" HelpText="The pane where the module will be displayed" ResourceKey="Pane">Pane: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select class="form-select" @bind="@_pane">
|
||||||
|
@foreach (string pane in PageState.Page.Panes)
|
||||||
|
{
|
||||||
|
<option value="@pane">@pane Pane</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="container" HelpText="Select the module's container" ResourceKey="Container">Container: </Label>
|
<Label Class="col-sm-3" For="container" HelpText="Select the module's container" ResourceKey="Container">Container: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@ -112,6 +123,7 @@
|
|||||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||||
private string _module;
|
private string _module;
|
||||||
private string _title;
|
private string _title;
|
||||||
|
private string _pane;
|
||||||
private string _containerType;
|
private string _containerType;
|
||||||
private string _allPages = "false";
|
private string _allPages = "false";
|
||||||
private string _permissionNames = "";
|
private string _permissionNames = "";
|
||||||
@ -134,80 +146,82 @@
|
|||||||
{
|
{
|
||||||
_module = ModuleState.ModuleDefinition.Name;
|
_module = ModuleState.ModuleDefinition.Name;
|
||||||
_title = ModuleState.Title;
|
_title = ModuleState.Title;
|
||||||
|
_pane = ModuleState.Pane;
|
||||||
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, PageState.Page.ThemeType);
|
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, PageState.Page.ThemeType);
|
||||||
_containerType = ModuleState.ContainerType;
|
_containerType = ModuleState.ContainerType;
|
||||||
_allPages = ModuleState.AllPages.ToString();
|
_allPages = ModuleState.AllPages.ToString();
|
||||||
_permissions = ModuleState.PermissionList;
|
_permissions = ModuleState.PermissionList;
|
||||||
_pageId = ModuleState.PageId.ToString();
|
_pageId = ModuleState.PageId.ToString();
|
||||||
createdby = ModuleState.CreatedBy;
|
createdby = ModuleState.CreatedBy;
|
||||||
createdon = ModuleState.CreatedOn;
|
createdon = ModuleState.CreatedOn;
|
||||||
modifiedby = ModuleState.ModifiedBy;
|
modifiedby = ModuleState.ModifiedBy;
|
||||||
modifiedon = ModuleState.ModifiedOn;
|
modifiedon = ModuleState.ModifiedOn;
|
||||||
|
|
||||||
if (ModuleState.ModuleDefinition != null)
|
if (ModuleState.ModuleDefinition != null)
|
||||||
{
|
{
|
||||||
_permissionNames = ModuleState.ModuleDefinition?.PermissionNames;
|
_permissionNames = ModuleState.ModuleDefinition?.PermissionNames;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(ModuleState.ModuleDefinition.SettingsType))
|
if (!string.IsNullOrEmpty(ModuleState.ModuleDefinition.SettingsType))
|
||||||
{
|
{
|
||||||
// module settings type explicitly declared in IModule interface
|
// module settings type explicitly declared in IModule interface
|
||||||
_moduleSettingsType = Type.GetType(ModuleState.ModuleDefinition.SettingsType);
|
_moduleSettingsType = Type.GetType(ModuleState.ModuleDefinition.SettingsType);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// legacy support - module settings type determined by convention ( ie. existence of a "Settings.razor" component in module )
|
// legacy support - module settings type determined by convention ( ie. existence of a "Settings.razor" component in module )
|
||||||
_moduleSettingsType = Type.GetType(ModuleState.ModuleDefinition.ControlTypeTemplate.Replace(Constants.ActionToken, PageState.Action), false, true);
|
_moduleSettingsType = Type.GetType(ModuleState.ModuleDefinition.ControlTypeTemplate.Replace(Constants.ActionToken, PageState.Action), false, true);
|
||||||
}
|
}
|
||||||
if (_moduleSettingsType != null)
|
if (_moduleSettingsType != null)
|
||||||
{
|
{
|
||||||
var moduleobject = Activator.CreateInstance(_moduleSettingsType) as IModuleControl;
|
var moduleobject = Activator.CreateInstance(_moduleSettingsType) as IModuleControl;
|
||||||
if (!string.IsNullOrEmpty(moduleobject.Title))
|
if (!string.IsNullOrEmpty(moduleobject.Title))
|
||||||
{
|
{
|
||||||
_moduleSettingsTitle = moduleobject.Title;
|
_moduleSettingsTitle = moduleobject.Title;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModuleSettingsComponent = builder =>
|
ModuleSettingsComponent = builder =>
|
||||||
{
|
{
|
||||||
builder.OpenComponent(0, _moduleSettingsType);
|
builder.OpenComponent(0, _moduleSettingsType);
|
||||||
builder.AddComponentReferenceCapture(1, inst => { _moduleSettings = Convert.ChangeType(inst, _moduleSettingsType); });
|
builder.AddComponentReferenceCapture(1, inst => { _moduleSettings = Convert.ChangeType(inst, _moduleSettingsType); });
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddModuleMessage(string.Format(Localizer["Error.Module.Load"], ModuleState.ModuleDefinitionName), MessageType.Error);
|
AddModuleMessage(string.Format(Localizer["Error.Module.Load"], ModuleState.ModuleDefinitionName), MessageType.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
var theme = PageState.Site.Themes.FirstOrDefault(item => item.Containers.Any(themecontrol => themecontrol.TypeName.Equals(_containerType)));
|
var theme = PageState.Site.Themes.FirstOrDefault(item => item.Containers.Any(themecontrol => themecontrol.TypeName.Equals(_containerType)));
|
||||||
if (theme != null && !string.IsNullOrEmpty(theme.ContainerSettingsType))
|
if (theme != null && !string.IsNullOrEmpty(theme.ContainerSettingsType))
|
||||||
{
|
{
|
||||||
_containerSettingsType = Type.GetType(theme.ContainerSettingsType);
|
_containerSettingsType = Type.GetType(theme.ContainerSettingsType);
|
||||||
if (_containerSettingsType != null)
|
if (_containerSettingsType != null)
|
||||||
{
|
{
|
||||||
ContainerSettingsComponent = builder =>
|
ContainerSettingsComponent = builder =>
|
||||||
{
|
{
|
||||||
builder.OpenComponent(0, _containerSettingsType);
|
builder.OpenComponent(0, _containerSettingsType);
|
||||||
builder.AddComponentReferenceCapture(1, inst => { _containerSettings = Convert.ChangeType(inst, _containerSettingsType); });
|
builder.AddComponentReferenceCapture(1, inst => { _containerSettings = Convert.ChangeType(inst, _containerSettingsType); });
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SaveModule()
|
private async Task SaveModule()
|
||||||
{
|
{
|
||||||
validated = true;
|
validated = true;
|
||||||
var interop = new Interop(JSRuntime);
|
var interop = new Interop(JSRuntime);
|
||||||
if (await interop.FormValid(form))
|
if (await interop.FormValid(form))
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(_title))
|
if (!string.IsNullOrEmpty(_title))
|
||||||
{
|
{
|
||||||
var pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
|
var pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
|
||||||
pagemodule.PageId = int.Parse(_pageId);
|
pagemodule.PageId = int.Parse(_pageId);
|
||||||
pagemodule.Title = _title;
|
pagemodule.Title = _title;
|
||||||
pagemodule.ContainerType = (_containerType != "-") ? _containerType : string.Empty;
|
pagemodule.Pane = _pane;
|
||||||
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Page.DefaultContainerType)
|
pagemodule.ContainerType = (_containerType != "-") ? _containerType : string.Empty;
|
||||||
|
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Page.DefaultContainerType)
|
||||||
{
|
{
|
||||||
pagemodule.ContainerType = string.Empty;
|
pagemodule.ContainerType = string.Empty;
|
||||||
}
|
}
|
||||||
|
@ -40,9 +40,9 @@
|
|||||||
<Label Class="col-sm-3" For="insert" HelpText="Select the location where you would like the page to be inserted in relation to other pages" ResourceKey="Insert">Insert: </Label>
|
<Label Class="col-sm-3" For="insert" HelpText="Select the location where you would like the page to be inserted in relation to other pages" ResourceKey="Insert">Insert: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="insert" class="form-select" @bind="@_insert" required>
|
<select id="insert" class="form-select" @bind="@_insert" required>
|
||||||
<option value="<<">@Localizer["AtBeginning"]</option>
|
|
||||||
@if (_children != null && _children.Count > 0)
|
@if (_children != null && _children.Count > 0)
|
||||||
{
|
{
|
||||||
|
<option value="<<">@Localizer["AtBeginning"]</option>
|
||||||
<option value="<">@Localizer["Before"]</option>
|
<option value="<">@Localizer["Before"]</option>
|
||||||
<option value=">">@Localizer["After"]</option>
|
<option value=">">@Localizer["After"]</option>
|
||||||
}
|
}
|
||||||
@ -257,7 +257,14 @@
|
|||||||
_themes = ThemeService.GetThemeControls(PageState.Site.Themes);
|
_themes = ThemeService.GetThemeControls(PageState.Site.Themes);
|
||||||
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
||||||
_containertype = PageState.Site.DefaultContainerType;
|
_containertype = PageState.Site.DefaultContainerType;
|
||||||
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
|
_children = new List<Page>();
|
||||||
|
foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
|
||||||
|
{
|
||||||
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||||
|
{
|
||||||
|
_children.Add(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
ThemeSettings();
|
ThemeSettings();
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
}
|
}
|
||||||
@ -279,28 +286,15 @@
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
_parentid = (string)e.Value;
|
_parentid = (string)e.Value;
|
||||||
_children = new List<Page>();
|
_children = new List<Page>();
|
||||||
if (_parentid == "-1")
|
foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
|
||||||
{
|
{
|
||||||
foreach (Page p in PageState.Pages.Where(item => item.ParentId == null))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
_children.Add(p);
|
||||||
{
|
}
|
||||||
_children.Add(p);
|
}
|
||||||
}
|
StateHasChanged();
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)))
|
|
||||||
{
|
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
|
||||||
{
|
|
||||||
_children.Add(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -48,13 +48,16 @@
|
|||||||
{
|
{
|
||||||
<option value="="><@Localizer["ThisLocation.Keep"]></option>
|
<option value="="><@Localizer["ThisLocation.Keep"]></option>
|
||||||
}
|
}
|
||||||
<option value="<<">@Localizer["ToBeginning"]</option>
|
|
||||||
@if (_children != null && _children.Count > 0)
|
@if (_children != null && _children.Count > 0)
|
||||||
{
|
{
|
||||||
|
<option value="<<">@Localizer["ToBeginning"]</option>
|
||||||
<option value="<">@Localizer["Before"]</option>
|
<option value="<">@Localizer["Before"]</option>
|
||||||
<option value=">">@Localizer["After"]</option>
|
<option value=">">@Localizer["After"]</option>
|
||||||
}
|
}
|
||||||
<option value=">>">@Localizer["ToEnd"]</option>
|
@if (_parentid != _currentparentid)
|
||||||
|
{
|
||||||
|
<option value=">>">@Localizer["ToEnd"]</option>
|
||||||
|
}
|
||||||
</select>
|
</select>
|
||||||
@if (_children != null && _children.Count > 0 && (_insert == "<" || _insert == ">"))
|
@if (_children != null && _children.Count > 0 && (_insert == "<" || _insert == ">"))
|
||||||
{
|
{
|
||||||
@ -209,7 +212,7 @@
|
|||||||
<th>@Localizer["ModuleDefinition"]</th>
|
<th>@Localizer["ModuleDefinition"]</th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><ActionLink Action="Settings" Text="Edit" ModuleId="@context.ModuleId" Security="SecurityAccessLevel.Edit" PermissionList="@context.PermissionList" ResourceKey="ModuleSettings" /></td>
|
<td><ActionLink Action="Settings" Text="Edit" Path="@_actualpath" ModuleId="@context.ModuleId" Security="SecurityAccessLevel.Edit" PermissionList="@context.PermissionList" ResourceKey="ModuleSettings" /></td>
|
||||||
<td><ActionDialog Header="Delete Module" Message="Are You Sure You Wish To Delete This Module?" Action="Delete" Security="SecurityAccessLevel.Edit" PermissionList="@context.PermissionList" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" ResourceKey="DeleteModule" /></td>
|
<td><ActionDialog Header="Delete Module" Message="Are You Sure You Wish To Delete This Module?" Action="Delete" Security="SecurityAccessLevel.Edit" PermissionList="@context.PermissionList" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" ResourceKey="DeleteModule" /></td>
|
||||||
<td>@context.Title</td>
|
<td>@context.Title</td>
|
||||||
<td>@context.ModuleDefinition?.Name</td>
|
<td>@context.ModuleDefinition?.Name</td>
|
||||||
@ -292,6 +295,7 @@
|
|||||||
private int _childid = -1;
|
private int _childid = -1;
|
||||||
private string _isnavigation;
|
private string _isnavigation;
|
||||||
private string _isclickable;
|
private string _isclickable;
|
||||||
|
private string _actualpath;
|
||||||
private string _path;
|
private string _path;
|
||||||
private string _url;
|
private string _url;
|
||||||
private string _ispersonalizable;
|
private string _ispersonalizable;
|
||||||
@ -323,7 +327,6 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
|
|
||||||
_pageId = Int32.Parse(PageState.QueryString["id"]);
|
_pageId = Int32.Parse(PageState.QueryString["id"]);
|
||||||
_page = await PageService.GetPageAsync(_pageId);
|
_page = await PageService.GetPageAsync(_pageId);
|
||||||
_icons = await SystemService.GetIconsAsync();
|
_icons = await SystemService.GetIconsAsync();
|
||||||
@ -341,10 +344,19 @@
|
|||||||
_parentid = _page.ParentId.ToString();
|
_parentid = _page.ParentId.ToString();
|
||||||
_parent = PageState.Pages.FirstOrDefault(item => item.PageId == _page.ParentId);
|
_parent = PageState.Pages.FirstOrDefault(item => item.PageId == _page.ParentId);
|
||||||
}
|
}
|
||||||
|
_children = new List<Page>();
|
||||||
|
foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
|
||||||
|
{
|
||||||
|
if (p.PageId != _pageId && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||||
|
{
|
||||||
|
_children.Add(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
_currentparentid = _parentid;
|
_currentparentid = _parentid;
|
||||||
_isnavigation = _page.IsNavigation.ToString();
|
_isnavigation = _page.IsNavigation.ToString();
|
||||||
_isclickable = _page.IsClickable.ToString();
|
_isclickable = _page.IsClickable.ToString();
|
||||||
_path = _page.Path;
|
_actualpath = _page.Path;
|
||||||
|
_path = _actualpath;
|
||||||
if (string.IsNullOrEmpty(_path))
|
if (string.IsNullOrEmpty(_path))
|
||||||
{
|
{
|
||||||
_path = "/";
|
_path = "/";
|
||||||
@ -363,7 +375,7 @@
|
|||||||
// appearance
|
// appearance
|
||||||
_title = _page.Title;
|
_title = _page.Title;
|
||||||
_themetype = _page.ThemeType;
|
_themetype = _page.ThemeType;
|
||||||
if (string.IsNullOrEmpty(_themetype) || ThemeService.GetTheme(PageState.Site.Themes, _themetype)?.ThemeName != ThemeService.GetTheme(PageState.Site.Themes, PageState.Site.DefaultThemeType)?.ThemeName)
|
if (string.IsNullOrEmpty(_themetype))
|
||||||
{
|
{
|
||||||
_themetype = PageState.Site.DefaultThemeType;
|
_themetype = PageState.Site.DefaultThemeType;
|
||||||
}
|
}
|
||||||
@ -415,34 +427,14 @@
|
|||||||
{
|
{
|
||||||
_parentid = (string)e.Value;
|
_parentid = (string)e.Value;
|
||||||
_children = new List<Page>();
|
_children = new List<Page>();
|
||||||
if (_parentid == "-1")
|
foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
|
||||||
{
|
{
|
||||||
foreach (Page p in PageState.Pages.Where(item => item.ParentId == null))
|
if (p.PageId != _pageId && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
_children.Add(p);
|
||||||
{
|
|
||||||
_children.Add(p);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
_insert = (_parentid == _currentparentid) ? "=" : ">>";
|
||||||
{
|
|
||||||
foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)))
|
|
||||||
{
|
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
|
||||||
{
|
|
||||||
_children.Add(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_parentid == _currentparentid)
|
|
||||||
{
|
|
||||||
_insert = "=";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_insert = ">>";
|
|
||||||
}
|
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -672,5 +664,4 @@
|
|||||||
{
|
{
|
||||||
_icon = NewIcon;
|
_icon = NewIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
{
|
{
|
||||||
<ActionLink Action="Add" Text="Add Page" ResourceKey="AddPage" />
|
<ActionLink Action="Add" Text="Add Page" ResourceKey="AddPage" />
|
||||||
|
|
||||||
<Pager Items="@PageState.Pages.Where(item => !item.IsDeleted)">
|
<Pager Items="@PageState.Pages.Where(item => !item.IsDeleted)" SearchProperties="Name">
|
||||||
<Header>
|
<Header>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="description" HelpText="The help text displayed to the user for this profile item" ResourceKey="Description">Description: </Label>
|
<Label Class="col-sm-3" For="description" HelpText="The help text displayed to the user for this profile item" ResourceKey="Description">Description: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<textarea id="description" class="form-control" @bind="@_description" rows="5" maxlength="256" required ></textarea>
|
<textarea id="description" class="form-control" @bind="@_description" rows="3" maxlength="256" required ></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -43,6 +43,12 @@
|
|||||||
<input id="length" class="form-control" @bind="@_maxlength" maxlength="4" required />
|
<input id="length" class="form-control" @bind="@_maxlength" maxlength="4" required />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="rows" HelpText="The number of rows for text entry (one is the default)" ResourceKey="Rows">Rows: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="rows" class="form-control" @bind="@_rows" maxlength="2" required />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="defaultVal" HelpText="The default value for this profile item" ResourceKey="DefaultValue">Default Value: </Label>
|
<Label Class="col-sm-3" For="defaultVal" HelpText="The default value for this profile item" ResourceKey="DefaultValue">Default Value: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@ -101,6 +107,7 @@
|
|||||||
private string _category = string.Empty;
|
private string _category = string.Empty;
|
||||||
private string _vieworder = "0";
|
private string _vieworder = "0";
|
||||||
private string _maxlength = "0";
|
private string _maxlength = "0";
|
||||||
|
private string _rows = "1";
|
||||||
private string _defaultvalue = string.Empty;
|
private string _defaultvalue = string.Empty;
|
||||||
private string _options = string.Empty;
|
private string _options = string.Empty;
|
||||||
private string _validation = string.Empty;
|
private string _validation = string.Empty;
|
||||||
@ -131,6 +138,7 @@
|
|||||||
_category = profile.Category;
|
_category = profile.Category;
|
||||||
_vieworder = profile.ViewOrder.ToString();
|
_vieworder = profile.ViewOrder.ToString();
|
||||||
_maxlength = profile.MaxLength.ToString();
|
_maxlength = profile.MaxLength.ToString();
|
||||||
|
_rows = profile.Rows.ToString();
|
||||||
_defaultvalue = profile.DefaultValue;
|
_defaultvalue = profile.DefaultValue;
|
||||||
_options = profile.Options;
|
_options = profile.Options;
|
||||||
_validation = profile.Validation;
|
_validation = profile.Validation;
|
||||||
@ -175,6 +183,7 @@
|
|||||||
profile.Category = _category;
|
profile.Category = _category;
|
||||||
profile.ViewOrder = int.Parse(_vieworder);
|
profile.ViewOrder = int.Parse(_vieworder);
|
||||||
profile.MaxLength = int.Parse(_maxlength);
|
profile.MaxLength = int.Parse(_maxlength);
|
||||||
|
profile.Rows = int.Parse(_rows);
|
||||||
profile.DefaultValue = _defaultvalue;
|
profile.DefaultValue = _defaultvalue;
|
||||||
profile.Options = _options;
|
profile.Options = _options;
|
||||||
profile.Validation = _validation;
|
profile.Validation = _validation;
|
||||||
|
@ -12,16 +12,22 @@ else
|
|||||||
{
|
{
|
||||||
<ActionLink Action="Add" Text="Add Profile" Security="SecurityAccessLevel.Edit" ResourceKey="AddProfile" />
|
<ActionLink Action="Add" Text="Add Profile" Security="SecurityAccessLevel.Edit" ResourceKey="AddProfile" />
|
||||||
|
|
||||||
<Pager Items="@_profiles">
|
<Pager Items="@_profiles" SearchProperties="Title,Category">
|
||||||
<Header>
|
<Header>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th>@SharedLocalizer["Name"]</th>
|
<th>@SharedLocalizer["Name"]</th>
|
||||||
|
<th>@Localizer["Title"]</th>
|
||||||
|
<th>@Localizer["Category"]</th>
|
||||||
|
<th>@Localizer["Order"]</th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ProfileId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="EditProfile" /></td>
|
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ProfileId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="EditProfile" /></td>
|
||||||
<td><ActionDialog Header="Delete Profile" Message="@string.Format(Localizer["Confirm.Profile.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteProfile(context.ProfileId))" ResourceKey="DeleteProfile" /></td>
|
<td><ActionDialog Header="Delete Profile" Message="@string.Format(Localizer["Confirm.Profile.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteProfile(context.ProfileId))" ResourceKey="DeleteProfile" /></td>
|
||||||
<td>@context.Name</td>
|
<td>@context.Name</td>
|
||||||
|
<td>@context.Title</td>
|
||||||
|
<td>@context.Category</td>
|
||||||
|
<td>@context.ViewOrder</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||||
|
<ModuleMessage Message="@_passwordrequirements" Type="MessageType.Info" />
|
||||||
<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="username" HelpText="Your username will be populated from the link you received in the password reset notification" ResourceKey="Username">Username: </Label>
|
<Label Class="col-sm-3" For="username" HelpText="Your username will be populated from the link you received in the password reset notification" ResourceKey="Username">Username: </Label>
|
||||||
@ -45,12 +46,14 @@
|
|||||||
private string _passwordtype = "password";
|
private string _passwordtype = "password";
|
||||||
private string _togglepassword = string.Empty;
|
private string _togglepassword = string.Empty;
|
||||||
private string _confirm = string.Empty;
|
private string _confirm = string.Empty;
|
||||||
|
private string _passwordrequirements;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||||
|
_passwordrequirements = await UserService.GetPasswordRequirementsAsync(PageState.Site.SiteId);
|
||||||
|
|
||||||
if (PageState.QueryString.ContainsKey("name") && PageState.QueryString.ContainsKey("token"))
|
if (PageState.QueryString.ContainsKey("name") && PageState.QueryString.ContainsKey("token"))
|
||||||
{
|
{
|
||||||
|
@ -12,7 +12,7 @@ else
|
|||||||
{
|
{
|
||||||
<ActionLink Action="Add" Text="Add Role" Security="SecurityAccessLevel.Edit" ResourceKey="AddRole" />
|
<ActionLink Action="Add" Text="Add Role" Security="SecurityAccessLevel.Edit" ResourceKey="AddRole" />
|
||||||
|
|
||||||
<Pager Items="@_roles">
|
<Pager Items="@_roles" SearchProperties="Name">
|
||||||
<Header>
|
<Header>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
|
@ -49,9 +49,18 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="sitemap" HelpText="The site map url for this site which can be submitted to search engines for indexing" ResourceKey="SiteMap">Site Map: </Label>
|
<Label Class="col-sm-3" For="sitemap" HelpText="The site map url for this site which can be submitted to search engines for indexing" ResourceKey="SiteMap">Site Map: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="sitemap" class="form-control" @bind="@_sitemap" required disabled />
|
<div class="input-group">
|
||||||
</div>
|
<input id="sitemap" class="form-control" @bind="@_sitemap" disabled />
|
||||||
|
<a href="@_sitemap" class="btn btn-secondary" target="_new">@Localizer["Browse"]</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="siteguid" HelpText="The Unique Identifier For The Site" ResourceKey="SiteGuid">ID: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="siteguid" class="form-control" @bind="@_siteguid" required disabled />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="version" HelpText="The site version (for site content migrations)" ResourceKey="Version">Version: </Label>
|
<Label Class="col-sm-3" For="version" HelpText="The site version (for site content migrations)" ResourceKey="Version">Version: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@ -348,6 +357,7 @@
|
|||||||
private string _homepageid = "-";
|
private string _homepageid = "-";
|
||||||
private string _isdeleted;
|
private string _isdeleted;
|
||||||
private string _sitemap = "";
|
private string _sitemap = "";
|
||||||
|
private string _siteguid = "";
|
||||||
private string _version = "";
|
private string _version = "";
|
||||||
private int _logofileid = -1;
|
private int _logofileid = -1;
|
||||||
private FileManager _logofilemanager;
|
private FileManager _logofilemanager;
|
||||||
@ -406,6 +416,7 @@
|
|||||||
}
|
}
|
||||||
_isdeleted = site.IsDeleted.ToString();
|
_isdeleted = site.IsDeleted.ToString();
|
||||||
_sitemap = PageState.Alias.Protocol + PageState.Alias.Name + "/pages/sitemap.xml";
|
_sitemap = PageState.Alias.Protocol + PageState.Alias.Name + "/pages/sitemap.xml";
|
||||||
|
_siteguid = site.SiteGuid;
|
||||||
_version = site.Version;
|
_version = site.Version;
|
||||||
|
|
||||||
// appearance
|
// appearance
|
||||||
@ -602,7 +613,7 @@
|
|||||||
|
|
||||||
// SMTP
|
// SMTP
|
||||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPHost", _smtphost, true);
|
settings = SettingService.SetSetting(settings, "SMTPHost", _smtphost, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPPort", _smtpport, true);
|
settings = SettingService.SetSetting(settings, "SMTPPort", _smtpport, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, true);
|
settings = SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
settings = SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
||||||
@ -610,6 +621,7 @@
|
|||||||
settings = SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
settings = SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPRelay", _smtprelay, true);
|
settings = SettingService.SetSetting(settings, "SMTPRelay", _smtprelay, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPEnabled", _smtpenabled, true);
|
settings = SettingService.SetSetting(settings, "SMTPEnabled", _smtpenabled, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "SiteGuid", _siteguid, true);
|
||||||
settings = SettingService.SetSetting(settings, "NotificationRetention", _retention, true);
|
settings = SettingService.SetSetting(settings, "NotificationRetention", _retention, true);
|
||||||
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
|
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ else
|
|||||||
{
|
{
|
||||||
<ActionLink Action="Add" Text="Add Site" ResourceKey="AddSite" />
|
<ActionLink Action="Add" Text="Add Site" ResourceKey="AddSite" />
|
||||||
|
|
||||||
<Pager Items="@_sites">
|
<Pager Items="@_sites" SearchProperties="Name">
|
||||||
<Header>
|
<Header>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
|
@ -48,7 +48,10 @@
|
|||||||
<select class="form-select" value="@_sort" @onchange="(e => SortChanged(e))">
|
<select class="form-select" value="@_sort" @onchange="(e => SortChanged(e))">
|
||||||
<option value="popularity">@SharedLocalizer["Search.Popularity"]</option>
|
<option value="popularity">@SharedLocalizer["Search.Popularity"]</option>
|
||||||
<option value="alphabetical">@SharedLocalizer["Search.Alphabetical"]</option>
|
<option value="alphabetical">@SharedLocalizer["Search.Alphabetical"]</option>
|
||||||
<option value="downloads">@SharedLocalizer["Search.Downloads"]</option>
|
@if (_price == "free")
|
||||||
|
{
|
||||||
|
<option value="downloads">@SharedLocalizer["Search.Downloads"]</option>
|
||||||
|
}
|
||||||
<option value="recent">@SharedLocalizer["Search.RecentlyReleased"]</option>
|
<option value="recent">@SharedLocalizer["Search.RecentlyReleased"]</option>
|
||||||
@if (_price == "paid")
|
@if (_price == "paid")
|
||||||
{
|
{
|
||||||
@ -63,6 +66,7 @@
|
|||||||
<div class="container-fluid px-0">
|
<div class="container-fluid px-0">
|
||||||
<div class="row g-0 mb-2">
|
<div class="row g-0 mb-2">
|
||||||
<div class="col-4">
|
<div class="col-4">
|
||||||
|
<a href="@context.ProductUrl" target="_blank">
|
||||||
@if (context.LogoUrl != null)
|
@if (context.LogoUrl != null)
|
||||||
{
|
{
|
||||||
<img src="@context.LogoUrl" class="img-fluid" alt="@context.Name" />
|
<img src="@context.LogoUrl" class="img-fluid" alt="@context.Name" />
|
||||||
@ -71,16 +75,23 @@
|
|||||||
{
|
{
|
||||||
<img src="/package.png" class="img-fluid" alt="@context.Name" />
|
<img src="/package.png" class="img-fluid" alt="@context.Name" />
|
||||||
}
|
}
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-8 text-end">
|
<div class="col-8 text-end">
|
||||||
<small>@SharedLocalizer["Search.Version"]:</small> <strong>@context.Version</strong>
|
<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>
|
<br /><small>@SharedLocalizer["Search.Released"]:</small> <strong>@context.ReleaseDate.ToString("MM/dd/yyyy")</strong>
|
||||||
@if (!string.IsNullOrEmpty(context.PackageUrl))
|
@if (!string.IsNullOrEmpty(context.PackageUrl))
|
||||||
{
|
{
|
||||||
<br />
|
<br /><small>@SharedLocalizer["Search.Source"]:</small> <strong>@(new Uri(context.PackageUrl).Host)</strong>
|
||||||
|
}
|
||||||
<small>@SharedLocalizer["Search.Source"]:</small> <strong>@(new Uri(context.PackageUrl).Host)</strong>
|
@if (context.Price == null)
|
||||||
|
{
|
||||||
|
<br /><small>@SharedLocalizer["Search.Downloads"]:</small> <strong>@(String.Format("{0:n0}", context.Downloads))</strong>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<br /><small>@SharedLocalizer["From"]:</small> <strong>@context.Price.Value.ToString("$#,##0.00")</strong>
|
||||||
|
@((MarkupString)(context.TrialPeriod > 0 ? " <strong>(" + context.TrialPeriod + " Day Trial)</strong>" : ""))
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -89,17 +100,12 @@
|
|||||||
<h3 style="display: inline;"><a href="@context.ProductUrl" target="_blank">@context.Name</a></h3><br />
|
<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 />
|
<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 />
|
||||||
@if (context.Price != null && !string.IsNullOrEmpty(context.PaymentUrl))
|
|
||||||
{
|
|
||||||
<small>@SharedLocalizer["From"]:</small> <strong>@context.Price.Value.ToString("$#,##0.00")</strong>
|
|
||||||
@((MarkupString)(context.TrialPeriod > 0 ? " <strong>(" + context.TrialPeriod + " Day Trial)</strong>" : ""))
|
|
||||||
}
|
|
||||||
<br />
|
<br />
|
||||||
@if (!string.IsNullOrEmpty(context.PackageUrl))
|
@if (!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) && string.IsNullOrEmpty(context.PackageUrl))
|
@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>
|
<a class="btn btn-success ms-2" style="text-decoration: none !important" href="@context.PaymentUrl" target="_new">@SharedLocalizer["Buy"]</a>
|
||||||
}
|
}
|
||||||
@ -215,6 +221,7 @@
|
|||||||
private async void PriceChanged(string price)
|
private async void PriceChanged(string price)
|
||||||
{
|
{
|
||||||
_price = price;
|
_price = price;
|
||||||
|
_sort = "popularity";
|
||||||
await LoadThemes();
|
await LoadThemes();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
@ -258,7 +265,7 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var package = await PackageService.GetPackageAsync(packageid, version);
|
var package = await PackageService.GetPackageAsync(packageid, version, false);
|
||||||
if (package != null)
|
if (package != null)
|
||||||
{
|
{
|
||||||
_productname = package.Name;
|
_productname = package.Name;
|
||||||
@ -287,7 +294,7 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await PackageService.DownloadPackageAsync(_packageid, _version, Constants.PackagesFolder);
|
await PackageService.DownloadPackageAsync(_packageid, _version);
|
||||||
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _packageid, _version);
|
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _packageid, _version);
|
||||||
AddModuleMessage(string.Format(Localizer["Success.Theme.Download"], NavigateUrl("admin/system")), MessageType.Success);
|
AddModuleMessage(string.Format(Localizer["Success.Theme.Download"], NavigateUrl("admin/system")), MessageType.Success);
|
||||||
_productname = "";
|
_productname = "";
|
||||||
|
@ -80,7 +80,10 @@
|
|||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
AddModuleMessage(Localizer["Info.Theme.CreatorIntent"], MessageType.Info);
|
if (!NavigationManager.BaseUri.Contains("localhost:"))
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Info.Theme.CreatorIntent"], MessageType.Info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
@using System.Net
|
@using System.Net
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject IThemeService ThemeService
|
@inject IThemeService ThemeService
|
||||||
|
@inject IPackageService PackageService
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject IStringLocalizer<Edit> Localizer
|
@inject IStringLocalizer<Edit> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
@ -42,10 +43,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="packagename" HelpText="The unique name of the package from which this module was installed" ResourceKey="PackageName">Package Name: </Label>
|
<Label Class="col-sm-3" For="packagename" HelpText="The unique name of the package from which this theme was installed. This value must be specified within the theme's ITheme interface specification." ResourceKey="PackageName">Package Name: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
|
@if (!string.IsNullOrEmpty(_packagename))
|
||||||
</div>
|
{
|
||||||
|
<div class="input-group">
|
||||||
|
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
|
||||||
|
@if (string.IsNullOrEmpty(_packageurl))
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="ValidatePackage">@Localizer["Validate"]</button>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<a href="@_packageurl" target="_blank" class="btn btn-primary">@SharedLocalizer["Download"]</a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="owner" HelpText="The owner or creator of the theme" ResourceKey="Owner">Owner: </Label>
|
<Label Class="col-sm-3" For="owner" HelpText="The owner or creator of the theme" ResourceKey="Owner">Owner: </Label>
|
||||||
@ -97,7 +115,8 @@
|
|||||||
private string _isenabled;
|
private string _isenabled;
|
||||||
private string _name;
|
private string _name;
|
||||||
private string _version;
|
private string _version;
|
||||||
private string _packagename;
|
private string _packagename = "";
|
||||||
|
private string _packageurl = "";
|
||||||
private string _owner = "";
|
private string _owner = "";
|
||||||
private string _url = "";
|
private string _url = "";
|
||||||
private string _contact = "";
|
private string _contact = "";
|
||||||
@ -166,4 +185,27 @@
|
|||||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task ValidatePackage()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var package = await PackageService.GetPackageAsync(_packagename, _version, true);
|
||||||
|
if (package == null || string.IsNullOrEmpty(package.PackageUrl))
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.Validate"], MessageType.Warning);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_packageurl = package.PackageUrl;
|
||||||
|
AddModuleMessage(Localizer["Message.Download"], MessageType.Info);
|
||||||
|
}
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Downloading Package {PackageId} {Version}", _packagename, _version);
|
||||||
|
AddModuleMessage(Localizer["Error.Validate"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,8 +79,7 @@ else
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
_themes = await ThemeService.GetThemesAsync();
|
_themes = await ThemeService.GetThemesAsync();
|
||||||
var list = _themes.Where(item => !string.IsNullOrEmpty(item.PackageName)).Select(item => item.PackageName).Distinct().ToList();
|
_packages = await PackageService.GetPackageUpdatesAsync("theme");
|
||||||
_packages = await PackageService.GetPackagesAsync(list);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -147,7 +146,7 @@ else
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await PackageService.DownloadPackageAsync(packagename, version, Constants.PackagesFolder);
|
await PackageService.DownloadPackageAsync(packagename, version);
|
||||||
await logger.LogInformation("Theme Downloaded {ThemeName} {Version}", packagename, version);
|
await logger.LogInformation("Theme Downloaded {ThemeName} {Version}", packagename, version);
|
||||||
AddModuleMessage(string.Format(Localizer["Success.Theme.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
AddModuleMessage(string.Format(Localizer["Success.Theme.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
||||||
}
|
}
|
||||||
|
@ -7,34 +7,38 @@
|
|||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
<TabStrip>
|
@if (_initialized)
|
||||||
<TabPanel Name="Download" ResourceKey="Download">
|
{
|
||||||
@if (_package != null && _upgradeavailable)
|
<TabStrip>
|
||||||
{
|
<TabPanel Name="Download" ResourceKey="Download">
|
||||||
<ModuleMessage Type="MessageType.Info" Message="Select The Download Button To Download The Framework Upgrade Package And Then Select Upgrade"></ModuleMessage>
|
@if (_package != null && _upgradeavailable)
|
||||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await Download(Constants.PackageId, @_package.Version))>@SharedLocalizer["Download"] @_package.Version</button>
|
{
|
||||||
<button type="button" class="btn btn-success" @onclick="Upgrade">@SharedLocalizer["Upgrade"]</button>
|
<ModuleMessage Type="MessageType.Info" Message="Select The Download Button To Download The Framework Upgrade Package And Then Select Upgrade"></ModuleMessage>
|
||||||
}
|
<button type="button" class="btn btn-primary" @onclick=@(async () => await Download(Constants.PackageId, @_package.Version))>@SharedLocalizer["Download"] @_package.Version</button>
|
||||||
else
|
<button type="button" class="btn btn-success" @onclick="Upgrade">@SharedLocalizer["Upgrade"]</button>
|
||||||
{
|
}
|
||||||
<ModuleMessage Type="MessageType.Info" Message=@Localizer["Message.Text"]></ModuleMessage>
|
else
|
||||||
}
|
{
|
||||||
</TabPanel>
|
<ModuleMessage Type="MessageType.Info" Message=@Localizer["Message.Text"]></ModuleMessage>
|
||||||
<TabPanel Name="Upload" ResourceKey="Upload">
|
}
|
||||||
<ModuleMessage Type="MessageType.Info" Message=@Localizer["MessgeUpgrade.Text"]></ModuleMessage>
|
</TabPanel>
|
||||||
<div class="container">
|
<TabPanel Name="Upload" ResourceKey="Upload">
|
||||||
<div class="row mb-1 align-items-center">
|
<ModuleMessage Type="MessageType.Info" Message=@Localizer["MessageUpgrade.Text"]></ModuleMessage>
|
||||||
<Label Class="col-sm-3" HelpText="Upload A Framework Package And Then Select Upgrade" ResourceKey="Framework">Framework: </Label>
|
<div class="container">
|
||||||
<div class="col-sm-9">
|
<div class="row mb-1 align-items-center">
|
||||||
<FileManager Folder="@Constants.PackagesFolder" />
|
<Label Class="col-sm-3" HelpText="Upload A Framework Package And Then Select Upgrade" ResourceKey="Framework">Framework: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<FileManager Folder="@Constants.PackagesFolder" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<button type="button" class="btn btn-success" @onclick="Upgrade">@SharedLocalizer["Upgrade"]</button>
|
||||||
<button type="button" class="btn btn-success" @onclick="Upgrade">@SharedLocalizer["Upgrade"]</button>
|
</TabPanel>
|
||||||
</TabPanel>
|
</TabStrip>
|
||||||
</TabStrip>
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
private bool _initialized = false;
|
||||||
private Package _package;
|
private Package _package;
|
||||||
private bool _upgradeavailable = false;
|
private bool _upgradeavailable = false;
|
||||||
|
|
||||||
@ -44,18 +48,26 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
List<Package> packages = await PackageService.GetPackagesAsync("framework", "", "", "");
|
if (NavigationManager.BaseUri.Contains("localhost:"))
|
||||||
if (packages != null)
|
|
||||||
{
|
{
|
||||||
_package = packages.Where(item => item.PackageId.StartsWith(Constants.PackageId)).FirstOrDefault();
|
AddModuleMessage(Localizer["Localhost.Text"], MessageType.Info);
|
||||||
if (_package != null)
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<Package> packages = await PackageService.GetPackagesAsync("framework", "", "", "");
|
||||||
|
if (packages != null)
|
||||||
{
|
{
|
||||||
_upgradeavailable = (Version.Parse(_package.Version).CompareTo(Version.Parse(Constants.Version)) > 0);
|
_package = packages.Where(item => item.PackageId.StartsWith(Constants.PackageId)).FirstOrDefault();
|
||||||
}
|
if (_package != null)
|
||||||
else
|
{
|
||||||
{
|
_upgradeavailable = (Version.Parse(_package.Version).CompareTo(Version.Parse(Constants.Version)) > 0);
|
||||||
_package = new Package { Name = Constants.PackageId, Version = Constants.Version };
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_package = new Package { Name = Constants.PackageId, Version = Constants.Version };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
_initialized = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -85,8 +97,8 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await PackageService.DownloadPackageAsync(packageid, version, Constants.PackagesFolder);
|
await PackageService.DownloadPackageAsync(packageid, version);
|
||||||
await PackageService.DownloadPackageAsync(Constants.UpdaterPackageId, version, Constants.PackagesFolder);
|
await PackageService.DownloadPackageAsync(Constants.UpdaterPackageId, version);
|
||||||
AddModuleMessage(Localizer["Success.Framework.Download"], MessageType.Success);
|
AddModuleMessage(Localizer["Success.Framework.Download"], MessageType.Success);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -28,7 +28,7 @@ else
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br/>
|
<br/>
|
||||||
<Pager Items="@_urlMappings">
|
<Pager Items="@_urlMappings" SearchProperties="Url">
|
||||||
<Header>
|
<Header>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
|
@ -123,13 +123,27 @@ else
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@if (p.IsRequired)
|
@if (p.Rows == 1)
|
||||||
{
|
{
|
||||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
|
@if (p.IsRequired)
|
||||||
|
{
|
||||||
|
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
|
@if (p.IsRequired)
|
||||||
|
{
|
||||||
|
<textarea id="@p.Name" class="form-control" maxlength="@p.MaxLength" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))"></textarea>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<textarea id="@p.Name" class="form-control" maxlength="@p.MaxLength" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))"></textarea>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@ -282,9 +296,11 @@ else
|
|||||||
private int folderid = -1;
|
private int folderid = -1;
|
||||||
private int photofileid = -1;
|
private int photofileid = -1;
|
||||||
private File photo = null;
|
private File photo = null;
|
||||||
|
|
||||||
private List<Profile> profiles;
|
private List<Profile> profiles;
|
||||||
private Dictionary<string, string> settings;
|
private Dictionary<string, string> settings;
|
||||||
private string category = string.Empty;
|
private string category = string.Empty;
|
||||||
|
|
||||||
private string filter = "to";
|
private string filter = "to";
|
||||||
private List<Notification> notifications;
|
private List<Notification> notifications;
|
||||||
private string notificationSummary = string.Empty;
|
private string notificationSummary = string.Empty;
|
||||||
@ -299,10 +315,7 @@ else
|
|||||||
|
|
||||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||||
|
|
||||||
if (PageState.Site.Settings.ContainsKey("LoginOptions:TwoFactor") && !string.IsNullOrEmpty(PageState.Site.Settings["LoginOptions:TwoFactor"]))
|
allowtwofactor = (SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:TwoFactor", "false") == "true");
|
||||||
{
|
|
||||||
allowtwofactor = (PageState.Site.Settings["LoginOptions:TwoFactor"] == "true");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PageState.User != null)
|
if (PageState.User != null)
|
||||||
{
|
{
|
||||||
@ -366,44 +379,47 @@ else
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (username != string.Empty && email != string.Empty && ValidateProfiles())
|
if (username != string.Empty && email != string.Empty)
|
||||||
{
|
{
|
||||||
if (_password == confirm)
|
if (_password == confirm)
|
||||||
{
|
{
|
||||||
var user = PageState.User;
|
if (ValidateProfiles())
|
||||||
user.Username = username;
|
|
||||||
user.Password = _password;
|
|
||||||
user.TwoFactorRequired = bool.Parse(twofactor);
|
|
||||||
user.Email = email;
|
|
||||||
user.DisplayName = (displayname == string.Empty ? username : displayname);
|
|
||||||
user.PhotoFileId = filemanager.GetFileId();
|
|
||||||
if (user.PhotoFileId == -1)
|
|
||||||
{
|
{
|
||||||
user.PhotoFileId = null;
|
var user = PageState.User;
|
||||||
}
|
user.Username = username;
|
||||||
if (user.PhotoFileId != null)
|
user.Password = _password;
|
||||||
{
|
user.TwoFactorRequired = bool.Parse(twofactor);
|
||||||
photofileid = user.PhotoFileId.Value;
|
user.Email = email;
|
||||||
photo = await FileService.GetFileAsync(photofileid);
|
user.DisplayName = (displayname == string.Empty ? username : displayname);
|
||||||
}
|
user.PhotoFileId = filemanager.GetFileId();
|
||||||
else
|
if (user.PhotoFileId == -1)
|
||||||
{
|
{
|
||||||
photofileid = -1;
|
user.PhotoFileId = null;
|
||||||
photo = null;
|
}
|
||||||
}
|
if (user.PhotoFileId != null)
|
||||||
|
{
|
||||||
|
photofileid = user.PhotoFileId.Value;
|
||||||
|
photo = await FileService.GetFileAsync(photofileid);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
photofileid = -1;
|
||||||
|
photo = null;
|
||||||
|
}
|
||||||
|
|
||||||
user = await UserService.UpdateUserAsync(user);
|
user = await UserService.UpdateUserAsync(user);
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
|
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
|
||||||
await logger.LogInformation("User Profile Saved");
|
await logger.LogInformation("User Profile Saved");
|
||||||
|
|
||||||
AddModuleMessage(Localizer["Success.Profile.Update"], MessageType.Success);
|
AddModuleMessage(Localizer["Success.Profile.Update"], MessageType.Success);
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error);
|
AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -427,7 +443,6 @@ else
|
|||||||
|
|
||||||
private bool ValidateProfiles()
|
private bool ValidateProfiles()
|
||||||
{
|
{
|
||||||
bool valid = true;
|
|
||||||
foreach (Profile profile in profiles)
|
foreach (Profile profile in profiles)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)) && !string.IsNullOrEmpty(profile.DefaultValue))
|
if (string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)) && !string.IsNullOrEmpty(profile.DefaultValue))
|
||||||
@ -436,18 +451,24 @@ else
|
|||||||
}
|
}
|
||||||
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||||
{
|
{
|
||||||
if (valid == true && profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
|
if (profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
|
||||||
{
|
{
|
||||||
valid = false;
|
AddModuleMessage(string.Format(SharedLocalizer["ProfileRequired"], profile.Title), MessageType.Warning);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
if (valid == true && !string.IsNullOrEmpty(profile.Validation))
|
if (!string.IsNullOrEmpty(profile.Validation))
|
||||||
{
|
{
|
||||||
Regex regex = new Regex(profile.Validation);
|
Regex regex = new Regex(profile.Validation);
|
||||||
valid = regex.Match(SettingService.GetSetting(settings, profile.Name, string.Empty)).Success;
|
bool valid = regex.Match(SettingService.GetSetting(settings, profile.Name, string.Empty)).Success;
|
||||||
|
if (!valid)
|
||||||
|
{
|
||||||
|
AddModuleMessage(string.Format(SharedLocalizer["ProfileInvalid"], profile.Title), MessageType.Warning);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return valid;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Cancel()
|
private void Cancel()
|
||||||
|
@ -55,7 +55,7 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<label class="col-sm-3">@Localizer["Message"] </label>
|
<label class="col-sm-3">@Localizer["Message"] </label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<textarea class="form-control" @bind="@body" rows="5" readonly />
|
<textarea id="txtFrom" class="form-control" @bind="@body" rows="5" readonly />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -66,7 +66,7 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<label class="col-sm-3">@Localizer["Message"] </label>
|
<label class="col-sm-3">@Localizer["Message"] </label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<textarea class="form-control" @bind="@body" rows="5" readonly />
|
<textarea id="txtTo" class="form-control" @bind="@body" rows="5" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -93,7 +93,7 @@
|
|||||||
{
|
{
|
||||||
<div class="control-group">
|
<div class="control-group">
|
||||||
<label class="control-label">@Localizer["OriginalMessage"] </label>
|
<label class="control-label">@Localizer["OriginalMessage"] </label>
|
||||||
<textarea class="form-control" @bind="@reply" rows="5" readonly />
|
<textarea id="txtReply" class="form-control" @bind="@reply" rows="5" readonly />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="username" HelpText="A unique username for a user. Note that this field can not be modified once it is saved." ResourceKey="Username"></Label>
|
<Label Class="col-sm-3" For="username" HelpText="A unique username for a user. Note that this field can not be modified once it is saved." ResourceKey="Username"></Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="username" class="form-control" @bind="@username" />
|
<input id="username" class="form-control" @bind="@_username" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -33,7 +33,7 @@
|
|||||||
<Label Class="col-sm-3" For="confirm" HelpText="Please enter the password again to confirm it matches with the value above" ResourceKey="Confirm"></Label>
|
<Label Class="col-sm-3" For="confirm" HelpText="Please enter the password again to confirm it matches with the value above" ResourceKey="Confirm"></Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@confirm" autocomplete="new-password" required />
|
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@_confirm" autocomplete="new-password" required />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -41,17 +41,25 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="email" HelpText="The email address where the user will receive notifications" ResourceKey="Email"></Label>
|
<Label Class="col-sm-3" For="email" HelpText="The email address where the user will receive notifications" ResourceKey="Email"></Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="email" class="form-control" @bind="@email" />
|
<input id="email" class="form-control" @bind="@_email" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="displayname" HelpText="The full name of the user" ResourceKey="DisplayName"></Label>
|
<Label Class="col-sm-3" For="displayname" HelpText="The full name of the user" ResourceKey="DisplayName"></Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="displayname" class="form-control" @bind="@displayname" />
|
<input id="displayname" class="form-control" @bind="@_displayname" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="notify" HelpText="Indicate if new users should receive an email notification" ResourceKey="Notify">Notify? </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="notify" class="form-select" @bind="@_notify" required>
|
||||||
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
}
|
}
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel Name="Profile" ResourceKey="Profile">
|
<TabPanel Name="Profile" ResourceKey="Profile">
|
||||||
@ -72,18 +80,50 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="@p.Name" HelpText="@p.Description">@p.Title</Label>
|
<Label Class="col-sm-3" For="@p.Name" HelpText="@p.Description">@p.Title</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@if (p.IsRequired)
|
@if (!string.IsNullOrEmpty(p.Options))
|
||||||
{
|
{
|
||||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
|
<select id="@p.Name" class="form-select" @onchange="@(e => ProfileChanged(e, p.Name))">
|
||||||
|
@foreach (var option in p.Options.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||||
|
{
|
||||||
|
@if (GetProfileValue(p.Name, "") == option || (GetProfileValue(p.Name, "") == "" && p.DefaultValue == option))
|
||||||
|
{
|
||||||
|
<option value="@option" selected>@option</option>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<option value="@option">@option</option>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</select>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
|
@if (p.Rows == 1)
|
||||||
|
{
|
||||||
|
@if (p.IsRequired)
|
||||||
|
{
|
||||||
|
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@if (p.IsRequired)
|
||||||
|
{
|
||||||
|
<textarea id="@p.Name" class="form-control" maxlength="@p.MaxLength" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))"></textarea>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<textarea id="@p.Name" class="form-control" maxlength="@p.MaxLength" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))"></textarea>
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@ -96,13 +136,14 @@
|
|||||||
|
|
||||||
@code {
|
@code {
|
||||||
private string _passwordrequirements;
|
private string _passwordrequirements;
|
||||||
private string username = string.Empty;
|
private string _username = string.Empty;
|
||||||
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 string confirm = string.Empty;
|
private string _confirm = string.Empty;
|
||||||
private string email = string.Empty;
|
private string _email = string.Empty;
|
||||||
private string displayname = string.Empty;
|
private string _displayname = string.Empty;
|
||||||
|
private string _notify = "True";
|
||||||
private List<Profile> profiles;
|
private List<Profile> profiles;
|
||||||
private Dictionary<string, string> settings;
|
private Dictionary<string, string> settings;
|
||||||
private string category = string.Empty;
|
private string category = string.Empty;
|
||||||
@ -139,30 +180,34 @@
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (username != string.Empty && _password != string.Empty && confirm != string.Empty && email != string.Empty && ValidateProfiles())
|
if (_username != string.Empty && _password != string.Empty && _confirm != string.Empty && _email != string.Empty)
|
||||||
{
|
{
|
||||||
if (_password == confirm)
|
if (_password == _confirm)
|
||||||
{
|
{
|
||||||
var user = new User();
|
if (ValidateProfiles())
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
await SettingService.UpdateUserSettingsAsync(settings, user.UserId);
|
var user = new User();
|
||||||
await logger.LogInformation("User Created {User}", user);
|
user.SiteId = PageState.Site.SiteId;
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
user.Username = _username;
|
||||||
}
|
user.Password = _password;
|
||||||
else
|
user.Email = _email;
|
||||||
{
|
user.DisplayName = string.IsNullOrWhiteSpace(_displayname) ? _username : _displayname;
|
||||||
await logger.LogError("Error Adding User {Username} {Email}", username, email);
|
user.PhotoFileId = null;
|
||||||
AddModuleMessage(Localizer["Error.User.AddCheckPass"], MessageType.Error);
|
user.SuppressNotification = !bool.Parse(_notify);
|
||||||
|
|
||||||
|
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
|
||||||
@ -177,14 +222,13 @@
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Adding User {Username} {Email} {Error}", username, email, ex.Message);
|
await logger.LogError(ex, "Error Adding User {Username} {Email} {Error}", _username, _email, ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.User.Add"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.User.Add"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ValidateProfiles()
|
private bool ValidateProfiles()
|
||||||
{
|
{
|
||||||
bool valid = true;
|
|
||||||
foreach (Profile profile in profiles)
|
foreach (Profile profile in profiles)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)) && !string.IsNullOrEmpty(profile.DefaultValue))
|
if (string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)) && !string.IsNullOrEmpty(profile.DefaultValue))
|
||||||
@ -193,18 +237,24 @@
|
|||||||
}
|
}
|
||||||
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||||
{
|
{
|
||||||
if (valid == true && profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
|
if (profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
|
||||||
{
|
{
|
||||||
valid = false;
|
AddModuleMessage(string.Format(SharedLocalizer["ProfileRequired"], profile.Title), MessageType.Warning);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
if (valid == true && !string.IsNullOrEmpty(profile.Validation))
|
if (!string.IsNullOrEmpty(profile.Validation))
|
||||||
{
|
{
|
||||||
Regex regex = new Regex(profile.Validation);
|
Regex regex = new Regex(profile.Validation);
|
||||||
valid = regex.Match(SettingService.GetSetting(settings, profile.Name, string.Empty)).Success;
|
bool valid = regex.Match(SettingService.GetSetting(settings, profile.Name, string.Empty)).Success;
|
||||||
|
if (!valid)
|
||||||
|
{
|
||||||
|
AddModuleMessage(string.Format(SharedLocalizer["ProfileInvalid"], profile.Title), MessageType.Warning);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return valid;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProfileChanged(ChangeEventArgs e, string SettingName)
|
private void ProfileChanged(ChangeEventArgs e, string SettingName)
|
||||||
|
@ -125,13 +125,27 @@ else
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@if (p.IsRequired)
|
@if (p.Rows == 1)
|
||||||
{
|
{
|
||||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
|
@if (p.IsRequired)
|
||||||
|
{
|
||||||
|
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
|
@if (p.IsRequired)
|
||||||
|
{
|
||||||
|
<textarea id="@p.Name" class="form-control" maxlength="@p.MaxLength" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))"></textarea>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<textarea id="@p.Name" class="form-control" maxlength="@p.MaxLength" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))"></textarea>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@ -240,35 +254,38 @@ else
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (username != string.Empty && email != string.Empty && ValidateProfiles())
|
if (username != string.Empty && email != string.Empty)
|
||||||
{
|
{
|
||||||
if (_password == confirm)
|
if (_password == confirm)
|
||||||
{
|
{
|
||||||
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
|
if (ValidateProfiles())
|
||||||
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.PhotoFileId = filemanager.GetFileId();
|
|
||||||
if (user.PhotoFileId == -1)
|
|
||||||
{
|
{
|
||||||
|
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
|
||||||
|
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.PhotoFileId = null;
|
||||||
}
|
user.PhotoFileId = filemanager.GetFileId();
|
||||||
|
if (user.PhotoFileId == -1)
|
||||||
|
{
|
||||||
|
user.PhotoFileId = null;
|
||||||
|
}
|
||||||
|
|
||||||
user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
|
user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
|
||||||
|
|
||||||
user = await UserService.UpdateUserAsync(user);
|
user = await UserService.UpdateUserAsync(user);
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
await SettingService.UpdateUserSettingsAsync(settings, user.UserId);
|
await SettingService.UpdateUserSettingsAsync(settings, user.UserId);
|
||||||
await logger.LogInformation("User Saved {User}", user);
|
await logger.LogInformation("User Saved {User}", user);
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error);
|
AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -290,7 +307,6 @@ else
|
|||||||
|
|
||||||
private bool ValidateProfiles()
|
private bool ValidateProfiles()
|
||||||
{
|
{
|
||||||
bool valid = true;
|
|
||||||
foreach (Profile profile in profiles)
|
foreach (Profile profile in profiles)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)) && !string.IsNullOrEmpty(profile.DefaultValue))
|
if (string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)) && !string.IsNullOrEmpty(profile.DefaultValue))
|
||||||
@ -299,18 +315,24 @@ else
|
|||||||
}
|
}
|
||||||
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||||
{
|
{
|
||||||
if (valid == true && profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
|
if (profile.IsRequired && string.IsNullOrEmpty(SettingService.GetSetting(settings, profile.Name, string.Empty)))
|
||||||
{
|
{
|
||||||
valid = false;
|
AddModuleMessage(string.Format(SharedLocalizer["ProfileRequired"], profile.Title), MessageType.Warning);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
if (valid == true && !string.IsNullOrEmpty(profile.Validation))
|
if (!string.IsNullOrEmpty(profile.Validation))
|
||||||
{
|
{
|
||||||
Regex regex = new Regex(profile.Validation);
|
Regex regex = new Regex(profile.Validation);
|
||||||
valid = regex.Match(SettingService.GetSetting(settings, profile.Name, string.Empty)).Success;
|
bool valid = regex.Match(SettingService.GetSetting(settings, profile.Name, string.Empty)).Success;
|
||||||
|
if (!valid)
|
||||||
|
{
|
||||||
|
AddModuleMessage(string.Format(SharedLocalizer["ProfileInvalid"], profile.Title), MessageType.Warning);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return valid;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProfileChanged(ChangeEventArgs e, string SettingName)
|
private void ProfileChanged(ChangeEventArgs e, string SettingName)
|
||||||
|
@ -17,26 +17,17 @@ else
|
|||||||
{
|
{
|
||||||
<TabStrip>
|
<TabStrip>
|
||||||
<TabPanel Name="Users" Heading="Users" ResourceKey="Users">
|
<TabPanel Name="Users" Heading="Users" ResourceKey="Users">
|
||||||
<div class="container">
|
<ActionLink Action="Add" Text="Add User" Security="SecurityAccessLevel.Edit" ResourceKey="AddUser" />
|
||||||
<div class="row mb-1 align-items-center">
|
<ActionLink Text="Import Users" Class="btn btn-secondary ms-2" Action="Users" Security="SecurityAccessLevel.Admin" ResourceKey="ImportUsers"/>
|
||||||
<div class="col-sm-4">
|
|
||||||
<ActionLink Action="Add" Text="Add User" Security="SecurityAccessLevel.Edit" ResourceKey="AddUser" />
|
<Pager Items="@users" RowClass="align-middle" SearchProperties="User.Username,User.Email,User.DisplayName">
|
||||||
</div>
|
|
||||||
<div class="col-sm-4">
|
|
||||||
<input class="form-control" @bind="@_search" />
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-4">
|
|
||||||
<button type="button" class="btn btn-secondary" @onclick="OnSearch">@SharedLocalizer["Search"]</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Pager Items="@users" RowClass="align-middle">
|
|
||||||
<Header>
|
<Header>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th class="app-sort-th link-primary text-decoration-underline" @onclick="@(() => SortTable("Username"))">@Localizer["Username"]<i class="@(SetSortIcon("Username"))"></i></th>
|
<th class="app-sort-th link-primary text-decoration-underline" @onclick="@(() => SortTable("Username"))">@Localizer["Username"]<i class="@(SetSortIcon("Username"))"></i></th>
|
||||||
<th class="app-sort-th link-primary text-decoration-underline" @onclick="@(() => SortTable("DisplayName"))">@Localizer["Name"]<i class="@(SetSortIcon("DisplayName"))"></i></th>
|
<th class="app-sort-th link-primary text-decoration-underline" @onclick="@(() => SortTable("DisplayName"))">@Localizer["Name"]<i class="@(SetSortIcon("DisplayName"))"></i></th>
|
||||||
|
<th class="app-sort-th link-primary text-decoration-underline" @onclick="@(() => SortTable("Email"))">@Localizer["Email"]<i class="@(SetSortIcon("Email"))"></i></th>
|
||||||
<th class="app-sort-th link-primary text-decoration-underline" @onclick="@(() => SortTable("LastLoginOn"))">@Localizer["LastLoginOn"]<i class="@(SetSortIcon("LastLoginOn"))"></i></th>
|
<th class="app-sort-th link-primary text-decoration-underline" @onclick="@(() => SortTable("LastLoginOn"))">@Localizer["LastLoginOn"]<i class="@(SetSortIcon("LastLoginOn"))"></i></th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
@ -50,11 +41,12 @@ else
|
|||||||
<ActionLink Action="Roles" Parameters="@($"id=" + context.UserId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="Roles" />
|
<ActionLink Action="Roles" Parameters="@($"id=" + context.UserId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="Roles" />
|
||||||
</td>
|
</td>
|
||||||
<td>@context.User.Username</td>
|
<td>@context.User.Username</td>
|
||||||
<td>@((MarkupString)string.Format("<a href=\"mailto:{0}\">{1}</a>", @context.User.Email, @context.User.DisplayName))</td>
|
<td>@context.User.DisplayName</td>
|
||||||
|
<td>@((MarkupString)string.Format("<a href=\"mailto:{0}\">{1}</a>", @context.User.Email, @context.User.Email))</td>
|
||||||
<td>@((context.User.LastLoginOn != DateTime.MinValue) ? string.Format("{0:dd-MMM-yyyy HH:mm:ss}", context.User.LastLoginOn) : "")</td>
|
<td>@((context.User.LastLoginOn != DateTime.MinValue) ? string.Format("{0:dd-MMM-yyyy HH:mm:ss}", context.User.LastLoginOn) : "")</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings" Security="SecurityAccessLevel.Admin">
|
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings" Security="SecurityAccessLevel.Admin">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<Section Name="User" Heading="User Settings" ResourceKey="UserSettings">
|
<Section Name="User" Heading="User Settings" ResourceKey="UserSettings">
|
||||||
@ -259,7 +251,22 @@ else
|
|||||||
<input id="parameters" class="form-control" @bind="@_parameters" />
|
<input id="parameters" class="form-control" @bind="@_parameters" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="authresponsetype" HelpText="Specify the authorization response type" ResourceKey="AuthResponseType">Authorization Response Type</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="authresponsetype" class="form-select" @bind="@_authresponsetype" required>
|
||||||
|
<option value="code">@Localizer["AuthFlow.Code"]</option>
|
||||||
|
<option value="code id_token">@Localizer["AuthFlow.CodeIdToken"]</option>
|
||||||
|
<option value="code id_token token">@Localizer["AuthFlow.CodeIdTokenToken"]</option>
|
||||||
|
<option value="code token">@Localizer["AuthFlow.CodeToken"]</option>
|
||||||
|
<option value="id_token">@Localizer["AuthFlow.IdToken"]</option>
|
||||||
|
<option value="id_token token">@Localizer["AuthFlow.IdTokenToken"]</option>
|
||||||
|
<option value="token">@Localizer["AuthFlow.Token"]</option>
|
||||||
|
<option value="none">@Localizer["AuthFlow.None"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="pkce" HelpText="Indicate if the provider supports Proof Key for Code Exchange (PKCE)" ResourceKey="PKCE">Use PKCE?</Label>
|
<Label Class="col-sm-3" For="pkce" HelpText="Indicate if the provider supports Proof Key for Code Exchange (PKCE)" ResourceKey="PKCE">Use PKCE?</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="pkce" class="form-select" @bind="@_pkce" required>
|
<select id="pkce" class="form-select" @bind="@_pkce" required>
|
||||||
@ -360,14 +367,12 @@ else
|
|||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
</TabStrip>
|
</TabStrip>
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<UserRole> allusers;
|
|
||||||
private List<UserRole> users;
|
private List<UserRole> users;
|
||||||
private string _search = "";
|
|
||||||
|
|
||||||
private string _allowregistration;
|
private string _allowregistration;
|
||||||
private string _allowsitelogin;
|
private string _allowsitelogin;
|
||||||
@ -397,6 +402,7 @@ else
|
|||||||
private string _scopes;
|
private string _scopes;
|
||||||
private string _parameters;
|
private string _parameters;
|
||||||
private string _pkce;
|
private string _pkce;
|
||||||
|
private string _authresponsetype;
|
||||||
private string _redirecturl;
|
private string _redirecturl;
|
||||||
private string _identifierclaimtype;
|
private string _identifierclaimtype;
|
||||||
private string _emailclaimtype;
|
private string _emailclaimtype;
|
||||||
@ -420,7 +426,6 @@ else
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
await LoadUserSettingsAsync();
|
|
||||||
await LoadUsersAsync(true);
|
await LoadUsersAsync(true);
|
||||||
|
|
||||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||||
@ -455,6 +460,7 @@ else
|
|||||||
_scopes = SettingService.GetSetting(settings, "ExternalLogin:Scopes", "");
|
_scopes = SettingService.GetSetting(settings, "ExternalLogin:Scopes", "");
|
||||||
_parameters = SettingService.GetSetting(settings, "ExternalLogin:Parameters", "");
|
_parameters = SettingService.GetSetting(settings, "ExternalLogin:Parameters", "");
|
||||||
_pkce = SettingService.GetSetting(settings, "ExternalLogin:PKCE", "false");
|
_pkce = SettingService.GetSetting(settings, "ExternalLogin:PKCE", "false");
|
||||||
|
_authresponsetype = SettingService.GetSetting(settings, "ExternalLogin:AuthResponseType", "code");
|
||||||
_redirecturl = PageState.Uri.Scheme + "://" + PageState.Alias.Name + "/signin-" + _providertype;
|
_redirecturl = PageState.Uri.Scheme + "://" + PageState.Alias.Name + "/signin-" + _providertype;
|
||||||
_identifierclaimtype = SettingService.GetSetting(settings, "ExternalLogin:IdentifierClaimType", "sub");
|
_identifierclaimtype = SettingService.GetSetting(settings, "ExternalLogin:IdentifierClaimType", "sub");
|
||||||
_emailclaimtype = SettingService.GetSetting(settings, "ExternalLogin:EmailClaimType", "email");
|
_emailclaimtype = SettingService.GetSetting(settings, "ExternalLogin:EmailClaimType", "email");
|
||||||
@ -475,32 +481,14 @@ else
|
|||||||
{
|
{
|
||||||
if (load)
|
if (load)
|
||||||
{
|
{
|
||||||
allusers = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Registered);
|
users = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Registered);
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
{
|
{
|
||||||
var hosts = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Host);
|
var hosts = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Host);
|
||||||
allusers.AddRange(hosts);
|
users.AddRange(hosts);
|
||||||
allusers = allusers.OrderBy(u => u.User.DisplayName).ToList();
|
users = users.OrderBy(u => u.User.DisplayName).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
users = allusers;
|
|
||||||
if (!string.IsNullOrEmpty(_search))
|
|
||||||
{
|
|
||||||
users = users.Where(item =>
|
|
||||||
(
|
|
||||||
item.User.Username.Contains(_search, StringComparison.OrdinalIgnoreCase) ||
|
|
||||||
item.User.Email.Contains(_search, StringComparison.OrdinalIgnoreCase) ||
|
|
||||||
item.User.DisplayName.Contains(_search, StringComparison.OrdinalIgnoreCase)
|
|
||||||
)
|
|
||||||
).ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task OnSearch()
|
|
||||||
{
|
|
||||||
await UpdateUserSettingsAsync();
|
|
||||||
await LoadUsersAsync(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DeleteUser(UserRole UserRole)
|
private async Task DeleteUser(UserRole UserRole)
|
||||||
@ -523,21 +511,6 @@ else
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string settingSearch = "AU-search";
|
|
||||||
|
|
||||||
private async Task LoadUserSettingsAsync()
|
|
||||||
{
|
|
||||||
Dictionary<string, string> settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
|
|
||||||
_search = SettingService.GetSetting(settings, settingSearch, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task UpdateUserSettingsAsync()
|
|
||||||
{
|
|
||||||
Dictionary<string, string> settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
|
|
||||||
settings = SettingService.SetSetting(settings, settingSearch, _search);
|
|
||||||
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SaveSiteSettings()
|
private async Task SaveSiteSettings()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -576,6 +549,7 @@ else
|
|||||||
settings = SettingService.SetSetting(settings, "ExternalLogin:Scopes", _scopes, true);
|
settings = SettingService.SetSetting(settings, "ExternalLogin:Scopes", _scopes, true);
|
||||||
settings = SettingService.SetSetting(settings, "ExternalLogin:Parameters", _parameters, true);
|
settings = SettingService.SetSetting(settings, "ExternalLogin:Parameters", _parameters, true);
|
||||||
settings = SettingService.SetSetting(settings, "ExternalLogin:PKCE", _pkce, true);
|
settings = SettingService.SetSetting(settings, "ExternalLogin:PKCE", _pkce, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "ExternalLogin:AuthResponseType", _authresponsetype, true);
|
||||||
settings = SettingService.SetSetting(settings, "ExternalLogin:IdentifierClaimType", _identifierclaimtype, true);
|
settings = SettingService.SetSetting(settings, "ExternalLogin:IdentifierClaimType", _identifierclaimtype, true);
|
||||||
settings = SettingService.SetSetting(settings, "ExternalLogin:EmailClaimType", _emailclaimtype, true);
|
settings = SettingService.SetSetting(settings, "ExternalLogin:EmailClaimType", _emailclaimtype, true);
|
||||||
settings = SettingService.SetSetting(settings, "ExternalLogin:RoleClaimType", _roleclaimtype, true);
|
settings = SettingService.SetSetting(settings, "ExternalLogin:RoleClaimType", _roleclaimtype, true);
|
||||||
|
69
Oqtane.Client/Modules/Admin/Users/Users.razor
Normal file
69
Oqtane.Client/Modules/Admin/Users/Users.razor
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
@namespace Oqtane.Modules.Admin.Users
|
||||||
|
@inherits ModuleBase
|
||||||
|
@inject NavigationManager NavigationManager
|
||||||
|
@inject IUserService UserService
|
||||||
|
@inject IStringLocalizer<Users> Localizer
|
||||||
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="importfile" HelpText="Upload or select a tab delimited text file containing user information. The file must be in the Template format specified (Roles can be specified as a comma delimited list)." ResourceKey="ImportFile">Import File:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<FileManager Id="importfile" @ref="_filemanager" Filter="txt" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="notify" HelpText="Indicate if new users should receive an email notification" ResourceKey="Notify">Notify? </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="notify" class="form-select" @bind="@_notify" required>
|
||||||
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<button type="button" class="btn btn-success" @onclick="ImportUsers">@Localizer["Import"]</button>
|
||||||
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
|
<a class="btn btn-info" href="/users.txt" target="_new">@Localizer["Template"]</a>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private FileManager _filemanager;
|
||||||
|
|
||||||
|
public override string Title => "Import Users";
|
||||||
|
|
||||||
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||||
|
|
||||||
|
private string _notify = "True";
|
||||||
|
|
||||||
|
private async Task ImportUsers()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fileid = _filemanager.GetFileId();
|
||||||
|
if (fileid != -1)
|
||||||
|
{
|
||||||
|
ShowProgressIndicator();
|
||||||
|
var results = await UserService.ImportUsersAsync(PageState.Site.SiteId, fileid, bool.Parse(_notify));
|
||||||
|
if (bool.Parse(results["Success"]))
|
||||||
|
{
|
||||||
|
AddModuleMessage(string.Format(Localizer["Message.Import.Success"], results["Users"]), MessageType.Success);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.Import.Failure"], MessageType.Error);
|
||||||
|
}
|
||||||
|
HideProgressIndicator();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.Import.Validation"], MessageType.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Importing Users {Error}", ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.Import"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -24,116 +24,135 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private string _text = string.Empty;
|
private string _text = string.Empty;
|
||||||
private string _parameters = string.Empty;
|
private int _moduleId = -1;
|
||||||
private string _url = string.Empty;
|
private string _path = string.Empty;
|
||||||
private List<Permission> _permissions;
|
private string _parameters = string.Empty;
|
||||||
private bool _editmode = false;
|
private string _url = string.Empty;
|
||||||
private bool _authorized = false;
|
private List<Permission> _permissions;
|
||||||
private string _classname = "btn btn-primary";
|
private bool _editmode = false;
|
||||||
private string _style = string.Empty;
|
private bool _authorized = false;
|
||||||
private string _iconSpan = string.Empty;
|
private string _classname = "btn btn-primary";
|
||||||
|
private string _style = string.Empty;
|
||||||
|
private string _iconSpan = string.Empty;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Action { get; set; } // required
|
public string Action { get; set; } // required
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Text { get; set; } // optional - defaults to Action if not specified
|
public string Text { get; set; } // optional - defaults to Action if not specified
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Parameters { get; set; } // optional - querystring parameters should be in the form of "id=x&name=y"
|
public int ModuleId { get; set; } = -1; // optional - allows the link to target a specific moduleid
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public int ModuleId { get; set; } = -1; // optional - allows the link to target a specific moduleid
|
public string Path { get; set; } = null; // optional - allows the link to target a specific page
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public Action OnClick { get; set; } = null; // optional - executes a method in the calling component
|
public string Parameters { get; set; } // optional - querystring parameters should be in the form of "id=x&name=y"
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel
|
public Action OnClick { get; set; } = null; // optional - executes a method in the calling component
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Permissions { get; set; } // deprecated - use PermissionList instead
|
public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public List<Permission> PermissionList { get; set; } // optional - can be used to specify permissions
|
public string Permissions { get; set; } // deprecated - use PermissionList instead
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool Disabled { get; set; } // optional
|
public List<Permission> PermissionList { get; set; } // optional - can be used to specify permissions
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string EditMode { get; set; } // optional - specifies if an authorized user must be in edit mode to see the action - default is false.
|
public bool Disabled { get; set; } // optional
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Class { get; set; } // optional - defaults to primary if not specified
|
public string EditMode { get; set; } // optional - specifies if an authorized user must be in edit mode to see the action - default is false.
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Style { get; set; } // optional
|
public string Class { get; set; } // optional - defaults to primary if not specified
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string IconName { get; set; } // optional - specifies an icon for the link - default is no icon
|
public string Style { get; set; } // optional
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool IconOnly { get; set; } // optional - specifies only icon in link
|
public string IconName { get; set; } // optional - specifies an icon for the link - default is no icon
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string ReturnUrl { get; set; } // optional - used to set a url to redirect to
|
public bool IconOnly { get; set; } // optional - specifies only icon in link
|
||||||
|
|
||||||
protected override void OnInitialized()
|
[Parameter]
|
||||||
{
|
public string ReturnUrl { get; set; } // optional - used to set a url to redirect to
|
||||||
if (!string.IsNullOrEmpty(Permissions))
|
|
||||||
{
|
|
||||||
PermissionList = JsonSerializer.Deserialize<List<Permission>>(Permissions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
|
||||||
{
|
|
||||||
base.OnParametersSet();
|
|
||||||
|
|
||||||
_text = Action;
|
protected override void OnInitialized()
|
||||||
if (!string.IsNullOrEmpty(Text))
|
{
|
||||||
{
|
if (!string.IsNullOrEmpty(Permissions))
|
||||||
_text = Text;
|
{
|
||||||
}
|
PermissionList = JsonSerializer.Deserialize<List<Permission>>(Permissions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (IconOnly && !string.IsNullOrEmpty(IconName))
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
_text = string.Empty;
|
base.OnParametersSet();
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Parameters))
|
_text = Action;
|
||||||
{
|
if (!string.IsNullOrEmpty(Text))
|
||||||
_parameters = Parameters;
|
{
|
||||||
}
|
_text = Text;
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Class))
|
if (IconOnly && !string.IsNullOrEmpty(IconName))
|
||||||
{
|
{
|
||||||
_classname = Class;
|
_text = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Style))
|
_moduleId = ModuleState.ModuleId;
|
||||||
{
|
if (ModuleId != -1)
|
||||||
_style = Style;
|
{
|
||||||
}
|
_moduleId = ModuleId;
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(EditMode))
|
_path = PageState.Page.Path;
|
||||||
{
|
if (Path != null)
|
||||||
_editmode = bool.Parse(EditMode);
|
{
|
||||||
}
|
_path = Path;
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(IconName))
|
if (!string.IsNullOrEmpty(Parameters))
|
||||||
{
|
{
|
||||||
if (!IconName.Contains(" "))
|
_parameters = Parameters;
|
||||||
{
|
}
|
||||||
IconName = "oi oi-" + IconName;
|
|
||||||
}
|
if (!string.IsNullOrEmpty(Class))
|
||||||
_iconSpan = $"<span class=\"{IconName}\"></span>{(IconOnly ? "" : " ")}";
|
{
|
||||||
}
|
_classname = Class;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(Style))
|
||||||
|
{
|
||||||
|
_style = Style;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(EditMode))
|
||||||
|
{
|
||||||
|
_editmode = bool.Parse(EditMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(IconName))
|
||||||
|
{
|
||||||
|
if (!IconName.Contains(" "))
|
||||||
|
{
|
||||||
|
IconName = "oi oi-" + IconName;
|
||||||
|
}
|
||||||
|
_iconSpan = $"<span class=\"{IconName}\"></span>{(IconOnly ? "" : " ")}";
|
||||||
|
}
|
||||||
|
|
||||||
_permissions = (PermissionList == null) ? ModuleState.PermissionList : PermissionList;
|
_permissions = (PermissionList == null) ? ModuleState.PermissionList : PermissionList;
|
||||||
_text = Localize(nameof(Text), _text);
|
_text = Localize(nameof(Text), _text);
|
||||||
_url = (ModuleId == -1) ? EditUrl(Action, _parameters) : EditUrl(ModuleId, Action, _parameters);
|
|
||||||
|
_url = EditUrl(_path, _moduleId, Action, _parameters);
|
||||||
if (!string.IsNullOrEmpty(ReturnUrl))
|
if (!string.IsNullOrEmpty(ReturnUrl))
|
||||||
{
|
{
|
||||||
_url += ((_url.Contains("?")) ? "&" : "?") + $"returnurl={WebUtility.UrlEncode(ReturnUrl)}";
|
_url += ((_url.Contains("?")) ? "&" : "?") + $"returnurl={WebUtility.UrlEncode(ReturnUrl)}";
|
||||||
|
@ -40,6 +40,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (GetFileId() != -1 && !UploadMultiple)
|
||||||
|
{
|
||||||
|
<input class="form-control" @bind="@_file.Name" disabled />
|
||||||
|
}
|
||||||
|
}
|
||||||
@if (ShowUpload && _haseditpermission)
|
@if (ShowUpload && _haseditpermission)
|
||||||
{
|
{
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -55,7 +62,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col mt-2 text-end">
|
<div class="col mt-2 text-end">
|
||||||
<button type="button" class="btn btn-success" @onclick="UploadFiles">@SharedLocalizer["Upload"]</button>
|
<button type="button" class="btn btn-success" @onclick="UploadFiles">@SharedLocalizer["Upload"]</button>
|
||||||
@if (GetFileId() != -1)
|
@if (GetFileId() != -1 && !UploadMultiple)
|
||||||
{
|
{
|
||||||
<button type="button" class="btn btn-danger mx-1" @onclick="DeleteFile">@SharedLocalizer["Delete"]</button>
|
<button type="button" class="btn btn-danger mx-1" @onclick="DeleteFile">@SharedLocalizer["Delete"]</button>
|
||||||
}
|
}
|
||||||
@ -341,7 +348,8 @@
|
|||||||
string restricted = "";
|
string restricted = "";
|
||||||
foreach (var upload in uploads)
|
foreach (var upload in uploads)
|
||||||
{
|
{
|
||||||
var extension = (upload.LastIndexOf(".") != -1) ? upload.Substring(upload.LastIndexOf(".") + 1) : "";
|
var filename = upload.Split(':')[0];
|
||||||
|
var extension = (filename.LastIndexOf(".") != -1) ? filename.Substring(filename.LastIndexOf(".") + 1) : "";
|
||||||
if (!Constants.UploadableFiles.Split(',').Contains(extension.ToLower()))
|
if (!Constants.UploadableFiles.Split(',').Contains(extension.ToLower()))
|
||||||
{
|
{
|
||||||
restricted += (restricted == "" ? "" : ",") + extension;
|
restricted += (restricted == "" ? "" : ",") + extension;
|
||||||
@ -368,24 +376,27 @@
|
|||||||
while (upload < uploads.Length && success)
|
while (upload < uploads.Length && success)
|
||||||
{
|
{
|
||||||
success = false;
|
success = false;
|
||||||
// note that progressive retry will only wait a maximum of 15 seconds which may not be long enough for very large file uploads
|
var filename = uploads[upload].Split(':')[0];
|
||||||
|
var size = Int64.Parse(uploads[upload].Split(':')[1]);
|
||||||
|
var maxattempts = (int)Math.Ceiling(size / 500000.0) + 4; // 30 MB takes 1 minute at 5 Mbps (min 5 attempts)
|
||||||
|
|
||||||
int attempts = 0;
|
int attempts = 0;
|
||||||
while (attempts < 5 && !success)
|
while (attempts < maxattempts && !success)
|
||||||
{
|
{
|
||||||
attempts += 1;
|
attempts += 1;
|
||||||
Thread.Sleep(1000 * attempts); // progressive retry
|
Thread.Sleep(1000);
|
||||||
|
|
||||||
if (Folder == Constants.PackagesFolder)
|
if (Folder == Constants.PackagesFolder)
|
||||||
{
|
{
|
||||||
var files = await FileService.GetFilesAsync(folder);
|
var files = await FileService.GetFilesAsync(folder);
|
||||||
if (files != null && files.Any(item => item.Name == uploads[upload]))
|
if (files != null && files.Any(item => item.Name == filename))
|
||||||
{
|
{
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var file = await FileService.GetFileAsync(int.Parse(folder), uploads[upload]);
|
var file = await FileService.GetFileAsync(int.Parse(folder), filename);
|
||||||
if (file != null)
|
if (file != null)
|
||||||
{
|
{
|
||||||
success = true;
|
success = true;
|
||||||
@ -433,7 +444,7 @@
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// set FileId to first file in upload collection
|
// set FileId to first file in upload collection
|
||||||
var file = await FileService.GetFileAsync(int.Parse(folder), uploads[0]);
|
var file = await FileService.GetFileAsync(int.Parse(folder), uploads[0].Split(":")[0]);
|
||||||
if (file != null)
|
if (file != null)
|
||||||
{
|
{
|
||||||
FileId = file.FileId;
|
FileId = file.FileId;
|
||||||
|
@ -1,10 +1,20 @@
|
|||||||
@namespace Oqtane.Modules.Controls
|
@namespace Oqtane.Modules.Controls
|
||||||
@inherits ModuleControlBase
|
@inherits ModuleControlBase
|
||||||
@inject IStringLocalizerFactory LocalizerFactory
|
@inject IStringLocalizerFactory LocalizerFactory
|
||||||
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
@typeparam TableItem
|
@typeparam TableItem
|
||||||
|
|
||||||
@if (ItemList != null)
|
@if (ItemList != null)
|
||||||
{
|
{
|
||||||
|
@if (!string.IsNullOrEmpty(SearchProperties))
|
||||||
|
{
|
||||||
|
<div class="input-group my-3">
|
||||||
|
<input id="search" class="form-control" placeholder=@string.Format(Localizer["SearchPlaceholder"], FormatSearchProperties()) @bind="@_search" />
|
||||||
|
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
@if ((Toolbar == "Top" || Toolbar == "Both") && _pages > 0 && Items.Count() > _maxItems)
|
@if ((Toolbar == "Top" || Toolbar == "Both") && _pages > 0 && Items.Count() > _maxItems)
|
||||||
{
|
{
|
||||||
<ul class="pagination justify-content-center my-2">
|
<ul class="pagination justify-content-center my-2">
|
||||||
@ -175,6 +185,9 @@
|
|||||||
private int _startPage = 0;
|
private int _startPage = 0;
|
||||||
private int _endPage = 0;
|
private int _endPage = 0;
|
||||||
private int _columns = 0;
|
private int _columns = 0;
|
||||||
|
private string _search = "";
|
||||||
|
|
||||||
|
private IEnumerable<TableItem> AllItems;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Format { get; set; } // Table or Grid
|
public string Format { get; set; } // Table or Grid
|
||||||
@ -221,6 +234,9 @@
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public Action<int> OnPageChange { get; set; } // a method to be executed in the calling component when the page changes
|
public Action<int> OnPageChange { get; set; } // a method to be executed in the calling component when the page changes
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string SearchProperties { get; set; } // comma delimited list of property names to include in search
|
||||||
|
|
||||||
private IEnumerable<TableItem> ItemList { get; set; }
|
private IEnumerable<TableItem> ItemList { get; set; }
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
@ -276,6 +292,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(SearchProperties))
|
||||||
|
{
|
||||||
|
AllItems = Items; // only used in search
|
||||||
|
if (!string.IsNullOrEmpty(_search))
|
||||||
|
{
|
||||||
|
Search();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(PageSize))
|
if (!string.IsNullOrEmpty(PageSize))
|
||||||
{
|
{
|
||||||
_maxItems = int.Parse(PageSize);
|
_maxItems = int.Parse(PageSize);
|
||||||
@ -323,10 +348,10 @@
|
|||||||
{
|
{
|
||||||
_endPage = _pages;
|
_endPage = _pages;
|
||||||
}
|
}
|
||||||
ItemList = Items.Skip((_page - 1) * _maxItems).Take(_maxItems);
|
ItemList = Items.Skip((_page - 1) * _maxItems).Take(_maxItems);
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
OnPageChange?.Invoke(_page);
|
OnPageChange?.Invoke(_page);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateList(int page)
|
public void UpdateList(int page)
|
||||||
{
|
{
|
||||||
@ -369,4 +394,75 @@
|
|||||||
|
|
||||||
UpdateList(_page);
|
UpdateList(_page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Search()
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(_search))
|
||||||
|
{
|
||||||
|
Items = AllItems.Where(item =>
|
||||||
|
{
|
||||||
|
var values = SearchProperties.Split(',')
|
||||||
|
.Select(itemType => GetPropertyValue(item, itemType))
|
||||||
|
.Where(value => value != null)
|
||||||
|
.Select(value => value.ToString().ToLower());
|
||||||
|
|
||||||
|
return values.Any(value => value.Contains(_search.ToLower()));
|
||||||
|
}).ToList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Items = AllItems;
|
||||||
|
}
|
||||||
|
_pages = (int)Math.Ceiling(Items.Count() / (decimal)_maxItems);
|
||||||
|
UpdateList(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private object GetPropertyValue(object obj, string propertyName)
|
||||||
|
{
|
||||||
|
var index = propertyName.IndexOf(".");
|
||||||
|
if (index != -1)
|
||||||
|
{
|
||||||
|
var propertyInfo = obj.GetType().GetProperty(propertyName.Substring(0, index));
|
||||||
|
if (propertyInfo != null)
|
||||||
|
{
|
||||||
|
return GetPropertyValue(propertyInfo.GetValue(obj), propertyName.Substring(index + 1));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var propertyInfo = obj.GetType().GetProperty(propertyName);
|
||||||
|
if (propertyInfo != null)
|
||||||
|
{
|
||||||
|
return propertyInfo.GetValue(obj);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
_search = "";
|
||||||
|
Items = AllItems;
|
||||||
|
_pages = (int)Math.Ceiling(Items.Count() / (decimal)_maxItems);
|
||||||
|
UpdateList(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string FormatSearchProperties()
|
||||||
|
{
|
||||||
|
var properties = new List<string>();
|
||||||
|
foreach (var property in SearchProperties.Split(',', StringSplitOptions.RemoveEmptyEntries))
|
||||||
|
{
|
||||||
|
var index = property.LastIndexOf(".");
|
||||||
|
if (index != -1)
|
||||||
|
{
|
||||||
|
properties.Add(property.Substring(index + 1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
properties.Add(property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string.Join(",", properties);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.3</Version>
|
<Version>4.0.6</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.3</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6</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>
|
||||||
|
@ -124,7 +124,7 @@
|
|||||||
<value>Error Loading Packages</value>
|
<value>Error Loading Packages</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Success.Module.Download" xml:space="preserve">
|
<data name="Success.Module.Download" xml:space="preserve">
|
||||||
<value>Module Package Saved Successfully. You Must <a href={0}>Restart</a> Your Application To Complete The Installation.</value>
|
<value>Module Package Downloaded Successfully. You Must <a href={0}>Restart</a> Your Application To Complete The Installation.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Error.Module.Download" xml:space="preserve">
|
<data name="Error.Module.Download" xml:space="preserve">
|
||||||
<value>Error Downloading Module</value>
|
<value>Error Downloading Module</value>
|
||||||
|
@ -132,6 +132,9 @@
|
|||||||
<data name="Message.Require.ValidName" xml:space="preserve">
|
<data name="Message.Require.ValidName" xml:space="preserve">
|
||||||
<value>You Must Provide A Valid Owner Name And Module Name ( ie. No Punctuation Or Spaces And The Values Cannot Be The Same ) And Choose A Template</value>
|
<value>You Must Provide A Valid Owner Name And Module Name ( ie. No Punctuation Or Spaces And The Values Cannot Be The Same ) And Choose A Template</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Message.Require.ValidDescription" xml:space="preserve">
|
||||||
|
<value>You Must Provide A Valid Description (ie. No Punctuation)</value>
|
||||||
|
</data>
|
||||||
<data name="OwnerName.HelpText" xml:space="preserve">
|
<data name="OwnerName.HelpText" xml:space="preserve">
|
||||||
<value>Enter the name of the organization who is developing this module. It should not contain spaces or punctuation.</value>
|
<value>Enter the name of the organization who is developing this module. It should not contain spaces or punctuation.</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -196,7 +196,7 @@
|
|||||||
<value>Information</value>
|
<value>Information</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PackageName.HelpText" xml:space="preserve">
|
<data name="PackageName.HelpText" xml:space="preserve">
|
||||||
<value>The unique name of the package from which this module was installed</value>
|
<value>The unique name of the package from which this module was installed. This value must be specified within the module's IModule interface specification.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PackageName.Text" xml:space="preserve">
|
<data name="PackageName.Text" xml:space="preserve">
|
||||||
<value>Package Name:</value>
|
<value>Package Name:</value>
|
||||||
@ -228,4 +228,16 @@
|
|||||||
<data name="View License" xml:space="preserve">
|
<data name="View License" xml:space="preserve">
|
||||||
<value>View License</value>
|
<value>View License</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Error.Validate" xml:space="preserve">
|
||||||
|
<value>Error Validating Package</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.Download" xml:space="preserve">
|
||||||
|
<value>Package Version Has Been Verified. Please Select The Download Button To Obtain The Package.</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.Validate" xml:space="preserve">
|
||||||
|
<value>This Package Version Has Not Been Registered In The Oqtane Marketplace Or You Do Not Have The Right To Use It From This Installation</value>
|
||||||
|
</data>
|
||||||
|
<data name="Validate" xml:space="preserve">
|
||||||
|
<value>Validate</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -159,4 +159,10 @@
|
|||||||
<data name="Module Settings" xml:space="preserve">
|
<data name="Module Settings" xml:space="preserve">
|
||||||
<value>Module Settings</value>
|
<value>Module Settings</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Pane.HelpText" xml:space="preserve">
|
||||||
|
<value>The pane where the module will be displayed</value>
|
||||||
|
</data>
|
||||||
|
<data name="Pane.Text" xml:space="preserve">
|
||||||
|
<value>Pane:</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -138,4 +138,13 @@
|
|||||||
<data name="EditProfile.Text" xml:space="preserve">
|
<data name="EditProfile.Text" xml:space="preserve">
|
||||||
<value>Edit</value>
|
<value>Edit</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Category" xml:space="preserve">
|
||||||
|
<value>Category</value>
|
||||||
|
</data>
|
||||||
|
<data name="Order" xml:space="preserve">
|
||||||
|
<value>Order</value>
|
||||||
|
</data>
|
||||||
|
<data name="Title" xml:space="preserve">
|
||||||
|
<value>Title</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -136,7 +136,7 @@
|
|||||||
<value>User Account Created. Please Check Your Email For Verification Instructions.</value>
|
<value>User Account Created. Please Check Your Email For Verification Instructions.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Error.User.AddInfo" xml:space="preserve">
|
<data name="Error.User.AddInfo" xml:space="preserve">
|
||||||
<value>Error Adding User. Please Ensure Password Meets Complexity Requirements And Username Is Not Already In Use.</value>
|
<value>Error Adding User. Please Ensure Password Meets Complexity Requirements And Username And Email Is Not Already In Use.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.Password.NoMatch" xml:space="preserve">
|
<data name="Message.Password.NoMatch" xml:space="preserve">
|
||||||
<value>Passwords Entered Do Not Match</value>
|
<value>Passwords Entered Do Not Match</value>
|
||||||
|
@ -390,4 +390,16 @@
|
|||||||
<data name="DeleteAlias.Header" xml:space="preserve">
|
<data name="DeleteAlias.Header" xml:space="preserve">
|
||||||
<value>Delete Alias</value>
|
<value>Delete Alias</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="SiteGuid.HelpText" xml:space="preserve">
|
||||||
|
<value>The Unique Identifier For The Site</value>
|
||||||
|
</data>
|
||||||
|
<data name="SiteGuid.Text" xml:space="preserve">
|
||||||
|
<value>ID:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Retention.HelpText" xml:space="preserve">
|
||||||
|
<value>Number of days of notifications to retain</value>
|
||||||
|
</data>
|
||||||
|
<data name="Retention.Text" xml:space="preserve">
|
||||||
|
<value>Retention (Days):</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -124,7 +124,7 @@
|
|||||||
<value>Theme: </value>
|
<value>Theme: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Success.Theme.Download" xml:space="preserve">
|
<data name="Success.Theme.Download" xml:space="preserve">
|
||||||
<value>Theme Package Saved Successfully. You Must <a href={0}>Restart</a> Your Application To Complete The Installation.</value>
|
<value>Theme Package Downloaded Successfully. You Must <a href={0}>Restart</a> Your Application To Complete The Installation.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Error.Theme.Download" xml:space="preserve">
|
<data name="Error.Theme.Download" xml:space="preserve">
|
||||||
<value>Error Downloading Theme</value>
|
<value>Error Downloading Theme</value>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
@ -163,7 +163,7 @@
|
|||||||
<value>The license of the theme</value>
|
<value>The license of the theme</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PackageName.HelpText" xml:space="preserve">
|
<data name="PackageName.HelpText" xml:space="preserve">
|
||||||
<value>The unique name of the package from which this module was installed</value>
|
<value>The unique name of the package from which this theme was installed. This value must be specified within the themee's ITheme interface specification.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PackageName.Text" xml:space="preserve">
|
<data name="PackageName.Text" xml:space="preserve">
|
||||||
<value>Package Name:</value>
|
<value>Package Name:</value>
|
||||||
@ -180,4 +180,16 @@
|
|||||||
<data name="View License" xml:space="preserve">
|
<data name="View License" xml:space="preserve">
|
||||||
<value>View License</value>
|
<value>View License</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Error.Validate" xml:space="preserve">
|
||||||
|
<value>Error Validating Package</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.Download" xml:space="preserve">
|
||||||
|
<value>Package Version Has Been Verified. Please Select The Download Button To Obtain The Package.</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.Validate" xml:space="preserve">
|
||||||
|
<value>This Package Version Has Not Been Registered In The Oqtane Marketplace Or You Do Not Have The Right To Use It From This Installation</value>
|
||||||
|
</data>
|
||||||
|
<data name="Validate" xml:space="preserve">
|
||||||
|
<value>Validate</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -144,7 +144,10 @@
|
|||||||
<data name="Message.Text" xml:space="preserve">
|
<data name="Message.Text" xml:space="preserve">
|
||||||
<value>Framework Is Already Up To Date</value>
|
<value>Framework Is Already Up To Date</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MessgeUpgrade.Text" xml:space="preserve">
|
<data name="MessageUpgrade.Text" xml:space="preserve">
|
||||||
<value>Upload A Framework Package (Oqtane.Framework.version.nupkg) And Then Select Upgrade</value>
|
<value>Upload A Framework Package (Oqtane.Framework.version.nupkg) And Then Select Upgrade</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Localhost.Text" xml:space="preserve">
|
||||||
|
<value>You Cannot Perform A System Update In A Development Environment</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -118,7 +118,7 @@
|
|||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<data name="Error.User.AddCheckPass" xml:space="preserve">
|
<data name="Error.User.AddCheckPass" xml:space="preserve">
|
||||||
<value>Error Adding User. Please Ensure Password Meets Complexity Requirements And Username Is Not Already In Use.</value>
|
<value>Error Adding User. Please Ensure Password Meets Complexity Requirements And Username And Email Is Not Already In Use.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.Password.NoMatch" xml:space="preserve">
|
<data name="Message.Password.NoMatch" xml:space="preserve">
|
||||||
<value>Passwords Entered Do Not Match</value>
|
<value>Passwords Entered Do Not Match</value>
|
||||||
@ -171,4 +171,10 @@
|
|||||||
<data name="Password.Placeholder" xml:space="preserve">
|
<data name="Password.Placeholder" xml:space="preserve">
|
||||||
<value>Password</value>
|
<value>Password</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Notify.HelpText" xml:space="preserve">
|
||||||
|
<value>Indicate if new users should receive an email notification</value>
|
||||||
|
</data>
|
||||||
|
<data name="Notify.Text" xml:space="preserve">
|
||||||
|
<value>Notify?</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -390,7 +390,7 @@
|
|||||||
<data name="RoleClaimType.Text" xml:space="preserve">
|
<data name="RoleClaimType.Text" xml:space="preserve">
|
||||||
<value>Role Claim:</value>
|
<value>Role Claim:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ProfileClaimTypes.HelpText" xml:space="preserve">
|
<data name="ProfileClaimTypes.HelpText" xml:space="preserve">
|
||||||
<value>Optionally provide a comma delimited list of user profile claims provided by the identity provider, as well as mappings to your user profile definition. For example if the identity provider includes a 'given_name' claim and you have a 'FirstName' user profile definition you should specify 'given_name:FirstName'.</value>
|
<value>Optionally provide a comma delimited list of user profile claims provided by the identity provider, as well as mappings to your user profile definition. For example if the identity provider includes a 'given_name' claim and you have a 'FirstName' user profile definition you should specify 'given_name:FirstName'.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ProfileClaimTypes.Text" xml:space="preserve">
|
<data name="ProfileClaimTypes.Text" xml:space="preserve">
|
||||||
@ -402,4 +402,37 @@
|
|||||||
<data name="Name" xml:space="preserve">
|
<data name="Name" xml:space="preserve">
|
||||||
<value>Name</value>
|
<value>Name</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Email" xml:space="preserve">
|
||||||
|
<value>Email</value>
|
||||||
|
</data>
|
||||||
|
<data name="ImportUsers.Text" xml:space="preserve">
|
||||||
|
<value>Import Users</value>
|
||||||
|
</data>
|
||||||
|
<data name="AuthFlow.Code" xml:space="preserve">
|
||||||
|
<value>code</value>
|
||||||
|
</data>
|
||||||
|
<data name="AuthFlow.CodeIdToken" xml:space="preserve">
|
||||||
|
<value>code id_token</value>
|
||||||
|
</data>
|
||||||
|
<data name="AuthFlow.CodeIdTokenToken" xml:space="preserve">
|
||||||
|
<value>code id_token token</value>
|
||||||
|
</data>
|
||||||
|
<data name="AuthFlow.CodeToken" xml:space="preserve">
|
||||||
|
<value>code token</value>
|
||||||
|
</data>
|
||||||
|
<data name="AuthFlow.IdToken" xml:space="preserve">
|
||||||
|
<value>id_token</value>
|
||||||
|
</data>
|
||||||
|
<data name="AuthFlow.IdTokenToken" xml:space="preserve">
|
||||||
|
<value>id_token token</value>
|
||||||
|
</data>
|
||||||
|
<data name="AuthFlow.None" xml:space="preserve">
|
||||||
|
<value>none</value>
|
||||||
|
</data>
|
||||||
|
<data name="AuthFlow.Token" xml:space="preserve">
|
||||||
|
<value>token</value>
|
||||||
|
</data>
|
||||||
|
<data name="AuthResponseType" xml:space="preserve">
|
||||||
|
<value>Authorization Response Type</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -117,61 +117,34 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<data name="Template.Text" xml:space="preserve">
|
<data name="ImportFile.HelpText" xml:space="preserve">
|
||||||
<value>Template: </value>
|
<value>Upload or select a tab delimited text file containing user information. The file must be in the Template format specified (Roles can be specified as a comma delimited list).</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Template.Select" xml:space="preserve">
|
<data name="ImportFile.Text" xml:space="preserve">
|
||||||
<value>Select Template</value>
|
<value>Import File:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Module.Create" xml:space="preserve">
|
<data name="Error.Import" xml:space="preserve">
|
||||||
<value>Create Module</value>
|
<value>Error Importing Users</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Module.Activate" xml:space="preserve">
|
<data name="Import" xml:space="preserve">
|
||||||
<value>Activate Module</value>
|
<value>Import</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Info.Module.Creator" xml:space="preserve">
|
<data name="Message.Import.Failure" xml:space="preserve">
|
||||||
<value>Please Note That The Module Creator Is Only Intended To Be Used In A Development Environment</value>
|
<value>User Import Failed. Please Review Your Event Log For More Detailed Information.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Info.Module.Activate" xml:space="preserve">
|
<data name="Message.Import.Success" xml:space="preserve">
|
||||||
<value>Once You Have Compiled The Module And Restarted The Application You Can Activate The Module Below</value>
|
<value>User Import Successful. {0} Users Imported.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Success.Module.Create" xml:space="preserve">
|
<data name="Message.Import.Validation" xml:space="preserve">
|
||||||
<value>The Source Code For Your Module Has Been Created At The Location Specified Below And Must Be Compiled In Order To Make It Functional. Once It Has Been Compiled You Must <a href={0}>Restart</a> Your Application To Apply These Changes.</value>
|
<value>You Must Specify A User File For Import</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.Require.ValidName" xml:space="preserve">
|
<data name="Template" xml:space="preserve">
|
||||||
<value>You Must Provide A Valid Owner Name And Module Name ( ie. No Punctuation Or Spaces And The Values Cannot Be The Same ) And Choose A Template</value>
|
<value>Template</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="OwnerName.HelpText" xml:space="preserve">
|
<data name="Notify.HelpText" xml:space="preserve">
|
||||||
<value>Enter the name of the organization who is developing this module. It should not contain spaces or punctuation.</value>
|
<value>Indicate if new users should receive an email notification</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ModuleName.HelpText" xml:space="preserve">
|
<data name="Notify.Text" xml:space="preserve">
|
||||||
<value>Enter a name for this module. It should not contain spaces or punctuation.</value>
|
<value>Notify?</value>
|
||||||
</data>
|
|
||||||
<data name="Description.HelpText" xml:space="preserve">
|
|
||||||
<value>Enter a short description for the module</value>
|
|
||||||
</data>
|
|
||||||
<data name="Template.HelpText" xml:space="preserve">
|
|
||||||
<value>Select a module template. Templates are located in the wwwroot/Modules/Templates folder on the server.</value>
|
|
||||||
</data>
|
|
||||||
<data name="FrameworkReference.HelpText" xml:space="preserve">
|
|
||||||
<value>Select a framework reference version</value>
|
|
||||||
</data>
|
|
||||||
<data name="Location.HelpText" xml:space="preserve">
|
|
||||||
<value>Location where the module will be created</value>
|
|
||||||
</data>
|
|
||||||
<data name="OwnerName.Text" xml:space="preserve">
|
|
||||||
<value>Owner Name: </value>
|
|
||||||
</data>
|
|
||||||
<data name="ModuleName.Text" xml:space="preserve">
|
|
||||||
<value>Module Name: </value>
|
|
||||||
</data>
|
|
||||||
<data name="Description.Text" xml:space="preserve">
|
|
||||||
<value>Description: </value>
|
|
||||||
</data>
|
|
||||||
<data name="FrameworkReference.Text" xml:space="preserve">
|
|
||||||
<value>Framework Reference: </value>
|
|
||||||
</data>
|
|
||||||
<data name="Location.Text" xml:space="preserve">
|
|
||||||
<value>Location: </value>
|
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
@ -120,4 +120,7 @@
|
|||||||
<data name="PageOfPages" xml:space="preserve">
|
<data name="PageOfPages" xml:space="preserve">
|
||||||
<value>Page {0} of {1}</value>
|
<value>Page {0} of {1}</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="SearchPlaceholder" xml:space="preserve">
|
||||||
|
<value>Search: {0}</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -426,4 +426,10 @@
|
|||||||
<data name="Password.ValidationCriteria" xml:space="preserve">
|
<data name="Password.ValidationCriteria" xml:space="preserve">
|
||||||
<value>Passwords Must Have A Minimum Length Of {0} Characters, Including At Least {1} Unique Character(s), {2}{3}{4}{5} To Satisfy Password Compexity Requirements For This Site.</value>
|
<value>Passwords Must Have A Minimum Length Of {0} Characters, Including At Least {1} Unique Character(s), {2}{3}{4}{5} To Satisfy Password Compexity Requirements For This Site.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ProfileInvalid" xml:space="preserve">
|
||||||
|
<value>{0} Is Not Valid</value>
|
||||||
|
</data>
|
||||||
|
<data name="ProfileRequired" xml:space="preserve">
|
||||||
|
<value>{0} Is Required</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -189,4 +189,13 @@
|
|||||||
<data name="Confirm.Page.Delete" xml:space="preserve">
|
<data name="Confirm.Page.Delete" xml:space="preserve">
|
||||||
<value>Are You Sure You Want To Delete This Page?</value>
|
<value>Are You Sure You Want To Delete This Page?</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Location" xml:space="preserve">
|
||||||
|
<value>Location:</value>
|
||||||
|
</data>
|
||||||
|
<data name="LocationBottom" xml:space="preserve">
|
||||||
|
<value>Bottom</value>
|
||||||
|
</data>
|
||||||
|
<data name="LocationTop" xml:space="preserve">
|
||||||
|
<value>Top</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -39,11 +39,10 @@ namespace Oqtane.Services
|
|||||||
Task<List<Package>> GetPackagesAsync(string type, string search, string price, string package, string sort);
|
Task<List<Package>> GetPackagesAsync(string type, string search, string price, string package, string sort);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a list of packages matching the list of package names
|
/// Returns a list of packages based on installationid
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="names"></param>
|
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<List<Package>> GetPackagesAsync(List<string> packagenames);
|
Task<List<Package>> GetPackageUpdatesAsync(string type);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a specific package
|
/// Returns a specific package
|
||||||
@ -51,7 +50,7 @@ namespace Oqtane.Services
|
|||||||
/// <param name="packageId"></param>
|
/// <param name="packageId"></param>
|
||||||
/// <param name="version"></param>
|
/// <param name="version"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<Package> GetPackageAsync(string packageId, string version);
|
Task<Package> GetPackageAsync(string packageId, string version, bool download);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Downloads a specific package as .nupkg file
|
/// Downloads a specific package as .nupkg file
|
||||||
@ -60,7 +59,7 @@ namespace Oqtane.Services
|
|||||||
/// <param name="version"></param>
|
/// <param name="version"></param>
|
||||||
/// <param name="folder"></param>
|
/// <param name="folder"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task DownloadPackageAsync(string packageId, string version, string folder);
|
Task DownloadPackageAsync(string packageId, string version);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Installs all packages located in //TODO: 2dm where?
|
/// Installs all packages located in //TODO: 2dm where?
|
||||||
|
@ -142,5 +142,14 @@ namespace Oqtane.Services
|
|||||||
/// <param name="siteId">ID of a <see cref="Site"/></param>
|
/// <param name="siteId">ID of a <see cref="Site"/></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<string> GetPasswordRequirementsAsync(int siteId);
|
Task<string> GetPasswordRequirementsAsync(int siteId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Bulk import of users
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="siteId">ID of a <see cref="Site"/></param>
|
||||||
|
/// <param name="fileId">ID of a <see cref="File"/></param>
|
||||||
|
/// <param name="notify">Indicates if new users should be notified by email</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<Dictionary<string, string>> ImportUsersAsync(int siteId, int fileId, bool notify);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,19 +31,19 @@ namespace Oqtane.Services
|
|||||||
return await GetJsonAsync<List<Package>>($"{Apiurl}?type={type}&search={WebUtility.UrlEncode(search)}&price={price}&package={package}&sort={sort}");
|
return await GetJsonAsync<List<Package>>($"{Apiurl}?type={type}&search={WebUtility.UrlEncode(search)}&price={price}&package={package}&sort={sort}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<Package>> GetPackagesAsync(List<string> packagenames)
|
public async Task<List<Package>> GetPackageUpdatesAsync(string type)
|
||||||
{
|
{
|
||||||
return await GetJsonAsync<List<Package>>($"{Apiurl}/list/?names={string.Join(",", packagenames)}");
|
return await GetJsonAsync<List<Package>>($"{Apiurl}/updates/?type={type}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Package> GetPackageAsync(string packageId, string version)
|
public async Task<Package> GetPackageAsync(string packageId, string version, bool download)
|
||||||
{
|
{
|
||||||
return await PostJsonAsync<Package>($"{Apiurl}?packageid={packageId}&version={version}", null);
|
return await PostJsonAsync<Package>($"{Apiurl}?packageid={packageId}&version={version}&download={download}&install=false", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DownloadPackageAsync(string packageId, string version, string folder)
|
public async Task DownloadPackageAsync(string packageId, string version)
|
||||||
{
|
{
|
||||||
await PostAsync($"{Apiurl}?packageid={packageId}&version={version}&folder={folder}");
|
await PostAsync($"{Apiurl}?packageid={packageId}&version={version}&download=true&install=true");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task InstallPackagesAsync()
|
public async Task InstallPackagesAsync()
|
||||||
|
@ -4,6 +4,7 @@ using System.Net.Http;
|
|||||||
using System;
|
using System;
|
||||||
using Oqtane.Documentation;
|
using Oqtane.Documentation;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
namespace Oqtane.Services
|
namespace Oqtane.Services
|
||||||
{
|
{
|
||||||
@ -18,7 +19,7 @@ namespace Oqtane.Services
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<Sync> GetSyncEventsAsync(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", CultureInfo.InvariantCulture)}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,9 @@ using Oqtane.Documentation;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.Extensions.Localization;
|
using Microsoft.Extensions.Localization;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
||||||
|
using Oqtane.Modules.Admin.Roles;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Oqtane.Services
|
namespace Oqtane.Services
|
||||||
{
|
{
|
||||||
@ -123,5 +126,10 @@ namespace Oqtane.Services
|
|||||||
// format requirements
|
// format requirements
|
||||||
return string.Format(passwordValidationCriteriaTemplate, minimumlength, uniquecharacters, digitRequirement, uppercaseRequirement, lowercaseRequirement, punctuationRequirement);
|
return string.Format(passwordValidationCriteriaTemplate, minimumlength, uniquecharacters, digitRequirement, uppercaseRequirement, lowercaseRequirement, punctuationRequirement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<Dictionary<string, string>> ImportUsersAsync(int siteId, int fileId, bool notify)
|
||||||
|
{
|
||||||
|
return await PostJsonAsync<Dictionary<string, string>>($"{Apiurl}/import?siteid={siteId}&fileid={fileId}¬ify={notify}", null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
<div class="main g-0">
|
<div class="main g-0">
|
||||||
<div class="top-row px-4">
|
<div class="top-row px-4">
|
||||||
<div class="ms-auto"><UserProfile /> <Login /> <ControlPanel /></div>
|
<div class="ms-auto"><UserProfile /> <Login /> <ControlPanel LanguageDropdownAlignment="right" /></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row px-4">
|
<div class="row px-4">
|
||||||
|
@ -10,12 +10,14 @@
|
|||||||
@inject IPageModuleService PageModuleService
|
@inject IPageModuleService PageModuleService
|
||||||
@inject ILogService logger
|
@inject ILogService logger
|
||||||
@inject ISettingService SettingService
|
@inject ISettingService SettingService
|
||||||
|
@inject IJSRuntime jsRuntime
|
||||||
|
@inject IServiceProvider ServiceProvider
|
||||||
@inject IStringLocalizer<ControlPanel> Localizer
|
@inject IStringLocalizer<ControlPanel> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
@if (ShowLanguageSwitcher)
|
@if (ShowLanguageSwitcher)
|
||||||
{
|
{
|
||||||
<LanguageSwitcher />
|
<LanguageSwitcher DropdownAlignment="@LanguageDropdownAlignment" />
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (_showEditMode || (PageState.Page.IsPersonalizable && PageState.User != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Registered)))
|
@if (_showEditMode || (PageState.Page.IsPersonalizable && PageState.User != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Registered)))
|
||||||
@ -109,13 +111,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
|
||||||
{
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col text-center">
|
<div class="col text-center">
|
||||||
<label for="Module" class="control-label">@Localizer["Module.Manage"] </label>
|
<label for="Module" class="control-label">@Localizer["Module.Manage"]</label>
|
||||||
<select class="form-select" @bind="@ModuleType">
|
<select class="form-select" @bind="@ModuleType">
|
||||||
<option value="new">@Localizer["Module.AddNew"]</option>
|
<option value="new">@Localizer["Module.AddNew"]</option>
|
||||||
<option value="existing">@Localizer["Module.AddExisting"]</option>
|
<option value="existing">@Localizer["Module.AddExisting"]</option>
|
||||||
@ -180,27 +179,33 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col text-center">
|
<div class="col text-center">
|
||||||
<label for="Title" class="control-label">@Localizer["Title"] </label>
|
<label for="Title" class="control-label">@Localizer["Title"]</label>
|
||||||
<input type="text" name="Title" class="form-control" @bind="@Title" />
|
<input type="text" name="Title" class="form-control" @bind="@Title" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if (_pane.Length > 1)
|
|
||||||
{
|
|
||||||
<div class="row">
|
|
||||||
<div class="col text-center">
|
|
||||||
<label for="Pane" class="control-label">@Localizer["Pane"] </label>
|
|
||||||
<select class="form-select" @bind="@Pane">
|
|
||||||
@foreach (string pane in PageState.Page.Panes)
|
|
||||||
{
|
|
||||||
<option value="@pane">@pane Pane</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col text-center">
|
<div class="col text-center">
|
||||||
<label for="Container" class="control-label">@Localizer["Container"] </label>
|
<label for="Pane" class="control-label">@Localizer["Pane"]</label>
|
||||||
|
<select class="form-select" @bind="@Pane">
|
||||||
|
@foreach (string pane in PageState.Page.Panes)
|
||||||
|
{
|
||||||
|
<option value="@pane">@pane Pane</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col text-center">
|
||||||
|
<label for="Insert" class="control-label">@Localizer["Location"]</label>
|
||||||
|
<select class="form-select" @bind="@Location">
|
||||||
|
<option value="@int.MinValue">@Localizer["LocationTop"]</option>
|
||||||
|
<option value="@int.MaxValue">@Localizer["LocationBottom"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col text-center">
|
||||||
|
<label for="Container" class="control-label">@Localizer["Container"]</label>
|
||||||
<select class="form-select" @bind="@ContainerType">
|
<select class="form-select" @bind="@ContainerType">
|
||||||
@foreach (var container in _containers)
|
@foreach (var container in _containers)
|
||||||
{
|
{
|
||||||
@ -220,13 +225,38 @@
|
|||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-primary col-12 mt-4" @onclick="@AddModule">@Localizer["Page.Module.Add"]</button>
|
<button type="button" class="btn btn-primary col-12 mt-4" @onclick="@AddModule">@Localizer["Page.Module.Add"]</button>
|
||||||
@((MarkupString)Message)
|
@((MarkupString)Message)
|
||||||
}
|
<hr class="app-rule" />
|
||||||
</div>
|
}
|
||||||
|
|
||||||
|
<div class="row d-flex">
|
||||||
|
<div class="col">
|
||||||
|
<button type="button" data-bs-dismiss="offcanvas" class="btn btn-secondary col-12" @onclick=@(async () => await LogoutUser())>@Localizer["Logout"]</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@code{
|
@code{
|
||||||
|
[Parameter]
|
||||||
|
public string ButtonClass { get; set; } = "btn-outline-secondary";
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string ContainerClass { get; set; } = "offcanvas offcanvas-end";
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string HeaderClass { get; set; } = "offcanvas-header";
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string BodyClass { get; set; } = "offcanvas-body overflow-auto";
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public bool ShowLanguageSwitcher { get; set; } = true;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string LanguageDropdownAlignment { get; set; } = string.Empty; // Empty or Left or Right
|
||||||
|
|
||||||
private bool _canViewAdminDashboard = false;
|
private bool _canViewAdminDashboard = false;
|
||||||
private bool _showEditMode = false;
|
private bool _showEditMode = false;
|
||||||
private bool _deleteConfirmation = false;
|
private bool _deleteConfirmation = false;
|
||||||
@ -237,12 +267,22 @@
|
|||||||
private List<Module> _modules = new List<Module>();
|
private List<Module> _modules = new List<Module>();
|
||||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||||
private string _category = "Common";
|
private string _category = "Common";
|
||||||
|
private string _pane = "";
|
||||||
|
|
||||||
protected string PageId { get; private set; } = "-";
|
protected string PageId { get; private set; } = "-";
|
||||||
protected string ModuleId { get; private set; } = "-";
|
protected string ModuleId { get; private set; } = "-";
|
||||||
protected string ModuleType { get; private set; } = "new";
|
protected string ModuleType { get; private set; } = "new";
|
||||||
protected string ModuleDefinitionName { get; private set; } = "-";
|
protected string ModuleDefinitionName { get; private set; } = "-";
|
||||||
|
|
||||||
|
protected string Title { get; private set; } = "";
|
||||||
|
protected string ContainerType { get; private set; } = "";
|
||||||
|
protected int Location { get; private set; } = int.MaxValue;
|
||||||
|
protected string Visibility { get; private set; } = "view";
|
||||||
|
protected string Message { get; private set; } = "";
|
||||||
|
|
||||||
|
private string settingCategory = "CP-category";
|
||||||
|
private string settingPane = "CP-pane";
|
||||||
|
|
||||||
protected string Category
|
protected string Category
|
||||||
{
|
{
|
||||||
get => _category;
|
get => _category;
|
||||||
@ -273,27 +313,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected string Title { get; private set; } = "";
|
|
||||||
protected string ContainerType { get; private set; } = "";
|
|
||||||
protected string Visibility { get; private set; } = "view";
|
|
||||||
protected string Message { get; private set; } = "";
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public string ButtonClass { get; set; } = "btn-outline-secondary";
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public string ContainerClass { get; set; } = "offcanvas offcanvas-end";
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public string HeaderClass { get; set; } = "offcanvas-header";
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public string BodyClass { get; set; } = "offcanvas-body overflow-auto";
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public bool ShowLanguageSwitcher { get; set; } = true;
|
|
||||||
|
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
_canViewAdminDashboard = CanViewAdminDashboard();
|
_canViewAdminDashboard = CanViewAdminDashboard();
|
||||||
@ -301,8 +320,9 @@
|
|||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
||||||
{
|
{
|
||||||
_showEditMode = true;
|
_showEditMode = true;
|
||||||
_pages?.Clear();
|
LoadSettingsAsync();
|
||||||
|
|
||||||
|
_pages?.Clear();
|
||||||
foreach (Page p in PageState.Pages)
|
foreach (Page p in PageState.Pages)
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||||
@ -310,7 +330,6 @@
|
|||||||
_pages.Add(p);
|
_pages.Add(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await LoadSettingsAsync();
|
|
||||||
|
|
||||||
var themes = await ThemeService.GetThemesAsync();
|
var themes = await ThemeService.GetThemesAsync();
|
||||||
_containers = ThemeService.GetContainerControls(themes, PageState.Page.ThemeType);
|
_containers = ThemeService.GetContainerControls(themes, PageState.Page.ThemeType);
|
||||||
@ -434,7 +453,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
pageModule.Pane = Pane;
|
pageModule.Pane = Pane;
|
||||||
pageModule.Order = int.MaxValue;
|
pageModule.Order = Location;
|
||||||
pageModule.ContainerType = ContainerType;
|
pageModule.ContainerType = ContainerType;
|
||||||
|
|
||||||
if (pageModule.ContainerType == PageState.Site.DefaultContainerType)
|
if (pageModule.ContainerType == PageState.Site.DefaultContainerType)
|
||||||
@ -510,7 +529,7 @@
|
|||||||
switch (location)
|
switch (location)
|
||||||
{
|
{
|
||||||
case "Admin":
|
case "Admin":
|
||||||
// get admin dashboard moduleid
|
// get admin dashboard moduleid
|
||||||
module = PageState.Modules.FirstOrDefault(item => item.ModuleDefinitionName == Constants.AdminDashboardModule);
|
module = PageState.Modules.FirstOrDefault(item => item.ModuleDefinitionName == Constants.AdminDashboardModule);
|
||||||
if (module != null)
|
if (module != null)
|
||||||
{
|
{
|
||||||
@ -613,15 +632,41 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string settingCategory = "CP-category";
|
// the following code is duplicated from LoginBase
|
||||||
private string settingPane = "CP-pane";
|
private async Task LogoutUser()
|
||||||
private string _pane = "";
|
{
|
||||||
|
await LoggingService.Log(PageState.Alias, PageState.Page.PageId, null, PageState.User?.UserId, GetType().AssemblyQualifiedName, "Logout", LogFunction.Security, LogLevel.Information, null, "User Logout For Username {Username}", PageState.User?.Username);
|
||||||
|
|
||||||
private async Task LoadSettingsAsync()
|
Route route = new Route(PageState.Uri.AbsoluteUri, PageState.Alias.Path);
|
||||||
|
var url = route.PathAndQuery;
|
||||||
|
|
||||||
|
// verify if anonymous users can access page
|
||||||
|
if (!UserSecurity.IsAuthorized(null, PermissionNames.View, PageState.Page.PermissionList))
|
||||||
|
{
|
||||||
|
url = PageState.Alias.Path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PageState.Runtime == Shared.Runtime.Hybrid)
|
||||||
|
{
|
||||||
|
// hybrid apps utilize an interactive logout
|
||||||
|
await UserService.LogoutUserAsync(PageState.User);
|
||||||
|
var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider));
|
||||||
|
authstateprovider.NotifyAuthenticationChanged();
|
||||||
|
NavigationManager.NavigateTo(url, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// post to the Logout page to complete the logout process
|
||||||
|
var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, returnurl = url };
|
||||||
|
var interop = new Interop(jsRuntime);
|
||||||
|
await interop.SubmitForm(Utilities.TenantUrl(PageState.Alias, "/pages/logout/"), fields);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadSettingsAsync()
|
||||||
{
|
{
|
||||||
Dictionary<string, string> settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
|
_category = SettingService.GetSetting(PageState.User.Settings, settingCategory, "Common");
|
||||||
_category = SettingService.GetSetting(settings, settingCategory, "Common");
|
var pane = SettingService.GetSetting(PageState.User.Settings, settingPane, "");
|
||||||
var pane = SettingService.GetSetting(settings, settingPane, "");
|
|
||||||
if (PageState.Page.Panes.Contains(pane))
|
if (PageState.Page.Panes.Contains(pane))
|
||||||
{
|
{
|
||||||
_pane = pane;
|
_pane = pane;
|
||||||
|
@ -8,11 +8,11 @@
|
|||||||
|
|
||||||
@if (_supportedCultures?.Count() > 1)
|
@if (_supportedCultures?.Count() > 1)
|
||||||
{
|
{
|
||||||
<div class="btn-group" role="group">
|
<div class="btn-group pe-1" role="group">
|
||||||
<button id="btnCultures" type="button" class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<button id="btnCultures" type="button" class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
<span class="oi oi-globe"></span>
|
<span class="oi oi-globe"></span>
|
||||||
</button>
|
</button>
|
||||||
<div class="dropdown-menu" aria-labelledby="btnCultures">
|
<div class="dropdown-menu @MenuAlignment" aria-labelledby="btnCultures">
|
||||||
@foreach (var culture in _supportedCultures)
|
@foreach (var culture in _supportedCultures)
|
||||||
{
|
{
|
||||||
<a class="dropdown-item @(CultureInfo.CurrentUICulture.Name == culture.Name ? "active" : String.Empty)" href="#" @onclick="@(async e => await SetCultureAsync(culture.Name))">@culture.DisplayName</a>
|
<a class="dropdown-item @(CultureInfo.CurrentUICulture.Name == culture.Name ? "active" : String.Empty)" href="#" @onclick="@(async e => await SetCultureAsync(culture.Name))">@culture.DisplayName</a>
|
||||||
@ -23,10 +23,15 @@
|
|||||||
|
|
||||||
@code{
|
@code{
|
||||||
private IEnumerable<Culture> _supportedCultures;
|
private IEnumerable<Culture> _supportedCultures;
|
||||||
|
[Parameter]
|
||||||
|
public string DropdownAlignment { get; set; } = string.Empty; // Empty or Left or Right
|
||||||
|
private string MenuAlignment = string.Empty;
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
var languages = PageState.Languages;
|
MenuAlignment = DropdownAlignment.ToLower() == "right" ? "dropdown-menu-end" : string.Empty;
|
||||||
|
|
||||||
|
var languages = PageState.Languages;
|
||||||
_supportedCultures = languages.Select(l => new Culture { Name = l.Code, DisplayName = l.Name });
|
_supportedCultures = languages.Select(l => new Culture { Name = l.Code, DisplayName = l.Name });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ namespace Oqtane.Themes.Controls
|
|||||||
{
|
{
|
||||||
[Inject] public NavigationManager NavigationManager { get; set; }
|
[Inject] public NavigationManager NavigationManager { get; set; }
|
||||||
[Inject] public IUserService UserService { get; set; }
|
[Inject] public IUserService UserService { get; set; }
|
||||||
|
[Inject] public ISettingService SettingService { get; set; }
|
||||||
[Inject] public IJSRuntime jsRuntime { get; set; }
|
[Inject] public IJSRuntime jsRuntime { get; set; }
|
||||||
[Inject] public IServiceProvider ServiceProvider { get; set; }
|
[Inject] public IServiceProvider ServiceProvider { get; set; }
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<nav class="navbar navbar-dark bg-primary fixed-top">
|
<nav class="navbar navbar-dark bg-primary fixed-top">
|
||||||
<Logo /><Menu Orientation="Horizontal" />
|
<Logo /><Menu Orientation="Horizontal" />
|
||||||
<div class="controls ms-auto">
|
<div class="controls ms-auto">
|
||||||
<div class="controls-group"><UserProfile ShowRegister="@_register" /> <Login ShowLogin="@_login" /> <ControlPanel /></div>
|
<div class="controls-group"><UserProfile ShowRegister="@_register" /> <Login ShowLogin="@_login" /> <ControlPanel LanguageDropdownAlignment="right" /></div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
@ -146,6 +146,10 @@
|
|||||||
{
|
{
|
||||||
editmode = false; // reset edit mode when navigating to different page
|
editmode = false; // reset edit mode when navigating to different page
|
||||||
}
|
}
|
||||||
|
if (querystring.ContainsKey("edit") && querystring["edit"] == "true")
|
||||||
|
{
|
||||||
|
editmode = true; // querystring can set edit mode
|
||||||
|
}
|
||||||
|
|
||||||
// get user
|
// get user
|
||||||
if (PageState == null || refresh || PageState.Alias.SiteId != SiteState.Alias.SiteId)
|
if (PageState == null || refresh || PageState.Alias.SiteId != SiteState.Alias.SiteId)
|
||||||
@ -290,7 +294,7 @@
|
|||||||
var urlMapping = await UrlMappingService.GetUrlMappingAsync(site.SiteId, route.PagePath);
|
var urlMapping = await UrlMappingService.GetUrlMappingAsync(site.SiteId, route.PagePath);
|
||||||
if (urlMapping != null && !string.IsNullOrEmpty(urlMapping.MappedUrl))
|
if (urlMapping != null && !string.IsNullOrEmpty(urlMapping.MappedUrl))
|
||||||
{
|
{
|
||||||
var url = (urlMapping.MappedUrl.StartsWith("http")) ? urlMapping.MappedUrl : route.SiteUrl + "/" + urlMapping.MappedUrl;
|
var url = (urlMapping.MappedUrl.StartsWith("http")) ? urlMapping.MappedUrl : route.SiteUrl + "/" + urlMapping.MappedUrl + route.Query;
|
||||||
NavigationManager.NavigateTo(url, false);
|
NavigationManager.NavigateTo(url, false);
|
||||||
}
|
}
|
||||||
else // not mapped
|
else // not mapped
|
||||||
|
@ -72,7 +72,7 @@
|
|||||||
while (index >= 0)
|
while (index >= 0)
|
||||||
{
|
{
|
||||||
var element = content.Substring(index, content.IndexOf(">", index) - index + 1);
|
var element = content.Substring(index, content.IndexOf(">", index) - index + 1);
|
||||||
if (!string.IsNullOrEmpty(element) && !element.ToLower().StartsWith("<script"))
|
if (!string.IsNullOrEmpty(element) && !element.ToLower().StartsWith("<script") && !element.ToLower().StartsWith("</script"))
|
||||||
{
|
{
|
||||||
if (!headcontent.Contains(element))
|
if (!headcontent.Contains(element))
|
||||||
{
|
{
|
||||||
@ -166,7 +166,7 @@
|
|||||||
if (!string.IsNullOrEmpty(src))
|
if (!string.IsNullOrEmpty(src))
|
||||||
{
|
{
|
||||||
src = (src.Contains("://")) ? src : PageState.Alias.BaseUrl + src;
|
src = (src.Contains("://")) ? src : PageState.Alias.BaseUrl + src;
|
||||||
scripts.Add(new { href = src, bundle = "", integrity = integrity, crossorigin = crossorigin, es6module = (type == "module"), location = location });
|
scripts.Add(new { href = src, bundle = "", integrity = integrity, crossorigin = crossorigin, es6module = (type == "module"), location = location.ToString().ToLower() });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<Version>4.0.3</Version>
|
<Version>4.0.6</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.3</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6</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.3</version>
|
<version>4.0.6</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.3</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6</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.3</Version>
|
<Version>4.0.6</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.3</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6</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.3</version>
|
<version>4.0.6</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.3</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6</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.3</Version>
|
<Version>4.0.6</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.3</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6</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.3</version>
|
<version>4.0.6</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.3</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6</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.3</Version>
|
<Version>4.0.6</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.3</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6</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.3</version>
|
<version>4.0.6</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.3</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6</releaseNotes>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
@ -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.3</Version>
|
<Version>4.0.6</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.3</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6</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.3</ApplicationDisplayVersion>
|
<ApplicationDisplayVersion>4.0.6</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>
|
||||||
|
@ -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.3</version>
|
<version>4.0.6</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.3</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6</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.3</version>
|
<version>4.0.6</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.3/Oqtane.Framework.4.0.3.Upgrade.zip</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v4.0.6/Oqtane.Framework.4.0.6.Upgrade.zip</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.3</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6</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.3</version>
|
<version>4.0.6</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.3</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6</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.3</version>
|
<version>4.0.6</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.3</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6</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.3</version>
|
<version>4.0.6</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.3</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6</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.3.Install.zip" -Force
|
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net7.0\publish\*" -DestinationPath "Oqtane.Framework.4.0.6.Install.zip" -Force
|
@ -1 +1 @@
|
|||||||
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net7.0\publish\*" -DestinationPath "Oqtane.Framework.4.0.3.Upgrade.zip" -Force
|
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net7.0\publish\*" -DestinationPath "Oqtane.Framework.4.0.6.Upgrade.zip" -Force
|
@ -139,14 +139,14 @@ namespace Oqtane.Controllers
|
|||||||
if (moduleDefinition.Template.ToLower().Contains("internal"))
|
if (moduleDefinition.Template.ToLower().Contains("internal"))
|
||||||
{
|
{
|
||||||
rootPath = Utilities.PathCombine(rootFolder.FullName, Path.DirectorySeparatorChar.ToString());
|
rootPath = Utilities.PathCombine(rootFolder.FullName, Path.DirectorySeparatorChar.ToString());
|
||||||
moduleDefinition.ModuleDefinitionName = moduleDefinition.ModuleDefinitionName + ", Oqtane.Client";
|
|
||||||
moduleDefinition.ServerManagerType = moduleDefinition.ModuleDefinitionName + ".Manager." + moduleDefinition.Name + "Manager, Oqtane.Server";
|
moduleDefinition.ServerManagerType = moduleDefinition.ModuleDefinitionName + ".Manager." + moduleDefinition.Name + "Manager, Oqtane.Server";
|
||||||
|
moduleDefinition.ModuleDefinitionName = moduleDefinition.ModuleDefinitionName + ", Oqtane.Client";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rootPath = Utilities.PathCombine(rootFolder.Parent.FullName, moduleDefinition.Owner + ".Module." + moduleDefinition.Name, Path.DirectorySeparatorChar.ToString());
|
rootPath = Utilities.PathCombine(rootFolder.Parent.FullName, moduleDefinition.Owner + ".Module." + moduleDefinition.Name, Path.DirectorySeparatorChar.ToString());
|
||||||
moduleDefinition.ModuleDefinitionName = moduleDefinition.ModuleDefinitionName + ", " + moduleDefinition.ModuleDefinitionName + ".Client.Oqtane";
|
|
||||||
moduleDefinition.ServerManagerType = moduleDefinition.ModuleDefinitionName + ".Manager." + moduleDefinition.Name + "Manager, " + moduleDefinition.ModuleDefinitionName + ".Server.Oqtane";
|
moduleDefinition.ServerManagerType = moduleDefinition.ModuleDefinitionName + ".Manager." + moduleDefinition.Name + "Manager, " + moduleDefinition.ModuleDefinitionName + ".Server.Oqtane";
|
||||||
|
moduleDefinition.ModuleDefinitionName = moduleDefinition.ModuleDefinitionName + ", " + moduleDefinition.ModuleDefinitionName + ".Client.Oqtane";
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessTemplatesRecursively(new DirectoryInfo(templatePath), rootPath, rootFolder.Name, templatePath, moduleDefinition);
|
ProcessTemplatesRecursively(new DirectoryInfo(templatePath), rootPath, rootFolder.Name, templatePath, moduleDefinition);
|
||||||
|
@ -51,20 +51,20 @@ namespace Oqtane.Controllers
|
|||||||
return packages;
|
return packages;
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET: api/<controller>/list/?names=x,y,z
|
// GET: api/<controller>/updates/?type=x
|
||||||
[HttpGet("list")]
|
[HttpGet("updates")]
|
||||||
public async Task<IEnumerable<Package>> GetPackages(string names)
|
public async Task<IEnumerable<Package>> GetPackageUpdates(string type)
|
||||||
{
|
{
|
||||||
// get packages
|
// get packages
|
||||||
List<Package> packages = new List<Package>();
|
List<Package> packages = new List<Package>();
|
||||||
var url = _configManager.GetSetting("PackageRegistryUrl", Constants.PackageRegistryUrl);
|
var url = _configManager.GetSetting("PackageRegistryUrl", Constants.PackageRegistryUrl);
|
||||||
if (!string.IsNullOrEmpty(url) && !string.IsNullOrEmpty(names))
|
if (!string.IsNullOrEmpty(url))
|
||||||
{
|
{
|
||||||
using (var client = new HttpClient())
|
using (var client = new HttpClient())
|
||||||
{
|
{
|
||||||
client.DefaultRequestHeaders.Add("Referer", HttpContext.Request.Scheme + "://" + HttpContext.Request.Host.Value);
|
client.DefaultRequestHeaders.Add("Referer", HttpContext.Request.Scheme + "://" + HttpContext.Request.Host.Value);
|
||||||
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(Constants.PackageId, Constants.Version));
|
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(Constants.PackageId, Constants.Version));
|
||||||
packages = await GetJson<List<Package>>(client, url + $"/api/registry/list/?id={_configManager.GetInstallationId()}&version={Constants.Version}&list={names}");
|
packages = await GetJson<List<Package>>(client, url + $"/api/registry/updates/?id={_configManager.GetInstallationId()}&version={Constants.Version}&type={type}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return packages;
|
return packages;
|
||||||
@ -72,14 +72,13 @@ namespace Oqtane.Controllers
|
|||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Authorize(Roles = RoleNames.Host)]
|
[Authorize(Roles = RoleNames.Host)]
|
||||||
public async Task<Package> Post(string packageid, string version, string folder)
|
public async Task<Package> Post(string packageid, string version, string download, string install)
|
||||||
{
|
{
|
||||||
// get package info
|
// get package info
|
||||||
Package package = null;
|
Package package = null;
|
||||||
var url = _configManager.GetSetting("PackageRegistryUrl", Constants.PackageRegistryUrl);
|
var url = _configManager.GetSetting("PackageRegistryUrl", Constants.PackageRegistryUrl);
|
||||||
if (!string.IsNullOrEmpty(url))
|
if (!string.IsNullOrEmpty(url))
|
||||||
{
|
{
|
||||||
var download = (string.IsNullOrEmpty(folder)) ? "false" : "true";
|
|
||||||
using (var client = new HttpClient())
|
using (var client = new HttpClient())
|
||||||
{
|
{
|
||||||
client.DefaultRequestHeaders.Add("Referer", HttpContext.Request.Scheme + "://" + HttpContext.Request.Host.Value);
|
client.DefaultRequestHeaders.Add("Referer", HttpContext.Request.Scheme + "://" + HttpContext.Request.Host.Value);
|
||||||
@ -89,16 +88,16 @@ namespace Oqtane.Controllers
|
|||||||
|
|
||||||
if (package != null)
|
if (package != null)
|
||||||
{
|
{
|
||||||
if (bool.Parse(download))
|
if (bool.Parse(install))
|
||||||
{
|
{
|
||||||
using (var httpClient = new HttpClient())
|
using (var httpClient = new HttpClient())
|
||||||
{
|
{
|
||||||
folder = Path.Combine(_environment.ContentRootPath, folder);
|
var folder = Path.Combine(_environment.ContentRootPath, Constants.PackagesFolder);
|
||||||
var response = await httpClient.GetAsync(package.PackageUrl).ConfigureAwait(false);
|
var response = await httpClient.GetAsync(package.PackageUrl).ConfigureAwait(false);
|
||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
string filename = packageid + "." + version + ".nupkg";
|
string filename = packageid + "." + version + ".nupkg";
|
||||||
using (var fileStream = new FileStream(Path.Combine(folder, filename), FileMode.Create, FileAccess.Write, FileShare.None))
|
using (var fileStream = new FileStream(Path.Combine(Constants.PackagesFolder, filename), FileMode.Create, FileAccess.Write, FileShare.None))
|
||||||
{
|
{
|
||||||
await response.Content.CopyToAsync(fileStream).ConfigureAwait(false);
|
await response.Content.CopyToAsync(fileStream).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -112,7 +111,7 @@ namespace Oqtane.Controllers
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, "Package {PackageId}.{Version} Is Not Registered", packageid, version);
|
_logger.Log(LogLevel.Error, this, LogFunction.Create, "Package {PackageId}.{Version} Is Not Registered In The Marketplace", packageid, version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return package;
|
return package;
|
||||||
@ -120,17 +119,31 @@ namespace Oqtane.Controllers
|
|||||||
|
|
||||||
private async Task<T> GetJson<T>(HttpClient httpClient, string url)
|
private async Task<T> GetJson<T>(HttpClient httpClient, string url)
|
||||||
{
|
{
|
||||||
Uri uri = new Uri(url);
|
try
|
||||||
var response = await httpClient.GetAsync(uri).ConfigureAwait(false);
|
|
||||||
if (response.IsSuccessStatusCode)
|
|
||||||
{
|
{
|
||||||
var stream = await response.Content.ReadAsStreamAsync();
|
Uri uri = new Uri(url);
|
||||||
using (var streamReader = new StreamReader(stream))
|
var response = await httpClient.GetAsync(uri).ConfigureAwait(false);
|
||||||
|
if (response.IsSuccessStatusCode && ValidateJsonContent(response.Content))
|
||||||
{
|
{
|
||||||
return await JsonSerializer.DeserializeAsync<T>(stream, new JsonSerializerOptions(JsonSerializerDefaults.Web));
|
var stream = await response.Content.ReadAsStreamAsync();
|
||||||
|
using (var streamReader = new StreamReader(stream))
|
||||||
|
{
|
||||||
|
return await JsonSerializer.DeserializeAsync<T>(stream, new JsonSerializerOptions(JsonSerializerDefaults.Web));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return default(T);
|
||||||
}
|
}
|
||||||
return default(T);
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Read, ex, "Error Accessing Marketplace API {Url}", url);
|
||||||
|
return default(T);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool ValidateJsonContent(HttpContent content)
|
||||||
|
{
|
||||||
|
var mediaType = content?.Headers.ContentType?.MediaType;
|
||||||
|
return mediaType != null && mediaType.Equals("application/json", StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("install")]
|
[HttpGet("install")]
|
||||||
|
@ -280,16 +280,10 @@ namespace Oqtane.Controllers
|
|||||||
if (currentPage.Path != page.Path)
|
if (currentPage.Path != page.Path)
|
||||||
{
|
{
|
||||||
var urlMapping = _urlMappings.GetUrlMapping(page.SiteId, currentPage.Path);
|
var urlMapping = _urlMappings.GetUrlMapping(page.SiteId, currentPage.Path);
|
||||||
if (urlMapping == null)
|
if (urlMapping != null)
|
||||||
{
|
{
|
||||||
urlMapping = new UrlMapping();
|
|
||||||
urlMapping.SiteId = page.SiteId;
|
|
||||||
urlMapping.Url = currentPage.Path;
|
|
||||||
urlMapping.MappedUrl = page.Path;
|
urlMapping.MappedUrl = page.Path;
|
||||||
urlMapping.Requests = 0;
|
_urlMappings.UpdateUrlMapping(urlMapping);
|
||||||
urlMapping.CreatedOn = System.DateTime.UtcNow;
|
|
||||||
urlMapping.RequestedOn = System.DateTime.UtcNow;
|
|
||||||
_urlMappings.AddUrlMapping(urlMapping);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ using Oqtane.Infrastructure;
|
|||||||
using Oqtane.Repository;
|
using Oqtane.Repository;
|
||||||
using Oqtane.Security;
|
using Oqtane.Security;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
using System;
|
||||||
|
|
||||||
namespace Oqtane.Controllers
|
namespace Oqtane.Controllers
|
||||||
{
|
{
|
||||||
@ -133,14 +133,22 @@ namespace Oqtane.Controllers
|
|||||||
var page = _pages.GetPage(pageid);
|
var page = _pages.GetPage(pageid);
|
||||||
if (page != null && page.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, page.SiteId, EntityNames.Page, pageid, PermissionNames.Edit))
|
if (page != null && page.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, page.SiteId, EntityNames.Page, pageid, PermissionNames.Edit))
|
||||||
{
|
{
|
||||||
|
var panes = pane;
|
||||||
|
if (pane == PaneNames.Default || pane == PaneNames.Admin)
|
||||||
|
{
|
||||||
|
// treat default and admin panes as a single pane
|
||||||
|
panes = PaneNames.Default + "," + PaneNames.Admin;
|
||||||
|
pane = PaneNames.Default;
|
||||||
|
}
|
||||||
int order = 1;
|
int order = 1;
|
||||||
List<PageModule> pagemodules = _pageModules.GetPageModules(page.SiteId)
|
List<PageModule> pagemodules = _pageModules.GetPageModules(page.SiteId)
|
||||||
.Where(item => item.PageId == pageid && item.Pane == pane).OrderBy(item => item.Order).ToList();
|
.Where(item => item.PageId == pageid && panes.Split(',').Contains(item.Pane)).OrderBy(item => item.Order).ToList();
|
||||||
foreach (PageModule pagemodule in pagemodules)
|
foreach (PageModule pagemodule in pagemodules)
|
||||||
{
|
{
|
||||||
if (pagemodule.Order != order)
|
if (pagemodule.Order != order || pagemodule.Pane != pane)
|
||||||
{
|
{
|
||||||
pagemodule.Order = order;
|
pagemodule.Order = order;
|
||||||
|
pagemodule.Pane = pane;
|
||||||
_pageModules.UpdatePageModule(pagemodule);
|
_pageModules.UpdatePageModule(pagemodule);
|
||||||
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.PageModule, pagemodule.PageModuleId, SyncEventActions.Update);
|
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.PageModule, pagemodule.PageModuleId, SyncEventActions.Update);
|
||||||
}
|
}
|
||||||
|
@ -26,17 +26,21 @@ namespace Oqtane.Controllers
|
|||||||
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 ISettingRepository _settings;
|
||||||
private readonly IJwtManager _jwtManager;
|
private readonly IJwtManager _jwtManager;
|
||||||
|
private readonly IFileRepository _files;
|
||||||
private readonly ILogManager _logger;
|
private readonly ILogManager _logger;
|
||||||
|
|
||||||
public UserController(IUserRepository users, ITenantManager tenantManager, IUserManager userManager, ISiteRepository sites, IUserPermissions userPermissions, IJwtManager jwtManager, ILogManager logger)
|
public UserController(IUserRepository users, ITenantManager tenantManager, IUserManager userManager, ISiteRepository sites, IUserPermissions userPermissions, ISettingRepository settings, IJwtManager jwtManager, IFileRepository files, ILogManager logger)
|
||||||
{
|
{
|
||||||
_users = users;
|
_users = users;
|
||||||
_tenantManager = tenantManager;
|
_tenantManager = tenantManager;
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_sites = sites;
|
_sites = sites;
|
||||||
_userPermissions = userPermissions;
|
_userPermissions = userPermissions;
|
||||||
|
_settings = settings;
|
||||||
_jwtManager = jwtManager;
|
_jwtManager = jwtManager;
|
||||||
|
_files = files;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,6 +56,12 @@ namespace Oqtane.Controllers
|
|||||||
{
|
{
|
||||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<Setting> settings = _settings.GetSettings(EntityNames.User, user.UserId).ToList();
|
||||||
|
user.Settings = settings.Where(item => !item.IsPrivate || _userPermissions.GetUser(User).UserId == user.UserId)
|
||||||
|
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
|
||||||
|
}
|
||||||
return Filter(user);
|
return Filter(user);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -75,6 +85,12 @@ namespace Oqtane.Controllers
|
|||||||
{
|
{
|
||||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<Setting> settings = _settings.GetSettings(EntityNames.User, user.UserId).ToList();
|
||||||
|
user.Settings = settings.Where(item => !item.IsPrivate || _userPermissions.GetUser(User).UserId == user.UserId)
|
||||||
|
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
|
||||||
|
}
|
||||||
return Filter(user);
|
return Filter(user);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -355,5 +371,41 @@ namespace Oqtane.Controllers
|
|||||||
|
|
||||||
return requirements;
|
return requirements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// POST api/<controller>/import?siteid=x&fileid=y¬ify=z
|
||||||
|
[HttpPost("import")]
|
||||||
|
[Authorize(Roles = RoleNames.Admin)]
|
||||||
|
public async Task<Dictionary<string, string>> Import(string siteid, string fileid, string notify)
|
||||||
|
{
|
||||||
|
if (int.TryParse(siteid, out int SiteId) && SiteId == _tenantManager.GetAlias().SiteId && int.TryParse(fileid, out int FileId) && bool.TryParse(notify, out bool Notify))
|
||||||
|
{
|
||||||
|
var file = _files.GetFile(FileId);
|
||||||
|
if (file != null)
|
||||||
|
{
|
||||||
|
if (_userPermissions.IsAuthorized(User, PermissionNames.View, file.Folder.PermissionList))
|
||||||
|
{
|
||||||
|
return await _userManager.ImportUsers(SiteId, _files.GetFilePath(file), Notify);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Import Attempt {SiteId} {FileId}", siteid, fileid);
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Import File Does Not Exist {SiteId} {FileId}", siteid, fileid);
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Import Attempt {SiteId} {FileId}", siteid, fileid);
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,6 +121,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||||||
|
|
||||||
public static IServiceCollection ConfigureOqtaneCookieOptions(this IServiceCollection services)
|
public static IServiceCollection ConfigureOqtaneCookieOptions(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
|
// note that ConfigureApplicationCookie internally uses an ApplicationScheme of "Identity.Application"
|
||||||
services.ConfigureApplicationCookie(options =>
|
services.ConfigureApplicationCookie(options =>
|
||||||
{
|
{
|
||||||
options.Cookie.HttpOnly = false;
|
options.Cookie.HttpOnly = false;
|
||||||
|
@ -28,7 +28,7 @@ namespace Oqtane.Extensions
|
|||||||
public static OqtaneSiteOptionsBuilder WithSiteAuthentication(this OqtaneSiteOptionsBuilder builder)
|
public static OqtaneSiteOptionsBuilder WithSiteAuthentication(this OqtaneSiteOptionsBuilder builder)
|
||||||
{
|
{
|
||||||
// site cookie authentication options
|
// site cookie authentication options
|
||||||
builder.AddSiteOptions<CookieAuthenticationOptions>((options, alias, sitesettings) =>
|
builder.AddSiteNamedOptions<CookieAuthenticationOptions>(Constants.AuthenticationScheme, (options, alias, sitesettings) =>
|
||||||
{
|
{
|
||||||
options.Cookie.Name = sitesettings.GetValue("LoginOptions:CookieName", ".AspNetCore.Identity.Application");
|
options.Cookie.Name = sitesettings.GetValue("LoginOptions:CookieName", ".AspNetCore.Identity.Application");
|
||||||
});
|
});
|
||||||
@ -44,7 +44,7 @@ namespace Oqtane.Extensions
|
|||||||
options.SaveTokens = false;
|
options.SaveTokens = false;
|
||||||
options.GetClaimsFromUserInfoEndpoint = true;
|
options.GetClaimsFromUserInfoEndpoint = true;
|
||||||
options.CallbackPath = string.IsNullOrEmpty(alias.Path) ? "/signin-" + AuthenticationProviderTypes.OpenIDConnect : "/" + alias.Path + "/signin-" + AuthenticationProviderTypes.OpenIDConnect;
|
options.CallbackPath = string.IsNullOrEmpty(alias.Path) ? "/signin-" + AuthenticationProviderTypes.OpenIDConnect : "/" + alias.Path + "/signin-" + AuthenticationProviderTypes.OpenIDConnect;
|
||||||
options.ResponseType = OpenIdConnectResponseType.Code; // authorization code flow
|
options.ResponseType = sitesettings.GetValue("ExternalLogin:AuthResponseType", "code"); // authorization code flow
|
||||||
options.ResponseMode = OpenIdConnectResponseMode.FormPost; // recommended as most secure
|
options.ResponseMode = OpenIdConnectResponseMode.FormPost; // recommended as most secure
|
||||||
|
|
||||||
// cookie config is required to avoid Correlation Failed errors
|
// cookie config is required to avoid Correlation Failed errors
|
||||||
|
@ -17,10 +17,22 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||||||
}
|
}
|
||||||
|
|
||||||
public OqtaneSiteOptionsBuilder AddSiteOptions<TOptions>(
|
public OqtaneSiteOptionsBuilder AddSiteOptions<TOptions>(
|
||||||
Action<TOptions, Alias, Dictionary<string, string>> action) where TOptions : class, new()
|
Action<TOptions, Alias, Dictionary<string, string>> configureOptions) where TOptions : class, new()
|
||||||
{
|
{
|
||||||
Services.TryAddSingleton<IOptionsMonitorCache<TOptions>, SiteOptionsCache<TOptions>>();
|
Services.TryAddSingleton<IOptionsMonitorCache<TOptions>, SiteOptionsCache<TOptions>>();
|
||||||
Services.AddSingleton<ISiteOptions<TOptions>, SiteOptions<TOptions>> (sp => new SiteOptions<TOptions>(action));
|
Services.AddSingleton<ISiteOptions<TOptions>, SiteOptions<TOptions>> (_ => new SiteOptions<TOptions>(configureOptions));
|
||||||
|
Services.TryAddTransient<IOptionsFactory<TOptions>, SiteOptionsFactory<TOptions>>();
|
||||||
|
Services.TryAddScoped<IOptionsSnapshot<TOptions>>(sp => BuildOptionsManager<TOptions>(sp));
|
||||||
|
Services.TryAddSingleton<IOptions<TOptions>>(sp => BuildOptionsManager<TOptions>(sp));
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OqtaneSiteOptionsBuilder AddSiteNamedOptions<TOptions>(string name,
|
||||||
|
Action<TOptions, Alias, Dictionary<string, string>> configureOptions) where TOptions : class, new()
|
||||||
|
{
|
||||||
|
Services.TryAddSingleton<IOptionsMonitorCache<TOptions>, SiteOptionsCache<TOptions>>();
|
||||||
|
Services.AddSingleton<ISiteNamedOptions<TOptions>, SiteNamedOptions<TOptions>>(_ => new SiteNamedOptions<TOptions>(name, configureOptions));
|
||||||
Services.TryAddTransient<IOptionsFactory<TOptions>, SiteOptionsFactory<TOptions>>();
|
Services.TryAddTransient<IOptionsFactory<TOptions>, SiteOptionsFactory<TOptions>>();
|
||||||
Services.TryAddScoped<IOptionsSnapshot<TOptions>>(sp => BuildOptionsManager<TOptions>(sp));
|
Services.TryAddScoped<IOptionsSnapshot<TOptions>>(sp => BuildOptionsManager<TOptions>(sp));
|
||||||
Services.TryAddSingleton<IOptions<TOptions>>(sp => BuildOptionsManager<TOptions>(sp));
|
Services.TryAddSingleton<IOptions<TOptions>>(sp => BuildOptionsManager<TOptions>(sp));
|
||||||
|
11
Oqtane.Server/Infrastructure/Options/ISiteNamedOptions.cs
Normal file
11
Oqtane.Server/Infrastructure/Options/ISiteNamedOptions.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Oqtane.Models;
|
||||||
|
|
||||||
|
namespace Oqtane.Infrastructure
|
||||||
|
{
|
||||||
|
public interface ISiteNamedOptions<TOptions>
|
||||||
|
where TOptions : class, new()
|
||||||
|
{
|
||||||
|
void Configure(string name, TOptions options, Alias alias, Dictionary<string, string> sitesettings);
|
||||||
|
}
|
||||||
|
}
|
28
Oqtane.Server/Infrastructure/Options/SiteNamedOptions.cs
Normal file
28
Oqtane.Server/Infrastructure/Options/SiteNamedOptions.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Oqtane.Models;
|
||||||
|
|
||||||
|
namespace Oqtane.Infrastructure
|
||||||
|
{
|
||||||
|
public class SiteNamedOptions<TOptions> : ISiteNamedOptions<TOptions>
|
||||||
|
where TOptions : class, new()
|
||||||
|
{
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
private readonly Action<TOptions, Alias, Dictionary<string, string>> configureOptions;
|
||||||
|
|
||||||
|
public SiteNamedOptions(string name, Action<TOptions, Alias, Dictionary<string, string>> configureOptions)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
this.configureOptions = configureOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Configure(string name, TOptions options, Alias alias, Dictionary<string, string> sitesettings)
|
||||||
|
{
|
||||||
|
if (name == Name)
|
||||||
|
{
|
||||||
|
configureOptions(options, alias, sitesettings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,13 +11,15 @@ namespace Oqtane.Infrastructure
|
|||||||
private readonly IConfigureOptions<TOptions>[] _configureOptions;
|
private readonly IConfigureOptions<TOptions>[] _configureOptions;
|
||||||
private readonly IPostConfigureOptions<TOptions>[] _postConfigureOptions;
|
private readonly IPostConfigureOptions<TOptions>[] _postConfigureOptions;
|
||||||
private readonly ISiteOptions<TOptions>[] _siteOptions;
|
private readonly ISiteOptions<TOptions>[] _siteOptions;
|
||||||
|
private readonly ISiteNamedOptions<TOptions>[] _siteNamedOptions;
|
||||||
private readonly IHttpContextAccessor _accessor;
|
private readonly IHttpContextAccessor _accessor;
|
||||||
|
|
||||||
public SiteOptionsFactory(IEnumerable<IConfigureOptions<TOptions>> configureOptions, IEnumerable<IPostConfigureOptions<TOptions>> postConfigureOptions, IEnumerable<ISiteOptions<TOptions>> siteOptions, IHttpContextAccessor accessor)
|
public SiteOptionsFactory(IEnumerable<IConfigureOptions<TOptions>> configureOptions, IEnumerable<IPostConfigureOptions<TOptions>> postConfigureOptions, IEnumerable<ISiteOptions<TOptions>> siteOptions, IEnumerable<ISiteNamedOptions<TOptions>> siteNamedOptions, IHttpContextAccessor accessor)
|
||||||
{
|
{
|
||||||
_configureOptions = configureOptions as IConfigureOptions<TOptions>[] ?? new List<IConfigureOptions<TOptions>>(configureOptions).ToArray();
|
_configureOptions = configureOptions as IConfigureOptions<TOptions>[] ?? new List<IConfigureOptions<TOptions>>(configureOptions).ToArray();
|
||||||
_postConfigureOptions = postConfigureOptions as IPostConfigureOptions<TOptions>[] ?? new List<IPostConfigureOptions<TOptions>>(postConfigureOptions).ToArray();
|
_postConfigureOptions = postConfigureOptions as IPostConfigureOptions<TOptions>[] ?? new List<IPostConfigureOptions<TOptions>>(postConfigureOptions).ToArray();
|
||||||
_siteOptions = siteOptions as ISiteOptions<TOptions>[] ?? new List<ISiteOptions<TOptions>>(siteOptions).ToArray();
|
_siteOptions = siteOptions as ISiteOptions<TOptions>[] ?? new List<ISiteOptions<TOptions>>(siteOptions).ToArray();
|
||||||
|
_siteNamedOptions = siteNamedOptions as ISiteNamedOptions<TOptions>[] ?? new List<ISiteNamedOptions<TOptions>>(siteNamedOptions).ToArray();
|
||||||
_accessor = accessor;
|
_accessor = accessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,6 +46,11 @@ namespace Oqtane.Infrastructure
|
|||||||
{
|
{
|
||||||
siteOption.Configure(options, _accessor.HttpContext.GetAlias(), _accessor.HttpContext.GetSiteSettings());
|
siteOption.Configure(options, _accessor.HttpContext.GetAlias(), _accessor.HttpContext.GetSiteSettings());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var siteNamedOption in _siteNamedOptions)
|
||||||
|
{
|
||||||
|
siteNamedOption.Configure(name, options, _accessor.HttpContext.GetAlias(), _accessor.HttpContext.GetSiteSettings());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// post configuration
|
// post configuration
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
|
|
||||||
@ -18,5 +19,6 @@ namespace Oqtane.Managers
|
|||||||
User VerifyTwoFactor(User user, string token);
|
User VerifyTwoFactor(User user, string token);
|
||||||
Task<User> LinkExternalAccount(User user, string token, string type, string key, string name);
|
Task<User> LinkExternalAccount(User user, string token, string type, string key, string name);
|
||||||
Task<bool> ValidatePassword(string password);
|
Task<bool> ValidatePassword(string password);
|
||||||
|
Task<Dictionary<string, string>> ImportUsers(int siteId, string filePath, bool notify);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
@ -16,24 +17,32 @@ namespace Oqtane.Managers
|
|||||||
public class UserManager : IUserManager
|
public class UserManager : IUserManager
|
||||||
{
|
{
|
||||||
private readonly IUserRepository _users;
|
private readonly IUserRepository _users;
|
||||||
|
private readonly IRoleRepository _roles;
|
||||||
private readonly IUserRoleRepository _userRoles;
|
private readonly IUserRoleRepository _userRoles;
|
||||||
private readonly UserManager<IdentityUser> _identityUserManager;
|
private readonly UserManager<IdentityUser> _identityUserManager;
|
||||||
private readonly SignInManager<IdentityUser> _identitySignInManager;
|
private readonly SignInManager<IdentityUser> _identitySignInManager;
|
||||||
private readonly ITenantManager _tenantManager;
|
private readonly ITenantManager _tenantManager;
|
||||||
private readonly INotificationRepository _notifications;
|
private readonly INotificationRepository _notifications;
|
||||||
private readonly IFolderRepository _folders;
|
private readonly IFolderRepository _folders;
|
||||||
|
private readonly IFileRepository _files;
|
||||||
|
private readonly IProfileRepository _profiles;
|
||||||
|
private readonly ISettingRepository _settings;
|
||||||
private readonly ISyncManager _syncManager;
|
private readonly ISyncManager _syncManager;
|
||||||
private readonly ILogManager _logger;
|
private readonly ILogManager _logger;
|
||||||
|
|
||||||
public UserManager(IUserRepository users, IUserRoleRepository userRoles, UserManager<IdentityUser> identityUserManager, SignInManager<IdentityUser> identitySignInManager, ITenantManager tenantManager, INotificationRepository notifications, IFolderRepository folders, ISyncManager syncManager, ILogManager logger)
|
public UserManager(IUserRepository users, IRoleRepository roles, IUserRoleRepository userRoles, UserManager<IdentityUser> identityUserManager, SignInManager<IdentityUser> identitySignInManager, ITenantManager tenantManager, INotificationRepository notifications, IFolderRepository folders, IFileRepository files, IProfileRepository profiles, ISettingRepository settings, ISyncManager syncManager, ILogManager logger)
|
||||||
{
|
{
|
||||||
_users = users;
|
_users = users;
|
||||||
|
_roles = roles;
|
||||||
_userRoles = userRoles;
|
_userRoles = userRoles;
|
||||||
_identityUserManager = identityUserManager;
|
_identityUserManager = identityUserManager;
|
||||||
_identitySignInManager = identitySignInManager;
|
_identitySignInManager = identitySignInManager;
|
||||||
_tenantManager = tenantManager;
|
_tenantManager = tenantManager;
|
||||||
_notifications = notifications;
|
_notifications = notifications;
|
||||||
_folders = folders;
|
_folders = folders;
|
||||||
|
_files = files;
|
||||||
|
_profiles = profiles;
|
||||||
|
_settings = settings;
|
||||||
_syncManager = syncManager;
|
_syncManager = syncManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
@ -95,6 +104,13 @@ namespace Oqtane.Managers
|
|||||||
IdentityUser identityuser = await _identityUserManager.FindByNameAsync(user.Username);
|
IdentityUser identityuser = await _identityUserManager.FindByNameAsync(user.Username);
|
||||||
if (identityuser == null)
|
if (identityuser == null)
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrEmpty(user.Password))
|
||||||
|
{
|
||||||
|
// create random interal password based on random date and punctuation ie. Jan-23-1981+14:43:12!
|
||||||
|
Random rnd = new Random();
|
||||||
|
var date = DateTime.UtcNow.AddDays(-rnd.Next(50 * 365)).AddHours(rnd.Next(0, 24)).AddMinutes(rnd.Next(0, 60)).AddSeconds(rnd.Next(0, 60));
|
||||||
|
user.Password = date.ToString("MMM-dd-yyyy+HH:mm:ss", CultureInfo.InvariantCulture) + (char)rnd.Next(33, 47);
|
||||||
|
}
|
||||||
identityuser = new IdentityUser();
|
identityuser = new IdentityUser();
|
||||||
identityuser.UserName = user.Username;
|
identityuser.UserName = user.Username;
|
||||||
identityuser.Email = user.Email;
|
identityuser.Email = user.Email;
|
||||||
@ -142,10 +158,13 @@ namespace Oqtane.Managers
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string url = alias.Protocol + alias.Name;
|
if (!user.SuppressNotification)
|
||||||
string body = "Dear " + user.DisplayName + ",\n\nA User Account Has Been Successfully Created For You With The Username " + user.Username + ". Please Visit " + url + " And Use The Login Option To Sign In. If You Do Not Know Your Password, Use The Forgot Password Option On The Login Page To Reset Your Account.\n\nThank You!";
|
{
|
||||||
var notification = new Notification(user.SiteId, User, "User Account Notification", body);
|
string url = alias.Protocol + alias.Name;
|
||||||
_notifications.AddNotification(notification);
|
string body = "Dear " + user.DisplayName + ",\n\nA User Account Has Been Successfully Created For You With The Username " + user.Username + ". Please Visit " + url + " And Use The Login Option To Sign In. If You Do Not Know Your Password, Use The Forgot Password Option On The Login Page To Reset Your Account.\n\nThank You!";
|
||||||
|
var notification = new Notification(user.SiteId, User, "User Account Notification", body);
|
||||||
|
_notifications.AddNotification(notification);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
User.Password = ""; // remove sensitive information
|
User.Password = ""; // remove sensitive information
|
||||||
@ -167,7 +186,7 @@ namespace Oqtane.Managers
|
|||||||
{
|
{
|
||||||
identityuser.Email = user.Email;
|
identityuser.Email = user.Email;
|
||||||
var valid = true;
|
var valid = true;
|
||||||
if (user.Password != "")
|
if (!string.IsNullOrEmpty(user.Password))
|
||||||
{
|
{
|
||||||
var validator = new PasswordValidator<IdentityUser>();
|
var validator = new PasswordValidator<IdentityUser>();
|
||||||
var result = await validator.ValidateAsync(_identityUserManager, null, user.Password);
|
var result = await validator.ValidateAsync(_identityUserManager, null, user.Password);
|
||||||
@ -179,7 +198,10 @@ namespace Oqtane.Managers
|
|||||||
}
|
}
|
||||||
if (valid)
|
if (valid)
|
||||||
{
|
{
|
||||||
await _identityUserManager.UpdateAsync(identityuser);
|
if (!string.IsNullOrEmpty(user.Password))
|
||||||
|
{
|
||||||
|
await _identityUserManager.UpdateAsync(identityuser); // requires password to be provided
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
@ -257,45 +279,52 @@ namespace Oqtane.Managers
|
|||||||
var LastIPAddress = user.LastIPAddress ?? "";
|
var LastIPAddress = user.LastIPAddress ?? "";
|
||||||
|
|
||||||
user = _users.GetUser(user.Username);
|
user = _users.GetUser(user.Username);
|
||||||
if (user.TwoFactorRequired)
|
if (!user.IsDeleted)
|
||||||
{
|
{
|
||||||
var token = await _identityUserManager.GenerateTwoFactorTokenAsync(identityuser, "Email");
|
if (user.TwoFactorRequired)
|
||||||
user.TwoFactorCode = token;
|
{
|
||||||
user.TwoFactorExpiry = DateTime.UtcNow.AddMinutes(10);
|
var token = await _identityUserManager.GenerateTwoFactorTokenAsync(identityuser, "Email");
|
||||||
_users.UpdateUser(user);
|
user.TwoFactorCode = token;
|
||||||
|
user.TwoFactorExpiry = DateTime.UtcNow.AddMinutes(10);
|
||||||
|
_users.UpdateUser(user);
|
||||||
|
|
||||||
string body = "Dear " + user.DisplayName + ",\n\nYou requested a secure verification code to log in to your account. Please enter the secure verification code on the site:\n\n" + token +
|
string body = "Dear " + user.DisplayName + ",\n\nYou requested a secure verification code to log in to your account. Please enter the secure verification code on the site:\n\n" + token +
|
||||||
"\n\nPlease note that the code is only valid for 10 minutes so if you are unable to take action within that time period, you should initiate a new login on the site." +
|
"\n\nPlease note that the code is only valid for 10 minutes so if you are unable to take action within that time period, you should initiate a new login on the site." +
|
||||||
"\n\nThank You!";
|
"\n\nThank You!";
|
||||||
var notification = new Notification(user.SiteId, user, "User Verification Code", body);
|
var notification = new Notification(user.SiteId, user, "User Verification Code", body);
|
||||||
_notifications.AddNotification(notification);
|
_notifications.AddNotification(notification);
|
||||||
|
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Security, "User Verification Notification Sent For {Username}", user.Username);
|
_logger.Log(LogLevel.Information, this, LogFunction.Security, "User Verification Notification Sent For {Username}", user.Username);
|
||||||
user.TwoFactorRequired = true;
|
user.TwoFactorRequired = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
user = _users.GetUser(identityuser.UserName);
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
if (identityuser.EmailConfirmed)
|
||||||
|
{
|
||||||
|
user.IsAuthenticated = true;
|
||||||
|
user.LastLoginOn = DateTime.UtcNow;
|
||||||
|
user.LastIPAddress = LastIPAddress;
|
||||||
|
_users.UpdateUser(user);
|
||||||
|
_logger.Log(LogLevel.Information, this, LogFunction.Security, "User Login Successful {Username}", user.Username);
|
||||||
|
|
||||||
|
if (setCookie)
|
||||||
|
{
|
||||||
|
await _identitySignInManager.SignInAsync(identityuser, isPersistent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Information, this, LogFunction.Security, "User Not Verified {Username}", user.Username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
user = _users.GetUser(identityuser.UserName);
|
_logger.Log(LogLevel.Information, this, LogFunction.Security, "User Login Failed - Account Deleted {Username}", user.Username);
|
||||||
if (user != null)
|
|
||||||
{
|
|
||||||
if (identityuser.EmailConfirmed)
|
|
||||||
{
|
|
||||||
user.IsAuthenticated = true;
|
|
||||||
user.LastLoginOn = DateTime.UtcNow;
|
|
||||||
user.LastIPAddress = LastIPAddress;
|
|
||||||
_users.UpdateUser(user);
|
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Security, "User Login Successful {Username}", user.Username);
|
|
||||||
|
|
||||||
if (setCookie)
|
|
||||||
{
|
|
||||||
await _identitySignInManager.SignInAsync(identityuser, isPersistent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Security, "User Not Verified {Username}", user.Username);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -436,5 +465,189 @@ namespace Oqtane.Managers
|
|||||||
var result = await validator.ValidateAsync(_identityUserManager, null, password);
|
var result = await validator.ValidateAsync(_identityUserManager, null, password);
|
||||||
return result.Succeeded;
|
return result.Succeeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<Dictionary<string, string>> ImportUsers(int siteId, string filePath, bool notify)
|
||||||
|
{
|
||||||
|
var success = true;
|
||||||
|
int rows = 0;
|
||||||
|
int users = 0;
|
||||||
|
|
||||||
|
if (System.IO.File.Exists(filePath))
|
||||||
|
{
|
||||||
|
var roles = _roles.GetRoles(siteId).ToList();
|
||||||
|
var profiles = _profiles.GetProfiles(siteId).ToList();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string row = "";
|
||||||
|
using (var reader = new StreamReader(filePath))
|
||||||
|
{
|
||||||
|
// header row
|
||||||
|
if (reader.Peek() > -1)
|
||||||
|
{
|
||||||
|
row = reader.ReadLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(row.Trim()))
|
||||||
|
{
|
||||||
|
var header = row.Replace("\"", "").Split('\t');
|
||||||
|
if (header[0].Trim() == "Email")
|
||||||
|
{
|
||||||
|
for (int index = 4; index < header.Length - 1; index++)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(header[index].Trim()) && !profiles.Any(item => item.Name == header[index].Trim()))
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Create, "User Import Contains Profile Name {Profile} Which Does Not Exist", header[index]);
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Create, "User Import File Is Not In Correct Format. Please Use Template Provided.");
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
// detail rows
|
||||||
|
while (reader.Peek() > -1)
|
||||||
|
{
|
||||||
|
row = reader.ReadLine();
|
||||||
|
rows++;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(row.Trim()))
|
||||||
|
{
|
||||||
|
var values = row.Replace("\"", "").Split('\t');
|
||||||
|
|
||||||
|
// user
|
||||||
|
var email = (values.Length > 0) ? values[0].Trim() : "";
|
||||||
|
var username = (values.Length > 1) ? values[1].Trim() : "";
|
||||||
|
var displayname = (values.Length > 2) ? values[2].Trim() : "";
|
||||||
|
|
||||||
|
var user = _users.GetUser(username, email);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
user = new User();
|
||||||
|
user.SiteId = siteId;
|
||||||
|
user.Email = values[0];
|
||||||
|
user.Username = (!string.IsNullOrEmpty(username)) ? username : user.Email;
|
||||||
|
user.DisplayName = (!string.IsNullOrEmpty(displayname)) ? displayname : user.Username;
|
||||||
|
user.EmailConfirmed = true;
|
||||||
|
user.SuppressNotification = !notify;
|
||||||
|
user = await AddUser(user);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Create, "User Import Error Importing User {Email} {Username} {DisplayName}", email, username, displayname);
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(displayname))
|
||||||
|
{
|
||||||
|
user.DisplayName = displayname;
|
||||||
|
user.Password = "";
|
||||||
|
user = await UpdateUser(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var rolenames = (values.Length > 3) ? values[3].Trim() : "";
|
||||||
|
if (user != null && !string.IsNullOrEmpty(rolenames))
|
||||||
|
{
|
||||||
|
// roles (comma delimited)
|
||||||
|
foreach (var rolename in rolenames.Split(','))
|
||||||
|
{
|
||||||
|
var role = roles.FirstOrDefault(item => item.Name == rolename.Trim());
|
||||||
|
if (role == null)
|
||||||
|
{
|
||||||
|
role = new Role();
|
||||||
|
role.SiteId = siteId;
|
||||||
|
role.Name = rolename.Trim();
|
||||||
|
role.Description = rolename.Trim();
|
||||||
|
role = _roles.AddRole(role);
|
||||||
|
roles.Add(role);
|
||||||
|
}
|
||||||
|
if (role != null)
|
||||||
|
{
|
||||||
|
var userrole = _userRoles.GetUserRole(user.UserId, role.RoleId, false);
|
||||||
|
if (userrole == null)
|
||||||
|
{
|
||||||
|
userrole = new UserRole();
|
||||||
|
userrole.UserId = user.UserId;
|
||||||
|
userrole.RoleId = role.RoleId;
|
||||||
|
_userRoles.AddUserRole(userrole);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user != null && values.Length > 4)
|
||||||
|
{
|
||||||
|
// profiles
|
||||||
|
var settings = _settings.GetSettings(EntityNames.User, user.UserId);
|
||||||
|
for (int index = 4; index < values.Length - 1; index++)
|
||||||
|
{
|
||||||
|
if (header.Length > index && !string.IsNullOrEmpty(values[index].Trim()))
|
||||||
|
{
|
||||||
|
var profile = profiles.FirstOrDefault(item => item.Name == header[index].Trim());
|
||||||
|
if (profile != null)
|
||||||
|
{
|
||||||
|
var setting = settings.FirstOrDefault(item => item.SettingName == profile.Name);
|
||||||
|
if (setting == null)
|
||||||
|
{
|
||||||
|
setting = new Setting();
|
||||||
|
setting.EntityName = EntityNames.User;
|
||||||
|
setting.EntityId = user.UserId;
|
||||||
|
setting.SettingName = profile.Name;
|
||||||
|
setting.SettingValue = values[index].Trim();
|
||||||
|
_settings.AddSetting(setting);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (setting.SettingValue != values[index].Trim())
|
||||||
|
{
|
||||||
|
setting.SettingValue = values[index].Trim();
|
||||||
|
_settings.UpdateSetting(setting);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
users++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Create, "User Import File Contains No Header Row");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Log(LogLevel.Information, this, LogFunction.Create, "User Import: {Rows} Rows Processed, {Users} Users Imported", rows, users);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Create, ex, "Error Importing User Import File {SiteId} {FilePath} {Notify}", siteId, filePath, notify);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
success = false;
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Create, "User Import File Does Not Exist {FilePath}", filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return results
|
||||||
|
var result = new Dictionary<string, string>();
|
||||||
|
result.Add("Success", success.ToString());
|
||||||
|
result.Add("Users", users.ToString());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
29
Oqtane.Server/Migrations/Tenant/04000601_AddProfileRows.cs
Normal file
29
Oqtane.Server/Migrations/Tenant/04000601_AddProfileRows.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Oqtane.Databases.Interfaces;
|
||||||
|
using Oqtane.Migrations.EntityBuilders;
|
||||||
|
using Oqtane.Repository;
|
||||||
|
|
||||||
|
namespace Oqtane.Migrations.Tenant
|
||||||
|
{
|
||||||
|
[DbContext(typeof(TenantDBContext))]
|
||||||
|
[Migration("Tenant.04.00.06.01")]
|
||||||
|
public class AddProfileRows : MultiDatabaseMigration
|
||||||
|
{
|
||||||
|
public AddProfileRows(IDatabase database) : base(database)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
var profileEntityBuilder = new ProfileEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
|
profileEntityBuilder.AddIntegerColumn("Rows", true);
|
||||||
|
profileEntityBuilder.UpdateColumn("Rows", "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
// not implemented
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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.3</Version>
|
<Version>4.0.6</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.3</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v4.0.6</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>
|
||||||
|
@ -4,6 +4,9 @@ using Microsoft.AspNetCore.Authorization;
|
|||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
using Oqtane.Extensions;
|
||||||
|
using Oqtane.Managers;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
namespace Oqtane.Pages
|
namespace Oqtane.Pages
|
||||||
{
|
{
|
||||||
@ -12,14 +15,16 @@ namespace Oqtane.Pages
|
|||||||
{
|
{
|
||||||
private readonly UserManager<IdentityUser> _identityUserManager;
|
private readonly UserManager<IdentityUser> _identityUserManager;
|
||||||
private readonly SignInManager<IdentityUser> _identitySignInManager;
|
private readonly SignInManager<IdentityUser> _identitySignInManager;
|
||||||
|
private readonly IUserManager _userManager;
|
||||||
|
|
||||||
public LoginModel(UserManager<IdentityUser> identityUserManager, SignInManager<IdentityUser> identitySignInManager)
|
public LoginModel(UserManager<IdentityUser> identityUserManager, SignInManager<IdentityUser> identitySignInManager, IUserManager userManager)
|
||||||
{
|
{
|
||||||
_identityUserManager = identityUserManager;
|
_identityUserManager = identityUserManager;
|
||||||
_identitySignInManager = identitySignInManager;
|
_identitySignInManager = identitySignInManager;
|
||||||
|
_userManager = userManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IActionResult> OnPostAsync(string username, string password, bool remember, string returnurl)
|
public async Task<IActionResult> OnPostAsync(string username, string password, bool remember, string returnurl)
|
||||||
{
|
{
|
||||||
if (!User.Identity.IsAuthenticated && !string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
|
if (!User.Identity.IsAuthenticated && !string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
|
||||||
{
|
{
|
||||||
@ -30,12 +35,18 @@ namespace Oqtane.Pages
|
|||||||
var result = await _identitySignInManager.CheckPasswordSignInAsync(identityuser, password, true);
|
var result = await _identitySignInManager.CheckPasswordSignInAsync(identityuser, password, true);
|
||||||
if (result.Succeeded)
|
if (result.Succeeded)
|
||||||
{
|
{
|
||||||
validuser = true;
|
var alias = HttpContext.GetAlias();
|
||||||
|
var user = _userManager.GetUser(identityuser.UserName, alias.SiteId);
|
||||||
|
if (user != null && !user.IsDeleted)
|
||||||
|
{
|
||||||
|
validuser = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (validuser)
|
if (validuser)
|
||||||
{
|
{
|
||||||
|
// note that .NET Identity uses a hardcoded ApplicationScheme of "Identity.Application" in SignInAsync
|
||||||
await _identitySignInManager.SignInAsync(identityuser, remember);
|
await _identitySignInManager.SignInAsync(identityuser, remember);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -437,17 +437,17 @@ namespace Oqtane.Pages
|
|||||||
"</script>";
|
"</script>";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ParseScripts(string headcontent)
|
private string ParseScripts(string content)
|
||||||
{
|
{
|
||||||
// iterate scripts
|
// iterate scripts
|
||||||
var scripts = "";
|
var scripts = "";
|
||||||
if (!string.IsNullOrEmpty(headcontent))
|
if (!string.IsNullOrEmpty(content))
|
||||||
{
|
{
|
||||||
var index = headcontent.IndexOf("<script");
|
var index = content.IndexOf("<script");
|
||||||
while (index >= 0)
|
while (index >= 0)
|
||||||
{
|
{
|
||||||
scripts += headcontent.Substring(index, headcontent.IndexOf("</script>", index) + 9 - index);
|
scripts += content.Substring(index, content.IndexOf("</script>", index) + 9 - index);
|
||||||
index = headcontent.IndexOf("<script", index + 1);
|
index = content.IndexOf("<script", index + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return scripts;
|
return scripts;
|
||||||
|
@ -32,8 +32,9 @@ namespace Oqtane.Repository
|
|||||||
|
|
||||||
public IEnumerable<File> GetFiles(int folderId, bool tracking)
|
public IEnumerable<File> GetFiles(int folderId, bool tracking)
|
||||||
{
|
{
|
||||||
var alias = _tenants.GetAlias();
|
var folder = _folderRepository.GetFolder(folderId, false);
|
||||||
IEnumerable<Permission> permissions = _permissions.GetPermissions(alias.SiteId, EntityNames.Folder, folderId).ToList();
|
IEnumerable<Permission> permissions = _permissions.GetPermissions(folder.SiteId, EntityNames.Folder, folderId).ToList();
|
||||||
|
|
||||||
IEnumerable<File> files;
|
IEnumerable<File> files;
|
||||||
if (tracking)
|
if (tracking)
|
||||||
{
|
{
|
||||||
@ -46,6 +47,7 @@ namespace Oqtane.Repository
|
|||||||
foreach (File file in files)
|
foreach (File file in files)
|
||||||
{
|
{
|
||||||
file.Folder.PermissionList = permissions.ToList();
|
file.Folder.PermissionList = permissions.ToList();
|
||||||
|
var alias = _tenants.GetAlias();
|
||||||
file.Url = GetFileUrl(file, alias);
|
file.Url = GetFileUrl(file, alias);
|
||||||
}
|
}
|
||||||
return files;
|
return files;
|
||||||
|
@ -11,6 +11,8 @@ namespace Oqtane.Repository
|
|||||||
UserRole UpdateUserRole(UserRole userRole);
|
UserRole UpdateUserRole(UserRole userRole);
|
||||||
UserRole GetUserRole(int userRoleId);
|
UserRole GetUserRole(int userRoleId);
|
||||||
UserRole GetUserRole(int userRoleId, bool tracking);
|
UserRole GetUserRole(int userRoleId, bool tracking);
|
||||||
|
UserRole GetUserRole(int userId, int roleId);
|
||||||
|
UserRole GetUserRole(int userId, int roleId, bool tracking);
|
||||||
void DeleteUserRole(int userRoleId);
|
void DeleteUserRole(int userRoleId);
|
||||||
void DeleteUserRoles(int userId);
|
void DeleteUserRoles(int userId);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ using System.Diagnostics;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Xml;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Oqtane.Infrastructure;
|
using Oqtane.Infrastructure;
|
||||||
@ -148,10 +147,11 @@ namespace Oqtane.Repository
|
|||||||
|
|
||||||
if (moduledefinition == null)
|
if (moduledefinition == null)
|
||||||
{
|
{
|
||||||
// new module definition (version is explicitly not set because it is updated as part of module migrations at startup)
|
// new module definition
|
||||||
moduledefinition = new ModuleDefinition { ModuleDefinitionName = ModuleDefinition.ModuleDefinitionName };
|
moduledefinition = new ModuleDefinition { ModuleDefinitionName = ModuleDefinition.ModuleDefinitionName };
|
||||||
_db.ModuleDefinition.Add(moduledefinition);
|
_db.ModuleDefinition.Add(moduledefinition);
|
||||||
_db.SaveChanges();
|
_db.SaveChanges();
|
||||||
|
// version is explicitly not set because it is updated as part of module migrations at startup
|
||||||
ModuleDefinition.Version = "";
|
ModuleDefinition.Version = "";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -160,6 +160,8 @@ namespace Oqtane.Repository
|
|||||||
ModuleDefinition.Name = (!string.IsNullOrEmpty(moduledefinition.Name)) ? moduledefinition.Name : ModuleDefinition.Name;
|
ModuleDefinition.Name = (!string.IsNullOrEmpty(moduledefinition.Name)) ? moduledefinition.Name : ModuleDefinition.Name;
|
||||||
ModuleDefinition.Description = (!string.IsNullOrEmpty(moduledefinition.Description)) ? moduledefinition.Description : ModuleDefinition.Description;
|
ModuleDefinition.Description = (!string.IsNullOrEmpty(moduledefinition.Description)) ? moduledefinition.Description : ModuleDefinition.Description;
|
||||||
ModuleDefinition.Categories = (!string.IsNullOrEmpty(moduledefinition.Categories)) ? moduledefinition.Categories : ModuleDefinition.Categories;
|
ModuleDefinition.Categories = (!string.IsNullOrEmpty(moduledefinition.Categories)) ? moduledefinition.Categories : ModuleDefinition.Categories;
|
||||||
|
// get current version
|
||||||
|
ModuleDefinition.Version = moduledefinition.Version;
|
||||||
|
|
||||||
// remove module definition from list as it is already synced
|
// remove module definition from list as it is already synced
|
||||||
moduledefinitions.Remove(moduledefinition);
|
moduledefinitions.Remove(moduledefinition);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user