Compare commits
475 Commits
Author | SHA1 | Date | |
---|---|---|---|
a16bc5db28 | |||
51657338f5 | |||
0fe3ea25af | |||
806daaf7c9 | |||
21ff4a83b5 | |||
ecc9aa40d7 | |||
c34ca2a59b | |||
dde7094fe3 | |||
105afdfefc | |||
4c254a8686 | |||
33ca203e57 | |||
2ff4133cd4 | |||
49ad85713e | |||
1978bf151f | |||
506378de82 | |||
53ead7a03f | |||
ab979fd63c | |||
1e84a2238b | |||
5618adf86c | |||
345b0bc95f | |||
b1d6c35e99 | |||
d767f1a101 | |||
c15f2b9a12 | |||
a21a53662b | |||
ebb5340019 | |||
6108bd214e | |||
eed27e101a | |||
2767680bed | |||
4080e30b6f | |||
e89257be62 | |||
d3c40a7e8b | |||
60657d5d25 | |||
71d5ae0e68 | |||
46b8d202c7 | |||
bc193a6470 | |||
577528fa0a | |||
35e78ea633 | |||
d5d4f85003 | |||
c6a49a6f5d | |||
a3ff9373a2 | |||
e6d2e74b17 | |||
e8464206e7 | |||
b6c4934123 | |||
8ee83f738b | |||
c359300375 | |||
eb3361fa07 | |||
1b53da6749 | |||
c701895e29 | |||
e81222821e | |||
cbca8c9e93 | |||
92c4edacf2 | |||
e4c648ee92 | |||
69f6586aa9 | |||
391713b84d | |||
8c6a25e4b4 | |||
250701aff0 | |||
2dfd1bd5a2 | |||
1c7380d4cf | |||
68d9ac88b3 | |||
f6b3874668 | |||
c616878a64 | |||
ad485a68ce | |||
2ebba3b8e7 | |||
4117e6e1c5 | |||
423ee04879 | |||
1625e3ba6c | |||
5a71ab3c20 | |||
b5833bf556 | |||
6c31765965 | |||
6dc1d42d90 | |||
e273a954e6 | |||
a602a942c4 | |||
dd32b33621 | |||
355d0405f4 | |||
c1e1595d58 | |||
ef476ac9b3 | |||
a7aaa7b18b | |||
3abfbab5d1 | |||
b158474e21 | |||
cfbcc41543 | |||
fec0a02b1c | |||
3d93ba1215 | |||
042083c0e7 | |||
e0bb7b7faf | |||
acc4099ac8 | |||
683ad8959a | |||
a559c771cf | |||
8ba0ebf955 | |||
d83ec1827a | |||
314e49f5e1 | |||
412b139796 | |||
9b29487934 | |||
95213e41c4 | |||
644ddfd5e1 | |||
68dd9900c4 | |||
6b100cf70b | |||
6f33e5e8a0 | |||
268e0e72a3 | |||
5380b12294 | |||
2ba1a95c8d | |||
1ad0ee4a71 | |||
fc12903cfd | |||
640d22484d | |||
34dc4d64e6 | |||
bbb547efb6 | |||
5b3640e23d | |||
0fbbe244d8 | |||
57def7da0c | |||
0fcf1c2732 | |||
c15b6cdf79 | |||
06e25e04f8 | |||
f8e04656cd | |||
1c8debd894 | |||
58d8fcd074 | |||
a70f1ee1e0 | |||
271ed3cbe2 | |||
8ddaf57e17 | |||
4f1ead116f | |||
3194c5b600 | |||
717f1a9b76 | |||
b7675a21eb | |||
b0d4c0d578 | |||
b7a1d2df75 | |||
5d31d33804 | |||
a97af42e4b | |||
17c6797afb | |||
c8129607e8 | |||
c2dce38bb1 | |||
8b0b7492f5 | |||
a25cfd87cc | |||
f9432acf1b | |||
c6c468c986 | |||
b92a888583 | |||
692b4b33fb | |||
79f427e10a | |||
340b3e7fe8 | |||
50a44c9416 | |||
3c41493d8e | |||
4566ea436c | |||
499bf3bc28 | |||
489a321763 | |||
9d86d923aa | |||
454529bd6a | |||
ca17dd3ca3 | |||
71c7a3de69 | |||
76fc689337 | |||
af5d25490a | |||
fb161ae783 | |||
b92b20e8d2 | |||
4b19059df1 | |||
baa6ec5cba | |||
1a86b80c61 | |||
3783da3647 | |||
39dfc00693 | |||
c7cad20aa7 | |||
5901365e0e | |||
6324aacba1 | |||
d51ba8f6dd | |||
9b69e135d9 | |||
c3218b2f5a | |||
9bbbff31f8 | |||
432429026b | |||
a47ecbdea9 | |||
f250aff99b | |||
003f14003e | |||
fe4e245cda | |||
668da62519 | |||
fd89254d5a | |||
b4338c1761 | |||
fb3c79617f | |||
b80fe428ac | |||
5806563ba4 | |||
5adecc307f | |||
12d1b5e849 | |||
3f2095870d | |||
1481c76a0d | |||
1cdc80e09b | |||
e568aa8320 | |||
28629aa836 | |||
19f180331b | |||
3292f0b545 | |||
3333bfeeff | |||
eb1ac3bc9b | |||
65ae1a6177 | |||
0fba385b9e | |||
ee65a54684 | |||
82fef82c4f | |||
70383a9b9d | |||
15fdba060c | |||
c1065dab2d | |||
dfb4afc698 | |||
893b09e7e4 | |||
938bcb2b62 | |||
ac45f67a21 | |||
36cd9664b1 | |||
073d330db4 | |||
9ba356c47e | |||
f2bec9b478 | |||
3d0cbdd1a7 | |||
c5f5bf0287 | |||
99986c1b94 | |||
7d669caa3c | |||
b68e3cb10f | |||
e305c488d4 | |||
a2417bbe56 | |||
b3967b36c0 | |||
5fb33dfee9 | |||
c002768e5b | |||
aff33c6a5d | |||
a84b497fae | |||
c33d1bcd3c | |||
4071e14a7e | |||
b5b3f190b7 | |||
d43a3e132c | |||
a90c21f80a | |||
2b768165e5 | |||
e8425ba03a | |||
b0a6f402e9 | |||
02e86a940b | |||
79d03eb43e | |||
b564955f85 | |||
5aed64f614 | |||
a823a4d9b7 | |||
4eed2193f4 | |||
48e7a41af6 | |||
bba5caecf7 | |||
ede6a45f15 | |||
9c65d23229 | |||
5dedfe9295 | |||
95d8c368c8 | |||
49fbfb8bbc | |||
aa3d2a5289 | |||
48ae6df4b7 | |||
c635351a12 | |||
d9ff77fd9a | |||
e1a7954307 | |||
efe6421133 | |||
79b62f4407 | |||
9d17804ac7 | |||
5986355504 | |||
192e6fde92 | |||
ad090e62cc | |||
5c072fea62 | |||
fd01a40810 | |||
7b9a83a273 | |||
f964e0e502 | |||
22acb7c74b | |||
6a99e81e75 | |||
93b6de1caf | |||
1fbab5db2b | |||
950e852dee | |||
826898e3fe | |||
1268149d83 | |||
908299970f | |||
861dde8627 | |||
cc9802a0d8 | |||
69d1f3aa53 | |||
ea4587d842 | |||
fb4c95f945 | |||
95a27af5f2 | |||
9d7b25ade6 | |||
3a8f4199cd | |||
11002efc02 | |||
367c1c3568 | |||
9e04230d99 | |||
21304db7c9 | |||
f4f6e98045 | |||
ad41eff38a | |||
dbd6cc4148 | |||
dda71e5ccd | |||
cfe8059176 | |||
8b00784ecc | |||
9bcc6bbad0 | |||
ce7995966d | |||
cea5f86df4 | |||
0912253b1b | |||
5aecc4be03 | |||
e09178c14c | |||
477ded6a4a | |||
311c48becb | |||
ec924a7ddf | |||
e39416a786 | |||
51b356cc0e | |||
66b13bdb8b | |||
4ade58da01 | |||
efcfc0783c | |||
aa22db7fe5 | |||
5e0f008b65 | |||
eaf840e1da | |||
fc9e47778b | |||
35edf78aed | |||
07718f0449 | |||
6759156519 | |||
e2688e6feb | |||
65ba6423b1 | |||
a2f8fe3694 | |||
5273a17ab6 | |||
f7c1e7b706 | |||
45bbc4c681 | |||
6af5682548 | |||
24ed06626d | |||
eeff4af167 | |||
17f46afe14 | |||
224618cf21 | |||
ea93ab2a83 | |||
b9f7c39550 | |||
86b4b8e43a | |||
f54d07548e | |||
037db8a3e4 | |||
8f00e85abd | |||
9ccc4c4059 | |||
8408f98693 | |||
cde271fd5b | |||
c21a097fd2 | |||
83c32d4963 | |||
22c2d56da0 | |||
bd8d6e0480 | |||
825eb700b1 | |||
e59ee70f88 | |||
1173a29ed5 | |||
6a2ff369ea | |||
e22606ae79 | |||
bf56c2a9fa | |||
6567b55ea3 | |||
20e90c0de4 | |||
2892d5ec6f | |||
e034811e92 | |||
ee18bbd145 | |||
e3ebbde767 | |||
6a57980439 | |||
765760f3a5 | |||
ab1ac7c995 | |||
99b0c9c079 | |||
e99ab431e1 | |||
1e1aaaccca | |||
318d6afb0e | |||
ba353857eb | |||
1fd42f343d | |||
ec9686cfb8 | |||
a1bff809f3 | |||
76fe155c0a | |||
0b0254aed9 | |||
9258c3849b | |||
d530f30bc9 | |||
7d8bbac04f | |||
7b0c0c3e17 | |||
298c3097f7 | |||
3a3f221418 | |||
78110791e1 | |||
95d4c3d0d5 | |||
e95b49ba8f | |||
92ccb7e463 | |||
2f34bf69e3 | |||
d093c03d92 | |||
d1ade8789b | |||
1291eb5b7c | |||
9c32937c83 | |||
1ec28e9825 | |||
86fce898e5 | |||
bbee87f7df | |||
811ddb9b44 | |||
de798da074 | |||
65d468be33 | |||
9664ff67f3 | |||
99f73cf31e | |||
a216e2b92e | |||
9dfd9ad519 | |||
97133510a7 | |||
43d166fb7d | |||
2f8a580854 | |||
a21a2ab3bb | |||
03106526e9 | |||
a9ac3917b3 | |||
53ff491efd | |||
1feb6ec452 | |||
df00f53e54 | |||
be32af7588 | |||
19be77ed49 | |||
1c43c095bc | |||
59850f4869 | |||
804b61ff95 | |||
d431c607ba | |||
b87b0489e9 | |||
2e593d44ee | |||
71354464e3 | |||
c48b4788c6 | |||
fe9a7333ed | |||
16d9e06db2 | |||
b40ee19735 | |||
d5b0356625 | |||
5ca77c3f64 | |||
54e9307795 | |||
60d7e45048 | |||
931559cca8 | |||
2567c2937d | |||
5b8e6d4df6 | |||
087c053bd5 | |||
7e699136d7 | |||
b7bbfe2a46 | |||
69783b0709 | |||
614041d55e | |||
856f61c2ee | |||
b0b196a522 | |||
62f04d239f | |||
4210d10fca | |||
d02842f0ea | |||
2543b7db79 | |||
41f430429b | |||
4ed4f8d942 | |||
cc5396801b | |||
a72dc36d67 | |||
50989e4e1e | |||
41487440e3 | |||
af72750354 | |||
a58dc49acc | |||
6dbb493d10 | |||
b8c37ff5d7 | |||
04319195c6 | |||
aadd78b7ac | |||
e23da1f5fb | |||
50eeaf8497 | |||
039202559f | |||
5419032e8d | |||
017a92c4bc | |||
a16040a595 | |||
3f6936a999 | |||
d3f3359f66 | |||
3f110aaabd | |||
4e884d57ca | |||
efbe0562f9 | |||
096dfea1a6 | |||
bd5a827593 | |||
404bcaddd4 | |||
d2d52a7eb3 | |||
1761c47713 | |||
82e97aa4fa | |||
e598178869 | |||
b6f89195ab | |||
7aa92c039a | |||
fff36949b7 | |||
c524f17978 | |||
e0a0497dd2 | |||
fce9220dcb | |||
a8ddb64b49 | |||
6d8df2661c | |||
1659de3a2b | |||
9752c72998 | |||
db2e3a518d | |||
94b20662a4 | |||
7bfc0998fd | |||
6707f0efdf | |||
c7fe5a538f | |||
9b20006938 | |||
0b258bd384 | |||
2302c17273 | |||
b619699637 | |||
34434e03fe | |||
29bd31f609 | |||
cf69f9e4c4 | |||
028c9bf0a8 | |||
3e9a4f2c1a | |||
960543d14d | |||
299674f53b | |||
306b78b526 | |||
f369382a54 | |||
ac67d88e74 | |||
1f4f70009c | |||
838d918451 | |||
8e6c73d2bc | |||
aeb599867c | |||
2fe93d4e64 | |||
3e789e0642 | |||
a762f206a1 | |||
c0b13a1f09 | |||
070ddff1b4 |
11
.gitignore
vendored
11
.gitignore
vendored
@ -12,9 +12,7 @@ msbuild.binlog
|
||||
*.idea
|
||||
|
||||
Oqtane.Server/appsettings.json
|
||||
Oqtane.Server/Data/*.mdf
|
||||
Oqtane.Server/Data/*.ldf
|
||||
Oqtane.Server/Data/*.db
|
||||
Oqtane.Server/Data
|
||||
|
||||
/Oqtane.Server/Properties/PublishProfiles/FolderProfile.pubxml
|
||||
Oqtane.Server/Content
|
||||
@ -22,3 +20,10 @@ Oqtane.Server/Packages
|
||||
Oqtane.Server/wwwroot/Content
|
||||
Oqtane.Server/wwwroot/Packages/*.log
|
||||
|
||||
Oqtane.Server/wwwroot/Modules
|
||||
!Oqtane.Server/wwwroot/Modules/Oqtane.Modules.*
|
||||
!Oqtane.Server/wwwroot/Modules/Templates
|
||||
|
||||
Oqtane.Server/wwwroot/Themes
|
||||
!Oqtane.Server/wwwroot/Themes/Oqtane.Themes.*
|
||||
!Oqtane.Server/wwwroot/Themes/Templates
|
||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018-2021 .NET Foundation
|
||||
Copyright (c) 2018-2022 .NET Foundation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -15,7 +15,7 @@
|
||||
<div style="@_display">
|
||||
<CascadingAuthenticationState>
|
||||
<CascadingValue Value="@PageState">
|
||||
<SiteRouter Runtime="@Runtime" RenderMode="@RenderMode" OnStateChange="@ChangeState" />
|
||||
<SiteRouter Runtime="@Runtime" RenderMode="@RenderMode" VisitorId="@VisitorId" OnStateChange="@ChangeState" />
|
||||
</CascadingValue>
|
||||
</CascadingAuthenticationState>
|
||||
</div>
|
||||
@ -39,6 +39,15 @@
|
||||
[Parameter]
|
||||
public string RenderMode { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public int VisitorId { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string RemoteIPAddress { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string AuthorizationToken { get; set; }
|
||||
|
||||
private bool _initialized = false;
|
||||
private string _display = "display: none;";
|
||||
private Installation _installation = new Installation { Success = false, Message = "" };
|
||||
@ -47,36 +56,22 @@
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
SiteState.RemoteIPAddress = RemoteIPAddress;
|
||||
SiteState.AntiForgeryToken = AntiForgeryToken;
|
||||
InstallationService.SetAntiForgeryTokenHeader(AntiForgeryToken);
|
||||
SiteState.AuthorizationToken = AuthorizationToken;
|
||||
|
||||
_installation = await InstallationService.IsInstalled();
|
||||
if (_installation.Alias != null)
|
||||
{
|
||||
SiteState.Alias = _installation.Alias;
|
||||
}
|
||||
else
|
||||
{
|
||||
_installation.Message = "Site Not Configured Correctly - No Matching Alias Exists For Host Name";
|
||||
}
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
if (string.IsNullOrEmpty(AntiForgeryToken))
|
||||
{
|
||||
// parameter values are not set when running on WebAssembly (seems to be a .NET 5 bug) - need to retrieve using JSInterop
|
||||
var interop = new Interop(JSRuntime);
|
||||
|
||||
SiteState.AntiForgeryToken = await interop.GetElementByName(Constants.RequestVerificationToken);
|
||||
InstallationService.SetAntiForgeryTokenHeader(SiteState.AntiForgeryToken);
|
||||
|
||||
Runtime = await interop.GetElementByName("app_runtime");
|
||||
RenderMode = await interop.GetElementByName("app_rendermode");
|
||||
}
|
||||
_display = "";
|
||||
StateHasChanged();
|
||||
}
|
||||
|
@ -46,6 +46,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||
services.AddScoped<ILocalizationService, LocalizationService>();
|
||||
services.AddScoped<ILanguageService, LanguageService>();
|
||||
services.AddScoped<IDatabaseService, DatabaseService>();
|
||||
services.AddScoped<IUrlMappingService, UrlMappingService>();
|
||||
services.AddScoped<IVisitorService, VisitorService>();
|
||||
services.AddScoped<ISyncService, SyncService>();
|
||||
|
||||
return services;
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
if (!String.IsNullOrEmpty(_server) && !String.IsNullOrEmpty(_database))
|
||||
{
|
||||
connectionString = $"Data Source={_server};AttachDbFilename=|DataDirectory|\\{_database}.mdf;Initial Catalog={_database};Integrated Security=SSPI;";
|
||||
connectionString = $"Data Source={_server};AttachDbFilename=|DataDirectory|\\{_database}.mdf;Initial Catalog={_database};Integrated Security=SSPI;Encrypt=false;";
|
||||
}
|
||||
|
||||
return connectionString;
|
||||
|
@ -28,7 +28,7 @@
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="pwd" HelpText="Enter the password to use for the database" ResourceKey="Pwd">Password:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="pwd" type="password" class="form-control" @bind="@_pwd" />
|
||||
<input id="pwd" type="password" class="form-control" @bind="@_pwd" autocomplete="new-password" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -40,7 +40,7 @@
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="pwd" HelpText="Enter the password to use for the database" ResourceKey="Pwd">Password:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="pwd" type="password" class="form-control" @bind="@_pwd" />
|
||||
<input id="pwd" type="password" class="form-control" @bind="@_pwd" autocomplete="new-password" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
@namespace Oqtane.Installer.Controls
|
||||
@implements Oqtane.Interfaces.IDatabaseConfigControl
|
||||
@inject IStringLocalizer<SqlServerConfig> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="server" HelpText="Enter the database server" ResourceKey="Server">Server:</Label>
|
||||
@ -34,7 +35,28 @@
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="pwd" HelpText="Enter the password to use for the database" ResourceKey="Pwd">Password:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="pwd" type="password" class="form-control" @bind="@_pwd" />
|
||||
<input id="pwd" type="password" class="form-control" @bind="@_pwd" autocomplete="new-password" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="encryption" HelpText="Specify if you are using an encrypted database connection. It is highly recommended to use encryption in a production environment." ResourceKey="Encryption">Encryption:</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="encryption" class="form-select custom-select" @bind="@_encryption">
|
||||
<option value="true">@SharedLocalizer["True"]</option>
|
||||
<option value="false">@SharedLocalizer["False"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@if (_encryption == "true")
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="trustservercertificate" HelpText="Specify the type of certificate you are using for encryption" ResourceKey="TrustServerCertificate">Certificate:</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="encryption" class="form-select custom-select" @bind="@_trustservercertificate">
|
||||
<option value="true">@Localizer["Self Signed"]</option>
|
||||
<option value="false">@Localizer["Verifiable"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@ -45,6 +67,8 @@
|
||||
private string _security = "integrated";
|
||||
private string _uid = String.Empty;
|
||||
private string _pwd = String.Empty;
|
||||
private string _encryption = "false";
|
||||
private string _trustservercertificate = "false";
|
||||
|
||||
public string GetConnectionString()
|
||||
{
|
||||
@ -60,16 +84,11 @@
|
||||
connectionString += "Integrated Security=SSPI;";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!String.IsNullOrEmpty(_uid) && !String.IsNullOrEmpty(_pwd))
|
||||
{
|
||||
connectionString += $"User ID={_uid};Password={_pwd};";
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionString = String.Empty;
|
||||
}
|
||||
}
|
||||
connectionString += $"Encrypt={_encryption};";
|
||||
connectionString += $"TrustServerCertificate={_trustservercertificate};";
|
||||
|
||||
return connectionString;
|
||||
}
|
||||
|
@ -24,10 +24,10 @@
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="databasetype" HelpText="Select the type of database you wish to use" ResourceKey="DatabaseType">Database:</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="databasetype" class="form-select custom-select" value="@_databaseName" @onchange="(e => DatabaseChanged(e))">
|
||||
@if (_databases != null)
|
||||
{
|
||||
foreach (var database in _databases)
|
||||
<select id="databasetype" class="form-select custom-select" value="@_databaseName" @onchange="(e => DatabaseChanged(e))">
|
||||
@foreach (var database in _databases)
|
||||
{
|
||||
if (database.IsDefault)
|
||||
{
|
||||
@ -38,8 +38,8 @@
|
||||
<option value="@database.Name">@Localizer[@database.Name]</option>
|
||||
}
|
||||
}
|
||||
}
|
||||
</select>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@{
|
||||
@ -62,13 +62,19 @@
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="password" HelpText="Provide a password for the primary user account" ResourceKey="Password">Password:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="password" type="password" class="form-control" @bind="@_hostPassword" />
|
||||
<div class="input-group">
|
||||
<input id="password" type="@_passwordtype" class="form-control" @bind="@_hostPassword" autocomplete="new-password" />
|
||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglepassword</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="confirm" HelpText="Please confirm the password entered above by entering it again" ResourceKey="Confirm">Confirm:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="confirm" type="password" class="form-control" @bind="@_confirmPassword" />
|
||||
<div class="input-group">
|
||||
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@_confirmPassword" autocomplete="new-password" />
|
||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglepassword</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
@ -97,13 +103,15 @@
|
||||
|
||||
@code {
|
||||
private List<Database> _databases;
|
||||
private string _databaseName = "LocalDB";
|
||||
private string _databaseName;
|
||||
private Type _databaseConfigType;
|
||||
private object _databaseConfig;
|
||||
private RenderFragment DatabaseConfigComponent { get; set; }
|
||||
|
||||
private string _hostUsername = string.Empty;
|
||||
private string _hostPassword = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private string _confirmPassword = string.Empty;
|
||||
private string _hostEmail = string.Empty;
|
||||
private bool _register = true;
|
||||
@ -112,7 +120,16 @@
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
_databases = await DatabaseService.GetDatabasesAsync();
|
||||
if (_databases.Exists(item => item.IsDefault))
|
||||
{
|
||||
_databaseName = _databases.Find(item => item.IsDefault).Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
_databaseName = "LocalDB";
|
||||
}
|
||||
LoadDatabaseConfigComponent();
|
||||
}
|
||||
|
||||
@ -150,8 +167,8 @@
|
||||
if (firstRender)
|
||||
{
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.IncludeLink("", "stylesheet", "https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css", "text/css", "sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC", "anonymous", "");
|
||||
await interop.IncludeScript("", "https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js", "sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM", "anonymous", "", "head", "");
|
||||
await interop.IncludeLink("", "stylesheet", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/css/bootstrap.min.css", "text/css", "sha512-GQGU0fMMi238uA+a/bdWJfpUGKUkBdgfFdgBm72SUQ6BeyWjoY/ton0tEjH+OSH9iP4Dfh+7HM0I9f5eR0L/4w==", "anonymous", "");
|
||||
await interop.IncludeScript("", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/js/bootstrap.bundle.min.js", "sha512-pax4MlgXjHEPfCwcJLQhigY7+N8rt6bVvWLFyUMuxShv170X53TRzGPmPkZmGBhk+jikR8WBM4yl7A9WMHHqvg==", "anonymous", "", "head");
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,7 +180,9 @@
|
||||
connectionString = databaseConfigControl.GetConnectionString();
|
||||
}
|
||||
|
||||
if (connectionString != "" && !string.IsNullOrEmpty(_hostUsername) && _hostPassword.Length >= 6 && _hostPassword == _confirmPassword && !string.IsNullOrEmpty(_hostEmail) && _hostEmail.Contains("@"))
|
||||
if (connectionString != "" && !string.IsNullOrEmpty(_hostUsername) && !string.IsNullOrEmpty(_hostPassword) && _hostPassword == _confirmPassword && !string.IsNullOrEmpty(_hostEmail) && _hostEmail.Contains("@"))
|
||||
{
|
||||
if (await UserService.ValidatePasswordAsync(_hostPassword))
|
||||
{
|
||||
_loadingDisplay = "";
|
||||
StateHasChanged();
|
||||
@ -199,8 +218,27 @@
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_message = Localizer["Message.Password.Invalid"];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_message = Localizer["Message.Require.DbInfo"];
|
||||
}
|
||||
}
|
||||
|
||||
private void TogglePassword()
|
||||
{
|
||||
if (_passwordtype == "password")
|
||||
{
|
||||
_passwordtype = "text";
|
||||
_togglepassword = SharedLocalizer["HidePassword"];
|
||||
}
|
||||
else
|
||||
{
|
||||
_passwordtype = "password";
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="upload" HelpText="Upload the file you want" ResourceKey="Upload">Upload: </Label>
|
||||
<div class="col-sm-9">
|
||||
<FileManager UploadMultiple="true" ShowFiles="false" FolderId="@_folderId" />
|
||||
<FileManager UploadMultiple="true" ShowFiles="false" FolderId="@_folderId" ShowSuccess="true" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -36,7 +36,9 @@
|
||||
<option value="m">@Localizer["Minute(s)"]</option>
|
||||
<option value="H">@Localizer["Hour(s)"]</option>
|
||||
<option value="d">@Localizer["Day(s)"]</option>
|
||||
<option value="w">@Localizer["Week(s)"]</option>
|
||||
<option value="M">@Localizer["Month(s)"]</option>
|
||||
<option value="O">@Localizer["Once"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@ -170,7 +172,14 @@
|
||||
job.JobType = _jobType;
|
||||
job.IsEnabled = Boolean.Parse(_isEnabled);
|
||||
job.Frequency = _frequency;
|
||||
if (job.Frequency == "O") // once
|
||||
{
|
||||
job.Interval = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
job.Interval = int.Parse(_interval);
|
||||
}
|
||||
job.StartDate = _startDate;
|
||||
if (job.StartDate != null)
|
||||
{
|
||||
|
@ -83,28 +83,28 @@ else
|
||||
|
||||
private string DisplayFrequency(int interval, string frequency)
|
||||
{
|
||||
var result = $"{Localizer["Every"]} {interval.ToString()} ";
|
||||
var result = "";
|
||||
switch (frequency)
|
||||
{
|
||||
case "m":
|
||||
result += Localizer["Minute"];
|
||||
result = $"{Localizer["Every"]} {interval.ToString()} " + Localizer["Minute"];
|
||||
break;
|
||||
case "H":
|
||||
result += Localizer["Hour"];
|
||||
result = $"{Localizer["Every"]} {interval.ToString()} " + Localizer["Hour"];
|
||||
break;
|
||||
case "d":
|
||||
result += Localizer["Day"];
|
||||
result = $"{Localizer["Every"]} {interval.ToString()} " + Localizer["Day"];
|
||||
break;
|
||||
case "w":
|
||||
result = $"{Localizer["Every"]} {interval.ToString()} " + Localizer["Week"];
|
||||
break;
|
||||
case "M":
|
||||
result += Localizer["Month"];
|
||||
result = $"{Localizer["Every"]} {interval.ToString()} " + Localizer["Month"];
|
||||
break;
|
||||
case "O":
|
||||
result = Localizer["Once"];
|
||||
break;
|
||||
}
|
||||
|
||||
if (interval > 1)
|
||||
{
|
||||
result += Localizer["s"];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -114,6 +114,7 @@ else
|
||||
{
|
||||
await JobService.DeleteJobAsync(job.JobId);
|
||||
await logger.LogInformation("Job Deleted {Job}", job);
|
||||
_jobs = await JobService.GetJobsAsync();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -124,13 +125,37 @@ else
|
||||
}
|
||||
|
||||
private async Task StartJob(int jobId)
|
||||
{
|
||||
try
|
||||
{
|
||||
await JobService.StartJobAsync(jobId);
|
||||
await logger.LogInformation("Job Started {JobId}", jobId);
|
||||
AddModuleMessage(Localizer["Message.Job.Start"], MessageType.Success);
|
||||
_jobs = await JobService.GetJobsAsync();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Starting Job {JobId} {Error}", jobId, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Job.Start"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task StopJob(int jobId)
|
||||
{
|
||||
try
|
||||
{
|
||||
await JobService.StopJobAsync(jobId);
|
||||
await logger.LogInformation("Job Stopped {JobId}", jobId);
|
||||
AddModuleMessage(Localizer["Message.Job.Stop"], MessageType.Success);
|
||||
_jobs = await JobService.GetJobsAsync();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Stopping Job {JobId} {Error}", jobId, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Job.Stop"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Refresh()
|
||||
|
@ -113,9 +113,9 @@ else
|
||||
<TabPanel Name="Upload" ResourceKey="Upload" Security="SecurityAccessLevel.Host">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" HelpText="Upload one or more translations. Once they are uploaded click Install to complete the installation." ResourceKey="Module">Language: </Label>
|
||||
<Label Class="col-sm-3" HelpText="Upload one or more translations. Once they are uploaded click Install to complete the installation." ResourceKey="LanguageUpload">Language: </Label>
|
||||
<div class="col-sm-9">
|
||||
<FileManager Filter="nupkg" ShowFiles="true" Folder="Packages" UploadMultiple="true" />
|
||||
<FileManager Folder="@Constants.PackagesFolder" UploadMultiple="true" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -317,7 +317,7 @@ else
|
||||
{
|
||||
try
|
||||
{
|
||||
await PackageService.DownloadPackageAsync(_packageid, _version, "Packages");
|
||||
await PackageService.DownloadPackageAsync(_packageid, _version, Constants.PackagesFolder);
|
||||
await logger.LogInformation("Language Package {Name} {Version} Downloaded Successfully", _packageid, _version);
|
||||
AddModuleMessage(Localizer["Success.Language.Download"], MessageType.Success);
|
||||
StateHasChanged();
|
||||
@ -350,7 +350,7 @@ else
|
||||
var localizationCookieValue = CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture));
|
||||
await interop.SetCookie(CookieRequestCultureProvider.DefaultCookieName, localizationCookieValue, 360);
|
||||
|
||||
NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
|
||||
NavigationManager.NavigateTo(NavigationManager.Uri, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ else
|
||||
var package = _packages.Where(item => item.PackageId == (Constants.PackageId + ".Client." + code)).FirstOrDefault();
|
||||
if (package != null)
|
||||
{
|
||||
upgradeavailable = (Version.Parse(package.Version).CompareTo(Version.Parse(Constants.Version)) > 0);
|
||||
upgradeavailable = (Version.Parse(package.Version).CompareTo(Version.Parse(Constants.Version)) == 0);
|
||||
}
|
||||
|
||||
}
|
||||
@ -97,7 +97,7 @@ else
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
await PackageService.DownloadPackageAsync(Constants.PackageId + ".Client." + code, Constants.Version, "Packages");
|
||||
await PackageService.DownloadPackageAsync(Constants.PackageId + ".Client." + code, Constants.Version, Constants.PackagesFolder);
|
||||
await logger.LogInformation("Translation Downloaded {Code} {Version}", code, Constants.Version);
|
||||
await PackageService.InstallPackagesAsync();
|
||||
AddModuleMessage(string.Format(Localizer["Success.Language.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
|
@ -7,54 +7,82 @@
|
||||
@inject IStringLocalizer<Index> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
@if (_message != string.Empty)
|
||||
{
|
||||
<ModuleMessage Message="@_message" Type="@_type" />
|
||||
}
|
||||
<AuthorizeView Roles="@RoleNames.Registered">
|
||||
<Authorizing>
|
||||
<text>...</text>
|
||||
</Authorizing>
|
||||
<Authorized>
|
||||
<ModuleMessage Message="@Localizer["Info.SignedIn"]" Type="MessageType.Info" />
|
||||
<div>@Localizer["Info.SignedIn"]</div>
|
||||
</Authorized>
|
||||
<NotAuthorized>
|
||||
@if (!twofactor)
|
||||
{
|
||||
<form @ref="login" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<div class="container Oqtane-Modules-Admin-Login" @onkeypress="@(e => KeyPressed(e))">
|
||||
<div class="Oqtane-Modules-Admin-Login" @onkeypress="@(e => KeyPressed(e))">
|
||||
@if (_allowexternallogin)
|
||||
{
|
||||
<button type="button" class="btn btn-primary" @onclick="ExternalLogin">@Localizer["Use"] @PageState.Site.Settings["ExternalLogin:ProviderName"]</button>
|
||||
<br /><br />
|
||||
}
|
||||
@if (_allowsitelogin)
|
||||
{
|
||||
<div class="form-group">
|
||||
<label for="Username" class="control-label">@SharedLocalizer["Username"] </label>
|
||||
<input type="text" @ref="username" name="Username" class="form-control username" placeholder="Username" @bind="@_username" id="Username" required />
|
||||
<Label Class="control-label" For="username" HelpText="Please enter your Username" ResourceKey="Username">Username:</Label>
|
||||
<input id="username" type="text" @ref="username" class="form-control" placeholder="@Localizer["Username.Placeholder"]" @bind="@_username" required />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="Password" class="control-label">@SharedLocalizer["Password"] </label>
|
||||
<input type="password" name="Password" class="form-control password" placeholder="Password" @bind="@_password" id="Password" required />
|
||||
<div class="form-group mt-2">
|
||||
<Label Class="control-label" For="password" HelpText="Please enter your Password" ResourceKey="Password">Password:</Label>
|
||||
<div class="input-group">
|
||||
<input id="password" type="@_passwordtype" name="Password" class="form-control" placeholder="@Localizer["Password.Placeholder"]" @bind="@_password" required />
|
||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglepassword</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="form-check form-check-inline">
|
||||
<label class="form-check-label" for="Remember">@Localizer["RememberMe"]</label>
|
||||
<input type="checkbox" class="form-check-input" name="Remember" @bind="@_remember" id="Remember" />
|
||||
</div>
|
||||
<div class="form-group mt-2">
|
||||
<div class="form-check">
|
||||
<input id="remember" type="checkbox" class="form-check-input" @bind="@_remember" />
|
||||
<Label Class="control-label" For="remember" HelpText="Specify if you would like to be signed back in automatically the next time you visit this site" ResourceKey="Remember">Remember Me?</Label>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary" @onclick="Login">@SharedLocalizer["Login"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
||||
<br /><br />
|
||||
<button type="button" class="btn btn-secondary" @onclick="Forgot">@Localizer["ForgotPassword"]</button>
|
||||
}
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
else
|
||||
{
|
||||
<form @ref="login" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<div class="container Oqtane-Modules-Admin-Login">
|
||||
<div class="form-group">
|
||||
<Label Class="control-label" For="code" HelpText="Please enter the secure verification code which was sent to you by email" ResourceKey="Code">Verification Code:</Label>
|
||||
<input id="code" class="form-control" @bind="@_code" placeholder="@Localizer["Code.Placeholder"]" maxlength="6" required />
|
||||
</div>
|
||||
<br />
|
||||
<button type="button" class="btn btn-primary" @onclick="Login">@SharedLocalizer["Login"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Cancel"]</button>
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
</NotAuthorized>
|
||||
</AuthorizeView>
|
||||
|
||||
@code {
|
||||
private string _returnUrl = string.Empty;
|
||||
private string _message = string.Empty;
|
||||
private MessageType _type = MessageType.Info;
|
||||
private string _username = string.Empty;
|
||||
private string _password = string.Empty;
|
||||
private bool _remember = false;
|
||||
private bool validated = false;
|
||||
|
||||
private bool _allowsitelogin = true;
|
||||
private bool _allowexternallogin = false;
|
||||
private ElementReference login;
|
||||
private bool validated = false;
|
||||
private bool twofactor = false;
|
||||
private string _username = string.Empty;
|
||||
private ElementReference username;
|
||||
private string _password = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private bool _remember = false;
|
||||
private string _code = string.Empty;
|
||||
|
||||
private string _returnUrl = string.Empty;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
||||
|
||||
@ -65,6 +93,20 @@
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
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"))
|
||||
{
|
||||
_returnUrl = PageState.QueryString["returnurl"];
|
||||
@ -75,85 +117,113 @@
|
||||
_username = PageState.QueryString["name"];
|
||||
}
|
||||
|
||||
if (PageState.QueryString.ContainsKey("token"))
|
||||
if (PageState.QueryString.ContainsKey("token") && !string.IsNullOrEmpty(_username))
|
||||
{
|
||||
var user = new User();
|
||||
user.SiteId = PageState.Site.SiteId;
|
||||
user.Username = _username;
|
||||
user = await UserService.VerifyEmailAsync(user, PageState.QueryString["token"]);
|
||||
|
||||
if (PageState.QueryString.ContainsKey("key"))
|
||||
{
|
||||
user = await UserService.LinkUserAsync(user, PageState.QueryString["token"], PageState.Site.Settings["ExternalLogin:ProviderType"], PageState.QueryString["key"], PageState.Site.Settings["ExternalLogin:ProviderName"]);
|
||||
if (user != null)
|
||||
{
|
||||
await logger.LogInformation(LogFunction.Security, "External Login Linkage Successful For Username {Username}", _username);
|
||||
AddModuleMessage(Localizer["Success.Account.Linked"], MessageType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
await logger.LogError(LogFunction.Security, "External Login Linkage Failed For Username {Username}", _username);
|
||||
AddModuleMessage(Localizer["Message.Account.NotLinked"], MessageType.Warning);
|
||||
}
|
||||
_username = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
user = await UserService.VerifyEmailAsync(user, PageState.QueryString["token"]);
|
||||
if (user != null)
|
||||
{
|
||||
await logger.LogInformation(LogFunction.Security, "Email Verified For For Username {Username}", _username);
|
||||
_message = Localizer["Success.Account.Verified"];
|
||||
AddModuleMessage(Localizer["Success.Account.Verified"], MessageType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
await logger.LogError(LogFunction.Security, "Email Verification Failed For Username {Username}", _username);
|
||||
_message = Localizer["Message.Account.NotVerfied"];
|
||||
_type = MessageType.Warning;
|
||||
AddModuleMessage(Localizer["Message.Account.NotVerified"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PageState.QueryString.ContainsKey("status"))
|
||||
{
|
||||
AddModuleMessage(Localizer["ExternalLoginStatus." + PageState.QueryString["status"]], MessageType.Info);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Login {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.LoadLogin"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
if(PageState.User == null)
|
||||
if (firstRender && PageState.User == null)
|
||||
{
|
||||
await username.FocusAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Login()
|
||||
{
|
||||
try
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(login))
|
||||
{
|
||||
if (PageState.Runtime == Oqtane.Shared.Runtime.Server)
|
||||
var user = new User { SiteId = PageState.Site.SiteId, Username = _username, Password = _password, LastIPAddress = SiteState.RemoteIPAddress};
|
||||
|
||||
if (!twofactor)
|
||||
{
|
||||
var user = new User();
|
||||
user.SiteId = PageState.Site.SiteId;
|
||||
user.Username = _username;
|
||||
user.Password = _password;
|
||||
user = await UserService.LoginUserAsync(user, false, false);
|
||||
user = await UserService.LoginUserAsync(user);
|
||||
}
|
||||
else
|
||||
{
|
||||
user = await UserService.VerifyTwoFactorAsync(user, _code);
|
||||
}
|
||||
|
||||
if (user.IsAuthenticated)
|
||||
{
|
||||
await logger.LogInformation(LogFunction.Security, "Login Successful For Username {Username}", _username);
|
||||
// server-side Blazor needs to post to the Login page so that the cookies are set correctly
|
||||
|
||||
// post back to the Login page so that the cookies are set correctly
|
||||
var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, username = _username, password = _password, remember = _remember, returnurl = _returnUrl };
|
||||
string url = Utilities.TenantUrl(PageState.Alias, "/pages/login/");
|
||||
await interop.SubmitForm(url, fields);
|
||||
}
|
||||
else
|
||||
{
|
||||
await logger.LogError(LogFunction.Security, "Login Failed For Username {Username}", _username);
|
||||
AddModuleMessage(Localizer["Error.Login.Fail"], MessageType.Error);
|
||||
}
|
||||
if ((PageState.Site.Settings.ContainsKey("LoginOptions:TwoFactor") && PageState.Site.Settings["LoginOptions:TwoFactor"] == "required") || user.TwoFactorRequired)
|
||||
{
|
||||
twofactor = true;
|
||||
validated = false;
|
||||
AddModuleMessage(Localizer["Message.TwoFactor"], MessageType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
// client-side Blazor
|
||||
var user = new User();
|
||||
user.SiteId = PageState.Site.SiteId;
|
||||
user.Username = _username;
|
||||
user.Password = _password;
|
||||
user = await UserService.LoginUserAsync(user, true, _remember);
|
||||
if (user.IsAuthenticated)
|
||||
if (!twofactor)
|
||||
{
|
||||
await logger.LogInformation(LogFunction.Security, "Login Successful For Username {Username}", _username);
|
||||
var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider));
|
||||
authstateprovider.NotifyAuthenticationChanged();
|
||||
NavigationManager.NavigateTo(NavigateUrl(_returnUrl, true));
|
||||
await logger.LogInformation(LogFunction.Security, "Login Failed For Username {Username}", _username);
|
||||
AddModuleMessage(Localizer["Error.Login.Fail"], MessageType.Error);
|
||||
}
|
||||
else
|
||||
{
|
||||
await logger.LogError(LogFunction.Security, "Login Failed For Username {Username}", _username);
|
||||
AddModuleMessage(Localizer["Error.Login.Fail"], MessageType.Error);
|
||||
await logger.LogInformation(LogFunction.Security, "Two Factor Verification Failed For Username {Username}", _username);
|
||||
AddModuleMessage(Localizer["Error.TwoFactor.Fail"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -162,6 +232,12 @@
|
||||
AddModuleMessage(Localizer["Message.Required.UserInfo"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Performing Login {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Login"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void Cancel()
|
||||
{
|
||||
@ -169,6 +245,8 @@
|
||||
}
|
||||
|
||||
private async Task Forgot()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_username != string.Empty)
|
||||
{
|
||||
@ -177,21 +255,35 @@
|
||||
{
|
||||
await UserService.ForgotPasswordAsync(user);
|
||||
await logger.LogInformation(LogFunction.Security, "Password Reset Notification Sent For Username {Username}", _username);
|
||||
_message = "Please Check The Email Address Associated To Your User Account For A Password Reset Notification";
|
||||
AddModuleMessage(Localizer["Message.ForgotUser"], MessageType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
_message = "User Does Not Exist";
|
||||
_type = MessageType.Warning;
|
||||
AddModuleMessage(Localizer["Message.UserDoesNotExist"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_message = "Please Enter The Username Related To Your Account And Then Select The Forgot Password Option Again";
|
||||
AddModuleMessage(Localizer["Message.ForgotPassword"], MessageType.Info);
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Resetting Password {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.ResetPassword"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
twofactor = false;
|
||||
_username = "";
|
||||
_password = "";
|
||||
ClearModuleMessage();
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task KeyPressed(KeyboardEventArgs e)
|
||||
{
|
||||
@ -200,4 +292,24 @@
|
||||
await Login();
|
||||
}
|
||||
}
|
||||
|
||||
private void TogglePassword()
|
||||
{
|
||||
if (_passwordtype == "password")
|
||||
{
|
||||
_passwordtype = "text";
|
||||
_togglepassword = SharedLocalizer["HidePassword"];
|
||||
}
|
||||
else
|
||||
{
|
||||
_passwordtype = "password";
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
}
|
||||
|
||||
private void ExternalLogin()
|
||||
{
|
||||
NavigationManager.NavigateTo(Utilities.TenantUrl(PageState.Alias, "/pages/external?returnurl=" + _returnUrl), true);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,75 +9,9 @@
|
||||
@inject IStringLocalizer<Detail> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
@if (_initialized)
|
||||
{
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
|
||||
<div class="col-sm-9">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="dateTime" HelpText="The date and time of this log" ResourceKey="DateTime">Date/Time: </Label>
|
||||
<div class="col-sm-9">
|
||||
@ -174,10 +108,12 @@
|
||||
<input id="server" class="form-control" @bind="@_server" readonly />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<NavLink class="btn btn-secondary" href="@CloseUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
|
||||
@code {
|
||||
@code {
|
||||
private bool _initialized = false;
|
||||
private int _logId;
|
||||
private string _logDate = string.Empty;
|
||||
private string _level = string.Empty;
|
||||
@ -219,7 +155,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (log.PageId != null && log.ModuleId != null)
|
||||
if (log.PageId != null && log.ModuleId != null && log.ModuleId != -1)
|
||||
{
|
||||
var pagemodule = await PageModuleService.GetPageModuleAsync(log.PageId.Value, log.ModuleId.Value);
|
||||
if (pagemodule != null)
|
||||
@ -243,6 +179,7 @@
|
||||
_exception = log.Exception;
|
||||
_properties = log.Properties;
|
||||
_server = log.Server;
|
||||
_initialized = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -251,4 +188,16 @@
|
||||
AddModuleMessage(Localizer["Error.Log.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private string CloseUrl()
|
||||
{
|
||||
if (!PageState.QueryString.ContainsKey("level"))
|
||||
{
|
||||
return NavigateUrl();
|
||||
}
|
||||
else
|
||||
{
|
||||
return NavigateUrl(PageState.Page.Path, "level=" + PageState.QueryString["level"] + "&function=" + PageState.QueryString["function"] + "&rows=" + PageState.QueryString["rows"] + "&page=" + PageState.QueryString["page"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
@namespace Oqtane.Modules.Admin.Logs
|
||||
@inherits ModuleBase
|
||||
@inject ILogService LogService
|
||||
@inject ISettingService SettingService
|
||||
@inject IStringLocalizer<Index> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
@ -10,11 +11,13 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<TabStrip>
|
||||
<TabPanel Name="Events" Heading="Events" ResourceKey="Events">
|
||||
<div class="container g-0">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<div class="col-sm-4">
|
||||
<Label For="level" HelpText="Select the log level for event log items" ResourceKey="Level">Level: </Label><br /><br />
|
||||
<select id="level" class="form-select" @onchange="(e => LevelChanged(e))">
|
||||
<select id="level" class="form-select" value="@_level" @onchange="(e => LevelChanged(e))">
|
||||
<option value="-"><@Localizer["AllLevels"]></option>
|
||||
<option value="Trace">@Localizer["Trace"]</option>
|
||||
<option value="Debug">@Localizer["Debug"]</option>
|
||||
@ -26,7 +29,7 @@ else
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<Label For="function" HelpText="Select the function for event log items" ResourceKey="Function">Function: </Label><br /><br />
|
||||
<select id="function" class="form-select" @onchange="(e => FunctionChanged(e))">
|
||||
<select id="function" class="form-select" value="@_function" @onchange="(e => FunctionChanged(e))">
|
||||
<option value="-"><@Localizer["AllFunctions"]></option>
|
||||
<option value="Create">@Localizer["Create"]</option>
|
||||
<option value="Read">@Localizer["Read"]</option>
|
||||
@ -38,7 +41,7 @@ else
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<Label For="rows" HelpText="Select the maximum number of event log items to review. Please note that if you choose more than 10 items the information will be split into pages." ResourceKey="Rows">Maximum Items: </Label><br /><br />
|
||||
<select id="rows" class="form-select" @onchange="(e => RowsChanged(e))">
|
||||
<select id="rows" class="form-select" value="@_rows" @onchange="(e => RowsChanged(e))">
|
||||
<option value="10">10</option>
|
||||
<option value="50">50</option>
|
||||
<option value="100">100</option>
|
||||
@ -46,10 +49,11 @@ else
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
@if (_logs.Any())
|
||||
{
|
||||
<Pager Items="@_logs">
|
||||
<Pager Items="@_logs" CurrentPage="@_page.ToString()" OnPageChange="OnPageChange">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@Localizer["Date"]</th>
|
||||
@ -58,7 +62,7 @@ else
|
||||
<th>@Localizer["Function"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td class="@GetClass(context.Function)"><ActionLink Action="Detail" Parameters="@($"id=" + context.LogId.ToString())" ResourceKey="LogDetails" /></td>
|
||||
<td class="@GetClass(context.Function)"><ActionLink Action="Detail" Parameters="@($"id=" + context.LogId.ToString() + "&level=" + _level + "&function=" + _function + "&rows=" + _rows + "&page=" + _page.ToString())" ResourceKey="LogDetails" /></td>
|
||||
<td class="@GetClass(context.Function)">@context.LogDate</td>
|
||||
<td class="@GetClass(context.Function)">@context.Level</td>
|
||||
<td class="@GetClass(context.Function)">@context.Feature</td>
|
||||
@ -70,13 +74,29 @@ else
|
||||
{
|
||||
<p><em>@Localizer["NoLogs"]</em></p>
|
||||
}
|
||||
</TabPanel>
|
||||
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="retention" HelpText="Number of days of events to retain" ResourceKey="Retention">Retention (Days): </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="retention" class="form-control" @bind="@_retention" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
||||
</TabPanel>
|
||||
</TabStrip>
|
||||
}
|
||||
|
||||
@code {
|
||||
private string _level = "-";
|
||||
private string _function = "-";
|
||||
private string _rows = "10";
|
||||
private int _page = 1;
|
||||
private List<Log> _logs;
|
||||
private string _retention = "";
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
@ -84,7 +104,27 @@ else
|
||||
{
|
||||
try
|
||||
{
|
||||
if (PageState.QueryString.ContainsKey("level"))
|
||||
{
|
||||
_level = PageState.QueryString["level"];
|
||||
}
|
||||
if (PageState.QueryString.ContainsKey("function"))
|
||||
{
|
||||
_function = PageState.QueryString["function"];
|
||||
}
|
||||
if (PageState.QueryString.ContainsKey("rows"))
|
||||
{
|
||||
_rows = PageState.QueryString["rows"];
|
||||
}
|
||||
if (PageState.QueryString.ContainsKey("page") && int.TryParse(PageState.QueryString["page"], out int page))
|
||||
{
|
||||
_page = page;
|
||||
}
|
||||
|
||||
await GetLogs();
|
||||
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
_retention = SettingService.GetSetting(settings, "LogRetention", "30");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -170,4 +210,27 @@ else
|
||||
}
|
||||
return classname;
|
||||
}
|
||||
|
||||
private async Task SaveSiteSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
settings = SettingService.SetSetting(settings, "LogRetention", _retention, true);
|
||||
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
||||
|
||||
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving Site Settings {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPageChange(int page)
|
||||
{
|
||||
_page = page;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -67,13 +67,12 @@
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-success" @onclick="CreateModule">@Localizer["Module.Create"]</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="button" class="btn btn-success" @onclick="ActivateModule">@Localizer["Module.Activate"]</button>
|
||||
</form>
|
||||
<button type="button" class="btn btn-success" @onclick="CreateModule">@Localizer["Module.Create"]</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="button" class="btn btn-success" @onclick="ActivateModule">@Localizer["Module.Activate"]</button>
|
||||
}
|
||||
|
||||
@code {
|
||||
@ -92,14 +91,9 @@
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
try
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_moduledefinitionname = SettingService.GetSetting(ModuleState.Settings, "ModuleDefinitionName", "");
|
||||
_templates = await ModuleDefinitionService.GetModuleDefinitionTemplatesAsync();
|
||||
_versions = Constants.ReleaseVersions.Split(',').Where(item => Version.Parse(item).CompareTo(Version.Parse("2.0.0")) >= 0).ToArray();
|
||||
|
||||
if (string.IsNullOrEmpty(_moduledefinitionname))
|
||||
{
|
||||
AddModuleMessage(Localizer["Info.Module.Creator"], MessageType.Info);
|
||||
@ -109,6 +103,14 @@
|
||||
AddModuleMessage(Localizer["Info.Module.Activate"], MessageType.Info);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_templates = await ModuleDefinitionService.GetModuleDefinitionTemplatesAsync();
|
||||
_versions = Constants.ReleaseVersions.Split(',').Where(item => Version.Parse(item).CompareTo(Version.Parse("2.0.0")) >= 0).ToArray();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Module Creator");
|
||||
@ -122,18 +124,24 @@
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (IsValid(_owner) && IsValid(_module) && _owner != _module && _template != "-")
|
||||
{
|
||||
var moduleDefinition = new ModuleDefinition { Owner = _owner, Name = _module, Description = _description, Template = _template, Version = _reference };
|
||||
moduleDefinition = await ModuleDefinitionService.CreateModuleDefinitionAsync(moduleDefinition);
|
||||
|
||||
var settings = ModuleState.Settings;
|
||||
var settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId);
|
||||
SettingService.SetSetting(settings, "ModuleDefinitionName", moduleDefinition.ModuleDefinitionName);
|
||||
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
|
||||
|
||||
GetLocation();
|
||||
|
||||
AddModuleMessage(string.Format(Localizer["Success.Module.Create"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Require.ValidName"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Creating Module");
|
||||
|
@ -1,7 +1,9 @@
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Models;
|
||||
|
||||
namespace Oqtane.Modules.Admin.ModuleCreator
|
||||
{
|
||||
[PrivateApi("Mark this as private, since it's not very useful in the public docs")]
|
||||
public class ModuleInfo : IModule
|
||||
{
|
||||
public ModuleDefinition ModuleDefinition => new ModuleDefinition
|
||||
|
@ -70,7 +70,7 @@
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" HelpText="Upload one or more module packages. Once they are uploaded click Install to complete the installation." ResourceKey="Module">Module: </Label>
|
||||
<div class="col-sm-9">
|
||||
<FileManager Filter="nupkg" ShowFiles="false" Folder="Packages" UploadMultiple="true" />
|
||||
<FileManager Folder="@Constants.PackagesFolder" UploadMultiple="true" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -229,7 +229,7 @@
|
||||
{
|
||||
try
|
||||
{
|
||||
await PackageService.DownloadPackageAsync(_packageid, _version, "Packages");
|
||||
await PackageService.DownloadPackageAsync(_packageid, _version, Constants.PackagesFolder);
|
||||
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _packageid, _version);
|
||||
AddModuleMessage(Localizer["Success.Module.Download"], MessageType.Success);
|
||||
_productname = "";
|
||||
|
@ -81,19 +81,23 @@
|
||||
private List<Template> _templates;
|
||||
private string _template = "-";
|
||||
private string[] _versions;
|
||||
private string _reference = Constants.Version;
|
||||
private string _reference = "local";
|
||||
private string _minversion = "2.0.0";
|
||||
private string _location = string.Empty;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
AddModuleMessage(Localizer["Info.Module.Development"], MessageType.Info);
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_templates = await ModuleDefinitionService.GetModuleDefinitionTemplatesAsync();
|
||||
_versions = Constants.ReleaseVersions.Split(',').Where(item => Version.Parse(item).CompareTo(Version.Parse("2.0.0")) >= 0).ToArray();
|
||||
AddModuleMessage(Localizer["Info.Module.Development"], MessageType.Info);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -22,6 +22,7 @@ else
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@SharedLocalizer["Name"]</th>
|
||||
<th>@SharedLocalizer["Version"]</th>
|
||||
<th>@Localizer["InUse"]</th>
|
||||
<th>@SharedLocalizer["Expires"]</th>
|
||||
<th style="width: 1px;"> </th>
|
||||
</Header>
|
||||
@ -35,13 +36,26 @@ else
|
||||
</td>
|
||||
<td>@context.Name</td>
|
||||
<td>@context.Version</td>
|
||||
<td>
|
||||
@if(context.AssemblyName == "Oqtane.Client" || PageState.Modules.Where(m => m.ModuleDefinition?.ModuleDefinitionId == context.ModuleDefinitionId).FirstOrDefault() != null)
|
||||
{
|
||||
<span>@SharedLocalizer["Yes"]</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>@SharedLocalizer["No"]</span>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@((MarkupString)PurchaseLink(context.PackageName))
|
||||
</td>
|
||||
<td>
|
||||
@if (UpgradeAvailable(context.PackageName, context.Version))
|
||||
@{
|
||||
var version = UpgradeAvailable(context.PackageName, context.Version);
|
||||
}
|
||||
@if (version != context.Version)
|
||||
{
|
||||
<button type="button" class="btn btn-success" @onclick=@(async () => await DownloadModule(context.PackageName, context.Version))>@SharedLocalizer["Upgrade"]</button>
|
||||
<button type="button" class="btn btn-success" @onclick=@(async () => await DownloadModule(context.PackageName, version))>@SharedLocalizer["Upgrade"]</button>
|
||||
}
|
||||
</td>
|
||||
</Row>
|
||||
@ -92,26 +106,24 @@ else
|
||||
return link;
|
||||
}
|
||||
|
||||
private bool UpgradeAvailable(string packagename, string version)
|
||||
private string UpgradeAvailable(string packagename, string version)
|
||||
{
|
||||
var upgradeavailable = false;
|
||||
if (!string.IsNullOrEmpty(packagename) && _packages != null)
|
||||
{
|
||||
var package = _packages.Where(item => item.PackageId == packagename).FirstOrDefault();
|
||||
if (package != null)
|
||||
if (package != null && Version.Parse(package.Version).CompareTo(Version.Parse(version)) > 0)
|
||||
{
|
||||
upgradeavailable = (Version.Parse(package.Version).CompareTo(Version.Parse(version)) > 0);
|
||||
return package.Version;
|
||||
}
|
||||
|
||||
}
|
||||
return upgradeavailable;
|
||||
return version;
|
||||
}
|
||||
|
||||
private async Task DownloadModule(string packagename, string version)
|
||||
{
|
||||
try
|
||||
{
|
||||
await PackageService.DownloadPackageAsync(packagename, version, "Packages");
|
||||
await PackageService.DownloadPackageAsync(packagename, version, Constants.PackagesFolder);
|
||||
await logger.LogInformation("Module Downloaded {ModuleDefinitionName} {Version}", packagename, version);
|
||||
await ModuleDefinitionService.InstallModuleDefinitionsAsync();
|
||||
AddModuleMessage(string.Format(Localizer["Success.Module.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
|
@ -74,7 +74,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="path" HelpText="Optionally enter a url path for this page (ie. home ). If you do not provide a url path, the page name will be used." ResourceKey="UrlPath">Url Path: </Label>
|
||||
<Label Class="col-sm-3" For="path" HelpText="Optionally enter a url path for this page (ie. home ). If you do not provide a url path, the page name will be used. If the page is intended to be the root path specify '/'." ResourceKey="UrlPath">Url Path: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="path" class="form-control" @bind="@_path" />
|
||||
</div>
|
||||
@ -95,6 +95,12 @@
|
||||
<input id="title" class="form-control" @bind="@_title" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="meta" HelpText="Optionally enter meta tags (in exactly the form you want them to be included in the page output)." ResourceKey="Meta">Meta: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="meta" class="form-control" @bind="@_meta" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="theme" HelpText="Select the theme for this page" ResourceKey="Theme">Theme: </Label>
|
||||
<div class="col-sm-9">
|
||||
@ -164,6 +170,7 @@
|
||||
private List<Page> _pageList;
|
||||
private string _name;
|
||||
private string _title;
|
||||
private string _meta;
|
||||
private string _path = string.Empty;
|
||||
private string _parentid = "-1";
|
||||
private string _insert = ">>";
|
||||
@ -293,11 +300,11 @@
|
||||
page.SiteId = PageState.Page.SiteId;
|
||||
page.Name = _name;
|
||||
page.Title = _title;
|
||||
|
||||
if (string.IsNullOrEmpty(_path))
|
||||
{
|
||||
_path = _name;
|
||||
}
|
||||
|
||||
if (_path.Contains("/"))
|
||||
{
|
||||
_path = _path.Substring(_path.LastIndexOf("/") + 1);
|
||||
@ -370,6 +377,7 @@
|
||||
page.Permissions = _permissionGrid.GetPermissions();
|
||||
page.IsPersonalizable = (_ispersonalizable == null ? false : Boolean.Parse(_ispersonalizable));
|
||||
page.UserId = null;
|
||||
page.Meta = _meta;
|
||||
|
||||
page = await PageService.AddPageAsync(page);
|
||||
await PageService.UpdatePageOrderAsync(page.SiteId, page.PageId, page.ParentId);
|
||||
|
@ -3,13 +3,14 @@
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IPageService PageService
|
||||
@inject IPageModuleService PageModuleService
|
||||
@inject IThemeService ThemeService
|
||||
@inject IStringLocalizer<Edit> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<TabStrip Refresh="@_refresh">
|
||||
<TabPanel Name="Settings" ResourceKey="Settings">
|
||||
<TabPanel Name="Settings" ResourceKey="Settings" Heading=@Localizer["Settings.Heading"]>
|
||||
@if (_themeList != null)
|
||||
{
|
||||
<div class="container">
|
||||
@ -81,7 +82,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="path" HelpText="Optionally enter a url path for this page (ie. home ). If you do not provide a url path, the page name will be used." ResourceKey="UrlPath">Url Path: </Label>
|
||||
<Label Class="col-sm-3" For="path" HelpText="Optionally enter a url path for this page (ie. home ). If you do not provide a url path, the page name will be used. If the page is intended to be the root path specify '/'." ResourceKey="UrlPath">Url Path: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="path" class="form-control" @bind="@_path" maxlength="256"/>
|
||||
</div>
|
||||
@ -101,6 +102,12 @@
|
||||
<input id="title" class="form-control" @bind="@_title" maxlength="200"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="meta" HelpText="Optionally enter meta tags (in exactly the form you want them to be included in the page output)." ResourceKey="Meta">Meta: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="meta" class="form-control" @bind="@_meta" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="theme" HelpText="Select the theme for this page" ResourceKey="Theme">Theme: </Label>
|
||||
<div class="col-sm-9">
|
||||
@ -151,10 +158,27 @@
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<PermissionGrid EntityName="@EntityNames.Page" Permissions="@_permissions" @ref="_permissionGrid" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
</TabPanel>
|
||||
<TabPanel Name="PageModules" Heading="Modules" ResourceKey="PageModules">
|
||||
@if(_pageModules != null)
|
||||
{
|
||||
<Pager Items="_pageModules">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@Localizer["ModuleTitle"]</th>
|
||||
<th>@Localizer["ModuleDefinition"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="Settings" Text="Edit" ModuleId="@context.ModuleId" Security="SecurityAccessLevel.Edit" Permissions="@context.Permissions" ResourceKey="ModuleSettings" /></td>
|
||||
<td><ActionDialog Header="Delete Module" Message="Are You Sure You Wish To Delete This Module?" Action="Delete" Security="SecurityAccessLevel.Edit" Permissions="@context.Permissions" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" ResourceKey="DeleteModule" /></td>
|
||||
<td>@context.Title</td>
|
||||
<td>@context.ModuleDefinition?.Name</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
}
|
||||
</TabPanel>
|
||||
@if (_themeSettingsType != null)
|
||||
@ -178,9 +202,11 @@
|
||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private List<Page> _pageList;
|
||||
private List<Module> _pageModules;
|
||||
private int _pageId;
|
||||
private string _name;
|
||||
private string _title;
|
||||
private string _meta;
|
||||
private string _path;
|
||||
private string _currentparentid;
|
||||
private string _parentid = "-1";
|
||||
@ -206,6 +232,7 @@
|
||||
private object _themeSettings;
|
||||
private RenderFragment ThemeSettingsComponent { get; set; }
|
||||
private bool _refresh = false;
|
||||
protected Page page;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
@ -213,22 +240,31 @@
|
||||
{
|
||||
_pageList = PageState.Pages;
|
||||
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
|
||||
|
||||
_themeList = await ThemeService.GetThemesAsync();
|
||||
_themes = ThemeService.GetThemeControls(_themeList);
|
||||
|
||||
_pageId = Int32.Parse(PageState.QueryString["id"]);
|
||||
var page = PageState.Pages.FirstOrDefault(item => item.PageId == _pageId);
|
||||
page = PageState.Pages.FirstOrDefault(item => item.PageId == _pageId);
|
||||
|
||||
if (page != null)
|
||||
{
|
||||
_name = page.Name;
|
||||
_title = page.Title;
|
||||
_meta = page.Meta;
|
||||
_path = page.Path;
|
||||
_pageModules = PageState.Modules.Where(m => m.PageId == page.PageId).ToList();
|
||||
|
||||
if (string.IsNullOrEmpty(_path))
|
||||
{
|
||||
_path = "/";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_path.Contains("/"))
|
||||
{
|
||||
_path = _path.Substring(_path.LastIndexOf("/") + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (page.ParentId == null)
|
||||
{
|
||||
@ -274,6 +310,25 @@
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DeleteModule(Module module)
|
||||
{
|
||||
try
|
||||
{
|
||||
PageModule pagemodule = await PageModuleService.GetPageModuleAsync(page.PageId, module.ModuleId);
|
||||
pagemodule.IsDeleted = true;
|
||||
await PageModuleService.UpdatePageModuleAsync(pagemodule);
|
||||
await logger.LogInformation(LogFunction.Update,"Module Deleted {Title}", module.Title);
|
||||
_pageModules.RemoveAll(item => item.PageModuleId == pagemodule.PageModuleId);
|
||||
StateHasChanged();
|
||||
NavigationManager.NavigateTo(NavigationManager.Uri + "&tab=PageModules");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Deleting Module {Title} {Error}", module.Title, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Module.Delete"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async void ParentChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
@ -337,6 +392,8 @@
|
||||
private void ThemeSettings()
|
||||
{
|
||||
_themeSettingsType = null;
|
||||
if (PageState.QueryString.ContainsKey("cp")) // can only be displayed if invoked from Control Panel
|
||||
{
|
||||
var theme = _themeList.FirstOrDefault(item => item.Themes.Any(themecontrol => themecontrol.TypeName.Equals(_themetype)));
|
||||
if (theme != null && !string.IsNullOrEmpty(theme.ThemeSettingsType))
|
||||
{
|
||||
@ -353,6 +410,7 @@
|
||||
_refresh = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SavePage()
|
||||
{
|
||||
@ -370,7 +428,8 @@
|
||||
|
||||
page.Name = _name;
|
||||
page.Title = _title;
|
||||
if (string.IsNullOrEmpty(_path) && _name.ToLower() != "home")
|
||||
|
||||
if (string.IsNullOrEmpty(_path))
|
||||
{
|
||||
_path = _name;
|
||||
}
|
||||
@ -378,6 +437,7 @@
|
||||
{
|
||||
_path = _path.Substring(_path.LastIndexOf("/") + 1);
|
||||
}
|
||||
|
||||
if (_parentid == "-1")
|
||||
{
|
||||
page.ParentId = null;
|
||||
@ -441,6 +501,7 @@
|
||||
page.Permissions = _permissionGrid.GetPermissions();
|
||||
page.IsPersonalizable = (_ispersonalizable != null && Boolean.Parse(_ispersonalizable));
|
||||
page.UserId = null;
|
||||
page.Meta = _meta;
|
||||
|
||||
page = await PageService.UpdatePageAsync(page);
|
||||
await PageService.UpdatePageOrderAsync(page.SiteId, page.PageId, page.ParentId);
|
||||
|
@ -13,11 +13,13 @@
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@SharedLocalizer["Name"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.PageId.ToString())" ResourceKey="EditPage" /></td>
|
||||
<td><ActionDialog Header="Delete Page" Message="@string.Format(Localizer["Confirm.Page.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeletePage(context))" ResourceKey="DeletePage" /></td>
|
||||
<td><button type="button" class="btn btn-secondary" @onclick="@(async () => NavigationManager.NavigateTo(Browse(context)))">@Localizer["Browse"]</button></td>
|
||||
<td>@(new string('-', context.Level * 2))@(context.Name)</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
@ -42,4 +44,8 @@
|
||||
AddModuleMessage(Localizer["Error.Page.Delete"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
protected string Browse(Page page)
|
||||
{
|
||||
return string.IsNullOrEmpty(page.Url) ? NavigateUrl(page.Path) : page.Url;
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@
|
||||
<th>@Localizer["DeletedOn"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><button @onclick="@(() => RestorePage(context))" class="btn btn-info" title="Restore">Restore</button></td>
|
||||
<td><button type="button" @onclick="@(() => RestorePage(context))" class="btn btn-success" title="Restore">Restore</button></td>
|
||||
<td><ActionDialog Header="Delete Page" Message="@string.Format(Localizer["Confirm.Page.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeletePage(context))" ResourceKey="DeletePage" /></td>
|
||||
<td>@context.Name</td>
|
||||
<td>@context.DeletedBy</td>
|
||||
@ -34,9 +34,7 @@
|
||||
</Pager>
|
||||
@if (_pages.Any())
|
||||
{
|
||||
<div style="text-align:right;">
|
||||
<ActionDialog Header="Delete All Pages" Message="Are You Sure You Wish To Permanently Delete All Pages?" Action="Delete All Pages" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllPages())" ResourceKey="DeleteAllPages" />
|
||||
</div>
|
||||
<br /><ActionDialog Header="Delete All Pages" Message="Are You Sure You Wish To Permanently Delete All Pages?" Action="Delete All Pages" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllPages())" ResourceKey="DeleteAllPages" />
|
||||
}
|
||||
}
|
||||
</TabPanel>
|
||||
@ -58,7 +56,7 @@
|
||||
<th>@Localizer["DeletedOn"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><button @onclick="@(() => RestoreModule(context))" class="btn btn-info" title="Restore">@Localizer["Restore"]</button></td>
|
||||
<td><button type="button" @onclick="@(() => RestoreModule(context))" class="btn btn-success" title="Restore">@Localizer["Restore"]</button></td>
|
||||
<td><ActionDialog Header="Delete Module" Message="@string.Format(Localizer["Confirm.Module.Delete"], context.Title)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" ResourceKey="DeleteModule" /></td>
|
||||
<td>@PageState.Pages.Find(item => item.PageId == context.PageId).Name</td>
|
||||
<td>@context.Title</td>
|
||||
@ -68,9 +66,7 @@
|
||||
</Pager>
|
||||
@if (_modules.Any())
|
||||
{
|
||||
<div style="text-align:right;">
|
||||
<ActionDialog Header="Delete All Modules" Message="Are You Sure You Wish To Permanently Delete All Modules?" Action="Delete All Modules" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllModules())" ResourceKey="DeleteAllModules" />
|
||||
</div>
|
||||
<br /><ActionDialog Header="Delete All Modules" Message="Are You Sure You Wish To Permanently Delete All Modules?" Action="Delete All Modules" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllModules())" ResourceKey="DeleteAllModules" />
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,13 +27,19 @@
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="password" HelpText="Please choose a sufficiently secure password and enter it here" ResourceKey="Password"></Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="password" type="password" class="form-control" @bind="@_password" autocomplete="new-password" required />
|
||||
<div class="input-group">
|
||||
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" required />
|
||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglepassword</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="confirm" HelpText="Enter your password again to confirm it matches the value entered above" ResourceKey="Confirm"></Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="confirm" type="password" class="form-control" @bind="@_confirm" autocomplete="new-password" required />
|
||||
<div class="input-group">
|
||||
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@_confirm" autocomplete="new-password" required />
|
||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglepassword</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
@ -66,12 +72,19 @@ else
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
private string _password = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private string _confirm = string.Empty;
|
||||
private string _email = string.Empty;
|
||||
private string _displayname = string.Empty;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
|
||||
private async Task Register()
|
||||
{
|
||||
validated = true;
|
||||
@ -90,9 +103,10 @@ else
|
||||
{
|
||||
SiteId = PageState.Site.SiteId,
|
||||
Username = _username,
|
||||
DisplayName = (_displayname == string.Empty ? _username : _displayname),
|
||||
Password = _password,
|
||||
Email = _email,
|
||||
Password = _password
|
||||
DisplayName = (_displayname == string.Empty ? _username : _displayname),
|
||||
PhotoFileId = null
|
||||
};
|
||||
user = await UserService.AddUserAsync(user);
|
||||
|
||||
@ -133,4 +147,18 @@ else
|
||||
{
|
||||
NavigationManager.NavigateTo(NavigateUrl(string.Empty));
|
||||
}
|
||||
|
||||
private void TogglePassword()
|
||||
{
|
||||
if (_passwordtype == "password")
|
||||
{
|
||||
_passwordtype = "text";
|
||||
_togglepassword = SharedLocalizer["HidePassword"];
|
||||
}
|
||||
else
|
||||
{
|
||||
_passwordtype = "password";
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,21 +7,34 @@
|
||||
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<div class="container">
|
||||
<div class="form-group">
|
||||
<label for="Username" class="control-label">@SharedLocalizer["Username"] </label>
|
||||
<input type="text" class="form-control" placeholder="Username" @bind="@_username" readonly id="Username" />
|
||||
<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>
|
||||
<div class="col-sm-9">
|
||||
<input id="username" type="text" class="form-control" @bind="@_username" readonly />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="Password" class="control-label">@SharedLocalizer["Password"] </label>
|
||||
<input type="password" class="form-control" placeholder="Password" @bind="@_password" id="Password" required />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="Confirm" class="control-label">@Localizer["Password.Confirm"] </label>
|
||||
<input type="password" class="form-control" placeholder="Password" @bind="@_confirm" id="Confirm" required />
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="password" HelpText="The new password. It must satisfy complexity rules for the site." ResourceKey="Password">Password: </Label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" required />
|
||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglepassword</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="confirm" HelpText="Enter the password again. It must exactly match the password entered above." ResourceKey="Confirm">Confirm: </Label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@_confirm" autocomplete="new-password" required />
|
||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglepassword</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<button type="button" class="btn btn-primary" @onclick="Reset">@Localizer["Password.Reset"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@code {
|
||||
@ -29,19 +42,24 @@
|
||||
private bool validated = false;
|
||||
private string _username = string.Empty;
|
||||
private string _password = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private string _confirm = string.Empty;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
||||
|
||||
protected override void OnInitialized()
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
|
||||
if (PageState.QueryString.ContainsKey("name") && PageState.QueryString.ContainsKey("token"))
|
||||
{
|
||||
_username = PageState.QueryString["name"];
|
||||
}
|
||||
else
|
||||
{
|
||||
NavigationManager.NavigateTo(NavigateUrl(string.Empty));
|
||||
await logger.LogError(LogFunction.Security, "Invalid Attempt To Access User Password Reset");
|
||||
NavigationManager.NavigateTo(NavigateUrl("")); // home page
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,4 +120,18 @@
|
||||
{
|
||||
NavigationManager.NavigateTo(NavigateUrl(string.Empty));
|
||||
}
|
||||
|
||||
private void TogglePassword()
|
||||
{
|
||||
if (_passwordtype == "password")
|
||||
{
|
||||
_passwordtype = "text";
|
||||
_togglepassword = SharedLocalizer["HidePassword"];
|
||||
}
|
||||
else
|
||||
{
|
||||
_passwordtype = "password";
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,13 +35,13 @@ else
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="effectiveDate" HelpText="The date that this role assignment is active" ResourceKey="EffectiveDate">Effective Date: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input type="date" id="effectiveDate" class="form-control" @bind="@effectivedate" required />
|
||||
<input type="date" id="effectiveDate" class="form-control" @bind="@effectivedate" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="expiryDate" HelpText="The date that this role assignment expires" ResourceKey="ExpiryDate">Expiry Date: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input type="date" id="expiryDate" class="form-control" @bind="@expirydate" required />
|
||||
<input type="date" id="expiryDate" class="form-control" @bind="@expirydate" />
|
||||
</div>
|
||||
</div>
|
||||
<br /><br />
|
||||
@ -53,12 +53,14 @@ else
|
||||
<Pager Items="@userroles">
|
||||
<Header>
|
||||
<th>@Localizer["Users"]</th>
|
||||
<th>@SharedLocalizer["Username"]</th>
|
||||
<th>@Localizer["Effective"]</th>
|
||||
<th>@Localizer["Expiry"]</th>
|
||||
<th> </th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td>@context.User.DisplayName</td>
|
||||
<td>@context.User.Username</td>
|
||||
<td>@context.EffectiveDate</td>
|
||||
<td>@context.ExpiryDate</td>
|
||||
<td>
|
||||
@ -93,11 +95,7 @@ else
|
||||
roleid = Int32.Parse(PageState.QueryString["id"]);
|
||||
Role role = await RoleService.GetRoleAsync(roleid);
|
||||
name = role.Name;
|
||||
users = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId);
|
||||
users = users
|
||||
.Where(u => u.Role.Name == RoleNames.Registered)
|
||||
.OrderBy(u => u.User.DisplayName)
|
||||
.ToList();
|
||||
users = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Registered);
|
||||
await GetUserRoles();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -111,8 +109,7 @@ else
|
||||
{
|
||||
try
|
||||
{
|
||||
userroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId);
|
||||
userroles = userroles.Where(item => item.RoleId == roleid).ToList();
|
||||
userroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, name);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -1,5 +1,6 @@
|
||||
@namespace Oqtane.Modules.Admin.Site
|
||||
@inherits ModuleBase
|
||||
@using System.Text.RegularExpressions
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject ISiteService SiteService
|
||||
@inject ITenantService TenantService
|
||||
@ -21,40 +22,6 @@
|
||||
<input id="name" class="form-control" @bind="@_name" maxlength="200" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="alias" HelpText="The aliases for the site. An alias can be a domain name (www.site.com) or a virtual folder (ie. www.site.com/folder). If a site has multiple aliases they should be separated by commas." ResourceKey="Aliases">Aliases: </Label>
|
||||
<div class="col-sm-9">
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
<textarea id="alias" class="form-control" @bind="@_urls" rows="3" required></textarea>
|
||||
}
|
||||
else
|
||||
{
|
||||
<textarea id="alias" class="form-control" @bind="@_urls" rows="3" readonly></textarea>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="allowRegister" HelpText="Do you want the users to be able to register for an account on the site" ResourceKey="AllowRegistration">Allow User Registration? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="allowRegister" class="form-select" @bind="@_allowregistration" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="isDeleted" HelpText="Is this site deleted?" ResourceKey="IsDeleted">Is Deleted? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="isDeleted" class="form-select" @bind="@_isdeleted" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Section Name="Appearance" Heading="Appearance" ResourceKey="Appearance">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="logo" HelpText="Specify a logo for the site" ResourceKey="Logo">Logo: </Label>
|
||||
<div class="col-sm-9">
|
||||
@ -104,9 +71,16 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="isDeleted" HelpText="Is this site deleted?" ResourceKey="IsDeleted">Deleted? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="isDeleted" class="form-select" @bind="@_isdeleted" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
<Section Name="SMTP" Heading="SMTP Settings" ResourceKey="SMTPSettings">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
@ -146,7 +120,10 @@
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="password" HelpText="Enter the password for your SMTP account" ResourceKey="SmtpPassword">Password: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="password" type="password" class="form-control" @bind="@_smtppassword" />
|
||||
<div class="input-group">
|
||||
<input id="password" type="@_smtppasswordtype" class="form-control" @bind="@_smtppassword" />
|
||||
<button type="button" class="btn btn-secondary" @onclick="@ToggleSMTPPassword">@_togglesmtppassword</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
@ -155,12 +132,15 @@
|
||||
<input id="sender" class="form-control" @bind="@_smtpsender" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="retention" HelpText="Number of days of notifications to retain" ResourceKey="Retention">Retention (Days): </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="retention" class="form-control" @bind="@_retention" />
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-secondary" @onclick="SendEmail">@Localizer["Smtp.TestConfig"]</button>
|
||||
<br /><br />
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</Section>
|
||||
<Section Name="PWA" Heading="Progressive Web Application Settings" ResourceKey="PWASettings">
|
||||
<div class="container">
|
||||
@ -187,8 +167,51 @@
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
@if (_aliases != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
<Section Name="Aliases" Heading="Aliases" ResourceKey="Aliases">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="alias" HelpText="The aliases for the site. An alias can be a domain name (www.site.com) or a virtual folder (ie. www.site.com/folder). If a site has multiple aliases they should be separated by commas." ResourceKey="Aliases">Aliases: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="alias" class="form-control" @bind="@_urls" rows="3" required></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="defaultalias" HelpText="The default alias for the site. Requests for non-default aliases will be redirected to the default alias." ResourceKey="DefaultAlias">Default Alias: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="defaultalias" class="form-select" @bind="@_defaultalias" required>
|
||||
@foreach (string name in _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(sValue => sValue.Trim()).ToArray())
|
||||
{
|
||||
<option value="@name">@name</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
<Section Name="Hosting" Heading="Hosting Model" ResourceKey="Hosting">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="runtime" HelpText="The Blazor runtime hosting model" ResourceKey="Runtime">Runtime: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="runtime" class="form-select" @bind="@_runtime" required>
|
||||
<option value="Server">@SharedLocalizer["BlazorServer"]</option>
|
||||
<option value="WebAssembly">@SharedLocalizer["BlazorWebAssembly"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="prerender" HelpText="Specifies if the site should be prerendered (for search crawlers, etc...)" ResourceKey="Prerender">Prerender? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="prerender" class="form-select" @bind="@_prerender" required>
|
||||
<option value="Prerendered">@SharedLocalizer["Yes"]</option>
|
||||
<option value="">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
<Section Name="TenantInformation" Heading="Tenant Information" ResourceKey="TenantInformation">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
@ -229,8 +252,11 @@
|
||||
private List<ThemeControl> _themes = new List<ThemeControl>();
|
||||
private List<ThemeControl> _containers = new List<ThemeControl>();
|
||||
private string _name = string.Empty;
|
||||
private List<Alias> _aliasList;
|
||||
private List<Alias> _aliases;
|
||||
private string _defaultalias = string.Empty;
|
||||
private string _urls = string.Empty;
|
||||
private string _runtime = "";
|
||||
private string _prerender = "";
|
||||
private int _logofileid = -1;
|
||||
private FileManager _logofilemanager;
|
||||
private int _faviconfileid = -1;
|
||||
@ -238,13 +264,15 @@
|
||||
private string _themetype = "-";
|
||||
private string _containertype = "-";
|
||||
private string _admincontainertype = "-";
|
||||
private string _allowregistration;
|
||||
private string _smtphost = string.Empty;
|
||||
private string _smtpport = string.Empty;
|
||||
private string _smtpssl = "False";
|
||||
private string _smtpusername = string.Empty;
|
||||
private string _smtppassword = string.Empty;
|
||||
private string _smtppasswordtype = "password";
|
||||
private string _togglesmtppassword = string.Empty;
|
||||
private string _smtpsender = string.Empty;
|
||||
private string _retention = string.Empty;
|
||||
private string _pwaisenabled;
|
||||
private int _pwaappiconfileid = -1;
|
||||
private FileManager _pwaappiconfilemanager;
|
||||
@ -272,18 +300,13 @@
|
||||
if (site != null)
|
||||
{
|
||||
_name = site.Name;
|
||||
_allowregistration = site.AllowRegistration.ToString();
|
||||
_runtime = site.Runtime;
|
||||
_prerender = site.RenderMode.Replace(_runtime, "");
|
||||
_isdeleted = site.IsDeleted.ToString();
|
||||
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
_aliasList = await AliasService.GetAliasesAsync();
|
||||
foreach (Alias alias in _aliasList.Where(item => item.SiteId == site.SiteId && item.TenantId == site.TenantId).ToList())
|
||||
{
|
||||
_urls += alias.Name + ",";
|
||||
}
|
||||
_urls = _urls.Substring(0, _urls.Length - 1);
|
||||
|
||||
await GetAliases();
|
||||
}
|
||||
|
||||
if (site.LogoFileId != null)
|
||||
@ -302,35 +325,25 @@
|
||||
_containertype = (!string.IsNullOrEmpty(site.DefaultContainerType)) ? site.DefaultContainerType : Constants.DefaultContainer;
|
||||
_admincontainertype = (!string.IsNullOrEmpty(site.AdminContainerType)) ? site.AdminContainerType : Constants.DefaultAdminContainer;
|
||||
|
||||
_pwaisenabled = site.PwaIsEnabled.ToString();
|
||||
if (site.PwaAppIconFileId != null)
|
||||
{
|
||||
_pwaappiconfileid = site.PwaAppIconFileId.Value;
|
||||
}
|
||||
if (site.PwaSplashIconFileId != null)
|
||||
{
|
||||
_pwasplashiconfileid = site.PwaSplashIconFileId.Value;
|
||||
}
|
||||
|
||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||
_smtphost = SettingService.GetSetting(settings, "SMTPHost", string.Empty);
|
||||
_smtpport = SettingService.GetSetting(settings, "SMTPPort", string.Empty);
|
||||
_smtpssl = SettingService.GetSetting(settings, "SMTPSSL", "False");
|
||||
_smtpusername = SettingService.GetSetting(settings, "SMTPUsername", string.Empty);
|
||||
_smtppassword = SettingService.GetSetting(settings, "SMTPPassword", string.Empty);
|
||||
_togglesmtppassword = SharedLocalizer["ShowPassword"];
|
||||
_smtpsender = SettingService.GetSetting(settings, "SMTPSender", string.Empty);
|
||||
|
||||
_pwaisenabled = site.PwaIsEnabled.ToString();
|
||||
|
||||
if (site.PwaAppIconFileId != null)
|
||||
{
|
||||
_pwaappiconfileid = site.PwaAppIconFileId.Value;
|
||||
}
|
||||
|
||||
if (site.PwaSplashIconFileId != null)
|
||||
{
|
||||
_pwasplashiconfileid = site.PwaSplashIconFileId.Value;
|
||||
}
|
||||
|
||||
_pwaisenabled = site.PwaIsEnabled.ToString();
|
||||
if (site.PwaAppIconFileId != null)
|
||||
{
|
||||
_pwaappiconfileid = site.PwaAppIconFileId.Value;
|
||||
}
|
||||
if (site.PwaSplashIconFileId != null)
|
||||
{
|
||||
_pwasplashiconfileid = site.PwaSplashIconFileId.Value;
|
||||
}
|
||||
_retention = SettingService.GetSetting(settings, "NotificationRetention", "30");
|
||||
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
@ -394,18 +407,22 @@
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_name != string.Empty && _urls != string.Empty && _themetype != "-" && _containertype != "-")
|
||||
if (_name != string.Empty && _themetype != "-" && _containertype != "-")
|
||||
{
|
||||
var unique = true;
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
foreach (string name in _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
_urls = Regex.Replace(_urls, @"\r\n?|\n", ","); // convert line breaks to commas
|
||||
var aliases = await AliasService.GetAliasesAsync();
|
||||
foreach (string name in _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(sValue => sValue.Trim()).ToArray())
|
||||
{
|
||||
if (_aliasList.Exists(item => item.Name == name && item.SiteId != PageState.Alias.SiteId && item.TenantId != PageState.Alias.TenantId))
|
||||
var alias = aliases.Where(item => item.Name == name).FirstOrDefault();
|
||||
if (alias != null && unique)
|
||||
{
|
||||
unique = false;
|
||||
unique = (alias.TenantId == PageState.Site.TenantId && alias.SiteId == PageState.Site.SiteId);
|
||||
}
|
||||
}
|
||||
if (unique && string.IsNullOrEmpty(_defaultalias)) unique = false;
|
||||
}
|
||||
|
||||
if (unique)
|
||||
@ -413,10 +430,19 @@
|
||||
var site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
||||
if (site != null)
|
||||
{
|
||||
bool refresh = (site.DefaultThemeType != _themetype || site.DefaultContainerType != _containertype);
|
||||
bool refresh = false;
|
||||
bool reload = false;
|
||||
|
||||
site.Name = _name;
|
||||
site.AllowRegistration = (_allowregistration == null ? true : Boolean.Parse(_allowregistration));
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
if (site.Runtime != _runtime || site.RenderMode != _runtime + _prerender)
|
||||
{
|
||||
site.Runtime = _runtime;
|
||||
site.RenderMode = _runtime + _prerender;
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
}
|
||||
site.IsDeleted = (_isdeleted == null ? true : Boolean.Parse(_isdeleted));
|
||||
|
||||
site.LogoFileId = null;
|
||||
@ -425,44 +451,64 @@
|
||||
{
|
||||
site.LogoFileId = logofileid;
|
||||
}
|
||||
var faviconFieldId = _faviconfilemanager.GetFileId();
|
||||
if (faviconFieldId != -1)
|
||||
int? faviconFieldId = _faviconfilemanager.GetFileId();
|
||||
if (faviconFieldId == -1) faviconFieldId = null;
|
||||
if (site.FaviconFileId != faviconFieldId)
|
||||
{
|
||||
site.FaviconFileId = faviconFieldId;
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
if (site.DefaultThemeType != _themetype)
|
||||
{
|
||||
site.DefaultThemeType = _themetype;
|
||||
refresh = true; // needs to be refreshed on client
|
||||
}
|
||||
if (site.DefaultContainerType != _containertype)
|
||||
{
|
||||
site.DefaultContainerType = _containertype;
|
||||
refresh = true; // needs to be refreshed on client
|
||||
}
|
||||
site.AdminContainerType = _admincontainertype;
|
||||
|
||||
site.PwaIsEnabled = (_pwaisenabled == null ? true : Boolean.Parse(_pwaisenabled));
|
||||
var pwaappiconfileid = _pwaappiconfilemanager.GetFileId();
|
||||
if (pwaappiconfileid != -1)
|
||||
if (site.PwaIsEnabled.ToString() != _pwaisenabled)
|
||||
{
|
||||
site.PwaIsEnabled = Boolean.Parse(_pwaisenabled);
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
int? pwaappiconfileid = _pwaappiconfilemanager.GetFileId();
|
||||
if (pwaappiconfileid == -1) pwaappiconfileid = null;
|
||||
if (site.PwaAppIconFileId != pwaappiconfileid)
|
||||
{
|
||||
site.PwaAppIconFileId = pwaappiconfileid;
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
var pwasplashiconfileid = _pwasplashiconfilemanager.GetFileId();
|
||||
if (pwasplashiconfileid != -1)
|
||||
int? pwasplashiconfileid = _pwasplashiconfilemanager.GetFileId();
|
||||
if (pwasplashiconfileid == -1) pwasplashiconfileid = null;
|
||||
if (site.PwaSplashIconFileId != pwasplashiconfileid)
|
||||
{
|
||||
site.PwaSplashIconFileId = pwasplashiconfileid;
|
||||
reload = true; // needs to be reloaded on server
|
||||
}
|
||||
|
||||
site = await SiteService.UpdateSiteAsync(site);
|
||||
|
||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||
SettingService.SetSetting(settings, "SMTPHost", _smtphost);
|
||||
SettingService.SetSetting(settings, "SMTPPort", _smtpport);
|
||||
SettingService.SetSetting(settings, "SMTPSSL", _smtpssl);
|
||||
SettingService.SetSetting(settings, "SMTPUsername", _smtpusername);
|
||||
SettingService.SetSetting(settings, "SMTPPassword", _smtppassword);
|
||||
SettingService.SetSetting(settings, "SMTPSender", _smtpsender);
|
||||
settings = SettingService.SetSetting(settings, "SMTPHost", _smtphost, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPPort", _smtpport, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
||||
settings = SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
||||
settings = SettingService.SetSetting(settings, "NotificationRetention", _retention, true);
|
||||
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
|
||||
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
var names = _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (Alias alias in _aliasList.Where(item => item.SiteId == site.SiteId && item.TenantId == site.TenantId).ToList())
|
||||
var names = _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(sValue => sValue.Trim()).ToArray();
|
||||
foreach (Alias alias in _aliases)
|
||||
{
|
||||
if (!names.Contains(alias.Name))
|
||||
if (!names.Contains(alias.Name.Trim()))
|
||||
{
|
||||
await AliasService.DeleteAliasAsync(alias.AliasId);
|
||||
}
|
||||
@ -470,30 +516,43 @@
|
||||
|
||||
foreach (string name in names)
|
||||
{
|
||||
if (!_aliasList.Exists(item => item.Name == name))
|
||||
var alias = _aliases.Find(item => item.Name.Trim() == name);
|
||||
if (alias == null)
|
||||
{
|
||||
Alias alias = new Alias();
|
||||
alias = new Alias();
|
||||
alias.Name = name;
|
||||
alias.TenantId = site.TenantId;
|
||||
alias.SiteId = site.SiteId;
|
||||
alias.IsDefault = (name == _defaultalias);
|
||||
await AliasService.AddAliasAsync(alias);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (alias.Name != name || alias.IsDefault != (alias.Name.Trim() == _defaultalias))
|
||||
{
|
||||
alias.Name = name;
|
||||
alias.IsDefault = (name == _defaultalias);
|
||||
await AliasService.UpdateAliasAsync(alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
await GetAliases();
|
||||
}
|
||||
|
||||
await logger.LogInformation("Site Settings Saved {Site}", site);
|
||||
|
||||
if (refresh)
|
||||
if (refresh || reload)
|
||||
{
|
||||
NavigationManager.NavigateTo(NavigateUrl()); // refresh to show new theme or container
|
||||
NavigationManager.NavigateTo(NavigateUrl(true), reload); // refresh/reload
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Success.Settings.SaveSite"], MessageType.Success);
|
||||
await interop.ScrollTo(0, 0, "smooth");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
else // deuplicate alias or default alias not specified
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Aliases.Taken"], MessageType.Warning);
|
||||
}
|
||||
@ -552,17 +611,19 @@
|
||||
try
|
||||
{
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
SettingService.SetSetting(settings, "SMTPHost", _smtphost);
|
||||
SettingService.SetSetting(settings, "SMTPPort", _smtpport);
|
||||
SettingService.SetSetting(settings, "SMTPSSL", _smtpssl);
|
||||
SettingService.SetSetting(settings, "SMTPUsername", _smtpusername);
|
||||
SettingService.SetSetting(settings, "SMTPPassword", _smtppassword);
|
||||
SettingService.SetSetting(settings, "SMTPSender", _smtpsender);
|
||||
SettingService.SetSetting(settings, "SMTPHost", _smtphost, true);
|
||||
SettingService.SetSetting(settings, "SMTPPort", _smtpport, true);
|
||||
SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, true);
|
||||
SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
||||
SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
||||
SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
||||
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
||||
await logger.LogInformation("Site SMTP Settings Saved");
|
||||
|
||||
await NotificationService.AddNotificationAsync(new Notification(PageState.Site.SiteId, PageState.User.DisplayName, PageState.User.Email, PageState.User.DisplayName, PageState.User.Email, PageState.Site.Name + " SMTP Configuration Test", "SMTP Server Is Configured Correctly."));
|
||||
await NotificationService.AddNotificationAsync(new Notification(PageState.Site.SiteId, PageState.User, PageState.Site.Name + " SMTP Configuration Test", "SMTP Server Is Configured Correctly."));
|
||||
AddModuleMessage(Localizer["Info.Smtp.SaveSettings"], MessageType.Info);
|
||||
var interop = new Interop(JSRuntime);
|
||||
await interop.ScrollTo(0, 0, "smooth");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -572,7 +633,35 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.required.Smtp"], MessageType.Warning);
|
||||
AddModuleMessage(Localizer["Message.Required.Smtp"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GetAliases()
|
||||
{
|
||||
_urls = string.Empty;
|
||||
_defaultalias = string.Empty;
|
||||
_aliases = await AliasService.GetAliasesAsync();
|
||||
_aliases = _aliases.Where(item => item.SiteId == PageState.Site.SiteId && item.TenantId == PageState.Site.TenantId).OrderBy(item => item.AliasId).ToList();
|
||||
foreach (Alias alias in _aliases)
|
||||
{
|
||||
_urls += (_urls == string.Empty) ? alias.Name.Trim() : ", " + alias.Name.Trim();
|
||||
if (alias.IsDefault && string.IsNullOrEmpty(_defaultalias)) _defaultalias = alias.Name.Trim();
|
||||
}
|
||||
if (string.IsNullOrEmpty(_defaultalias)) _defaultalias = _aliases.First().Name.Trim();
|
||||
}
|
||||
|
||||
private void ToggleSMTPPassword()
|
||||
{
|
||||
if (_smtppasswordtype == "password")
|
||||
{
|
||||
_smtppasswordtype = "text";
|
||||
_togglesmtppassword = SharedLocalizer["HidePassword"];
|
||||
}
|
||||
else
|
||||
{
|
||||
_smtppasswordtype = "password";
|
||||
_togglesmtppassword = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
@namespace Oqtane.Modules.Admin.Sites
|
||||
@using Oqtane.Interfaces
|
||||
@using System.Text.RegularExpressions
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject ITenantService TenantService
|
||||
@ -82,6 +83,24 @@ else
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="runtime" HelpText="The runtime hosting model" ResourceKey="Runtime">Runtime: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="runtime" class="form-select" @bind="@_runtime" required>
|
||||
<option value="Server">@SharedLocalizer["BlazorServer"]</option>
|
||||
<option value="WebAssembly">@SharedLocalizer["BlazorWebAssembly"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="prerender" HelpText="Specifies if the site should be prerendered (for search crawlers, etc...)" ResourceKey="Prerender">Prerender? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="prerender" class="form-select" @bind="@_prerender" required>
|
||||
<option value="Prerendered">@SharedLocalizer["Yes"]</option>
|
||||
<option value="">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="tenant" HelpText="Select the tenant for the site" ResourceKey="Tenant">Tenant: </Label>
|
||||
<div class="col-sm-9">
|
||||
@ -129,15 +148,15 @@ else
|
||||
@DatabaseConfigComponent;
|
||||
}
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="hostUsername" HelpText="Enter the username of the host for this site" ResourceKey="HostUsername">Host Username:</Label>
|
||||
<Label Class="col-sm-3" For="hostUsername" HelpText="Enter the username of an existing host user" ResourceKey="HostUsername">Host Username:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="hostUsername" class="form-control" @bind="@_hostUserName" readonly />
|
||||
<input id="hostUsername" class="form-control" @bind="@_hostusername" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="hostPassword" HelpText="Enter the password for the host of this site" ResourceKey="HostPassword">Host Password:</Label>
|
||||
<Label Class="col-sm-3" For="hostPassword" HelpText="Enter the password of an existing host user" ResourceKey="HostPassword">Host Password:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="hostPassword" type="password" class="form-control" @bind="@_hostpassword" required />
|
||||
<input id="hostPassword" type="password" class="form-control" @bind="@_hostpassword" autocomplete="new-password" required />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@ -168,7 +187,7 @@ else
|
||||
|
||||
private string _tenantName = string.Empty;
|
||||
|
||||
private string _hostUserName = UserNames.Host;
|
||||
private string _hostusername = string.Empty;
|
||||
private string _hostpassword = string.Empty;
|
||||
|
||||
private string _name = string.Empty;
|
||||
@ -177,6 +196,8 @@ else
|
||||
private string _containertype = "-";
|
||||
private string _admincontainertype = "";
|
||||
private string _sitetemplatetype = "-";
|
||||
private string _runtime = "Server";
|
||||
private string _prerender = "Prerendered";
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
@ -262,6 +283,7 @@ else
|
||||
{
|
||||
if (_tenantid != "-" && _name != string.Empty && _urls != string.Empty && _themetype != "-" && _containertype != "-" && _sitetemplatetype != "-")
|
||||
{
|
||||
_urls = Regex.Replace(_urls, @"\r\n?|\n", ",");
|
||||
var duplicates = new List<string>();
|
||||
var aliases = await AliasService.GetAliasesAsync();
|
||||
foreach (string name in _urls.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
@ -283,9 +305,10 @@ else
|
||||
// validate host credentials
|
||||
var user = new User();
|
||||
user.SiteId = PageState.Site.SiteId;
|
||||
user.Username = UserNames.Host;
|
||||
user.Username = _hostusername;
|
||||
user.Password = _hostpassword;
|
||||
user = await UserService.LoginUserAsync(user, false, false);
|
||||
user.LastIPAddress = PageState.RemoteIPAddress;
|
||||
user = await UserService.LoginUserAsync(user);
|
||||
if (user.IsAuthenticated)
|
||||
{
|
||||
var connectionString = String.Empty;
|
||||
@ -300,8 +323,9 @@ else
|
||||
config.TenantName = _tenantName;
|
||||
config.DatabaseType = database.DBType;
|
||||
config.ConnectionString = connectionString;
|
||||
config.HostEmail = user.Email;
|
||||
config.HostUsername = _hostusername;
|
||||
config.HostPassword = _hostpassword;
|
||||
config.HostEmail = user.Email;
|
||||
config.HostName = user.DisplayName;
|
||||
config.IsNewTenant = true;
|
||||
}
|
||||
@ -340,6 +364,8 @@ else
|
||||
config.DefaultContainer = _containertype;
|
||||
config.DefaultAdminContainer = _admincontainertype;
|
||||
config.SiteTemplate = _sitetemplatetype;
|
||||
config.Runtime = _runtime;
|
||||
config.RenderMode = _runtime + _prerender;
|
||||
|
||||
ShowProgressIndicator();
|
||||
|
||||
@ -347,8 +373,7 @@ else
|
||||
if (installation.Success)
|
||||
{
|
||||
var aliasname = config.Aliases.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)[0];
|
||||
var uri = new Uri(NavigationManager.Uri);
|
||||
NavigationManager.NavigateTo(uri.Scheme + "://" + aliasname, true);
|
||||
NavigationManager.NavigateTo(PageState.Uri.Scheme + "://" + aliasname, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -30,20 +30,16 @@ else
|
||||
|
||||
@code {
|
||||
private List<Alias> _sites;
|
||||
private string _scheme;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
var uri = new Uri(NavigationManager.Uri);
|
||||
_scheme = uri.Scheme + "://";
|
||||
|
||||
var aliases = await AliasService.GetAliasesAsync();
|
||||
_sites = new List<Alias>();
|
||||
foreach (Alias alias in aliases)
|
||||
{
|
||||
if (!_sites.Exists(item => item.TenantId == alias.TenantId && item.SiteId == alias.SiteId))
|
||||
if (alias.IsDefault && !_sites.Exists(item => item.TenantId == alias.TenantId && item.SiteId == alias.SiteId))
|
||||
{
|
||||
_sites.Add(alias);
|
||||
}
|
||||
@ -52,11 +48,11 @@ else
|
||||
|
||||
private void Edit(string name)
|
||||
{
|
||||
NavigationManager.NavigateTo(_scheme + name + "/admin/site/?reload");
|
||||
NavigationManager.NavigateTo(PageState.Uri.Scheme + "://" + name + "/admin/site", true);
|
||||
}
|
||||
|
||||
private void Browse(string name)
|
||||
{
|
||||
NavigationManager.NavigateTo(_scheme + name + "/?reload");
|
||||
NavigationManager.NavigateTo(PageState.Uri.Scheme + "://" + name, true);
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,6 @@ else
|
||||
{
|
||||
@if (_results.Count > 0)
|
||||
{
|
||||
<div class="table-responsive">
|
||||
<Pager Class="table table-bordered" Items="@_results">
|
||||
<Header>
|
||||
@foreach (KeyValuePair<string, string> kvp in _results.First())
|
||||
@ -72,7 +71,6 @@ else
|
||||
}
|
||||
</Row>
|
||||
</Pager>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -27,17 +27,47 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="serverpath" HelpText="Server Path" ResourceKey="ServerPath">Server Path: </Label>
|
||||
<Label Class="col-sm-3" For="machinename" HelpText="Machine Name" ResourceKey="MachineName">Machine Name: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="serverpath" class="form-control" @bind="@_serverpath" readonly />
|
||||
<input id="machinename" class="form-control" @bind="@_machinename" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="servertime" HelpText="Server Time" ResourceKey="ServerTime">Server Time: </Label>
|
||||
<Label Class="col-sm-3" For="ipaddress" HelpText="Server IP Address" ResourceKey="IPAddress">IP Address: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="ipaddress" class="form-control" @bind="@_ipaddress" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="contentrootpath" HelpText="Root Path" ResourceKey="ContentRootPath">Root Path: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="contentrootpath" class="form-control" @bind="@_contentrootpath" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="webrootpath" HelpText="Web Path" ResourceKey="WebRootPath">Web Path: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="webrootpath" class="form-control" @bind="@_webrootpath" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="servertime" HelpText="Server Date/Time (in UTC)" ResourceKey="ServerTime">Server Date/Time: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="servertime" class="form-control" @bind="@_servertime" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="tickcount" HelpText="Amount Of Time The Service Has Been Available And Operational" ResourceKey="TickCount">Service Uptime: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="tickcount" class="form-control" @bind="@_tickcount" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="workingset" HelpText="Memory Allocation Of Service (in MB)" ResourceKey="WorkingSet">Memory Allocation: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="workingset" class="form-control" @bind="@_workingset" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="installationid" HelpText="The Unique Identifier For Your Installation" ResourceKey="InstallationId">Installation ID: </Label>
|
||||
<div class="col-sm-9">
|
||||
@ -50,24 +80,6 @@
|
||||
</TabPanel>
|
||||
<TabPanel Name="Options" Heading="Options" ResourceKey="Options">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="runtime" HelpText="Blazor Runtime (Server or WebAssembly)" ResourceKey="BlazorRuntime">Blazor Runtime: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="runtime" class="form-select" @bind="@_runtime">
|
||||
<option value="Server">@Localizer["Server"]</option>
|
||||
<option value="WebAssembly">@Localizer["WebAssembly"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="rendermode" HelpText="Blazor Server Render Mode" ResourceKey="RenderMode">Render Mode: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="rendermode" class="form-select" @bind="@_rendermode">
|
||||
<option value="Server">@Localizer["Server"]</option>
|
||||
<option value="ServerPrerendered">@Localizer["ServerPrerendered"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="detailederrors" HelpText="Specify If Detailed Errors Are Enabled For Blazor. This Option Should Not Not Be Enabled In Production." ResourceKey="DetailedErrors">Detailed Errors? </Label>
|
||||
<div class="col-sm-9">
|
||||
@ -87,6 +99,21 @@
|
||||
<option value="Warning">@Localizer["Warning"]</option>
|
||||
<option value="Error">@Localizer["Error"]</option>
|
||||
<option value="Critical">@Localizer["Critical"]</option>
|
||||
<option value="None">@Localizer["None"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="notificationlevel" HelpText="The Minimum Logging Level For Which Notifications Should Be Sent To Host Users." ResourceKey="NotificationLevel">Notification Level: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="notificationlevel" class="form-select" @bind="@_notificationlevel">
|
||||
<option value="Trace">@Localizer["Trace"]</option>
|
||||
<option value="Debug">@Localizer["Debug"]</option>
|
||||
<option value="Information">@Localizer["Information"]</option>
|
||||
<option value="Warning">@Localizer["Warning"]</option>
|
||||
<option value="Error">@Localizer["Error"]</option>
|
||||
<option value="Critical">@Localizer["Critical"]</option>
|
||||
<option value="None">@Localizer["None"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@ -122,14 +149,18 @@
|
||||
private string _version = string.Empty;
|
||||
private string _clrversion = string.Empty;
|
||||
private string _osversion = string.Empty;
|
||||
private string _serverpath = string.Empty;
|
||||
private string _machinename = string.Empty;
|
||||
private string _ipaddress = string.Empty;
|
||||
private string _contentrootpath = string.Empty;
|
||||
private string _webrootpath = string.Empty;
|
||||
private string _servertime = string.Empty;
|
||||
private string _tickcount = string.Empty;
|
||||
private string _workingset = string.Empty;
|
||||
private string _installationid = string.Empty;
|
||||
|
||||
private string _runtime = string.Empty;
|
||||
private string _rendermode = string.Empty;
|
||||
private string _detailederrors = string.Empty;
|
||||
private string _logginglevel = string.Empty;
|
||||
private string _notificationlevel = string.Empty;
|
||||
private string _swagger = string.Empty;
|
||||
private string _packageservice = string.Empty;
|
||||
|
||||
@ -137,21 +168,29 @@
|
||||
{
|
||||
_version = Constants.Version;
|
||||
|
||||
Dictionary<string, string> systeminfo = await SystemService.GetSystemInfoAsync();
|
||||
Dictionary<string, object> systeminfo = await SystemService.GetSystemInfoAsync("environment");
|
||||
if (systeminfo != null)
|
||||
{
|
||||
_clrversion = systeminfo["clrversion"];
|
||||
_osversion = systeminfo["osversion"];
|
||||
_serverpath = systeminfo["serverpath"];
|
||||
_servertime = systeminfo["servertime"];
|
||||
_installationid = systeminfo["installationid"];
|
||||
_clrversion = systeminfo["CLRVersion"].ToString();
|
||||
_osversion = systeminfo["OSVersion"].ToString();
|
||||
_machinename = systeminfo["MachineName"].ToString();
|
||||
_ipaddress = systeminfo["IPAddress"].ToString();
|
||||
_contentrootpath = systeminfo["ContentRootPath"].ToString();
|
||||
_webrootpath = systeminfo["WebRootPath"].ToString();
|
||||
_servertime = systeminfo["ServerTime"].ToString() + " UTC";
|
||||
_tickcount = TimeSpan.FromMilliseconds(Convert.ToInt64(systeminfo["TickCount"].ToString())).ToString();
|
||||
_workingset = (Convert.ToInt64(systeminfo["WorkingSet"].ToString()) / 1000000).ToString() + " MB";
|
||||
}
|
||||
|
||||
_runtime = systeminfo["runtime"];
|
||||
_rendermode = systeminfo["rendermode"];
|
||||
_detailederrors = systeminfo["detailederrors"];
|
||||
_logginglevel = systeminfo["logginglevel"];
|
||||
_swagger = systeminfo["swagger"];
|
||||
_packageservice = systeminfo["packageservice"];
|
||||
systeminfo = await SystemService.GetSystemInfoAsync();
|
||||
if (systeminfo != null)
|
||||
{
|
||||
_installationid = systeminfo["InstallationId"].ToString();
|
||||
_detailederrors = systeminfo["DetailedErrors"].ToString();
|
||||
_logginglevel = systeminfo["Logging:LogLevel:Default"].ToString();
|
||||
_notificationlevel = systeminfo["Logging:LogLevel:Notify"].ToString();
|
||||
_swagger = systeminfo["UseSwagger"].ToString();
|
||||
_packageservice = systeminfo["PackageService"].ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,13 +198,12 @@
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = new Dictionary<string, string>();
|
||||
settings.Add("runtime", _runtime);
|
||||
settings.Add("rendermode", _rendermode);
|
||||
settings.Add("detailederrors", _detailederrors);
|
||||
settings.Add("logginglevel", _logginglevel);
|
||||
settings.Add("swagger", _swagger);
|
||||
settings.Add("packageservice", _packageservice);
|
||||
var settings = new Dictionary<string, object>();
|
||||
settings.Add("DetailedErrors", _detailederrors);
|
||||
settings.Add("Logging:LogLevel:Default", _logginglevel);
|
||||
settings.Add("Logging:LogLevel:Notify", _notificationlevel);
|
||||
settings.Add("UseSwagger", _swagger);
|
||||
settings.Add("PackageService", _packageservice);
|
||||
await SystemService.UpdateSystemInfoAsync(settings);
|
||||
AddModuleMessage(Localizer["Success.UpdateConfig.Restart"], MessageType.Success);
|
||||
}
|
||||
|
@ -70,8 +70,7 @@
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" HelpText="Upload one or more theme packages. Once they are uploaded click Install to complete the installation." ResourceKey="Theme">Theme: </Label>
|
||||
<div class="col-sm-9">
|
||||
<FileManager Filter="nupkg" ShowFiles="false" Folder="Packages" UploadMultiple="@true" />
|
||||
|
||||
<FileManager Folder="@Constants.PackagesFolder" UploadMultiple="true" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -230,7 +229,7 @@
|
||||
{
|
||||
try
|
||||
{
|
||||
await PackageService.DownloadPackageAsync(_packageid, _version, "Packages");
|
||||
await PackageService.DownloadPackageAsync(_packageid, _version, Constants.PackagesFolder);
|
||||
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _packageid, _version);
|
||||
AddModuleMessage(Localizer["Success.Theme.Download"], MessageType.Success);
|
||||
_productname = "";
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
@if (_templates != null)
|
||||
{
|
||||
<div class="container">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="owner" HelpText="Enter the name of the organization who is developing this theme. It should not contain spaces or punctuation." ResourceKey="OwnerName">Owner Name: </Label>
|
||||
<div class="col-sm-9">
|
||||
@ -51,7 +51,8 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@if (!string.IsNullOrEmpty(_location)) {
|
||||
@if (!string.IsNullOrEmpty(_location))
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="location" HelpText="Location where the theme will be created" ResourceKey="Location">Location: </Label>
|
||||
<div class="col-sm-9">
|
||||
@ -59,7 +60,7 @@
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<button type="button" class="btn btn-success" @onclick="CreateTheme">@Localizer["Theme.Create"]</button>
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
@ -71,19 +72,23 @@
|
||||
private List<Template> _templates;
|
||||
private string _template = "-";
|
||||
private string[] _versions;
|
||||
private string _reference = Constants.Version;
|
||||
private string _reference = "local";
|
||||
private string _minversion = "2.0.0";
|
||||
private string _location = string.Empty;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
AddModuleMessage(Localizer["Info.Theme.CreatorIntent"], MessageType.Info);
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_templates = await ThemeService.GetThemeTemplatesAsync();
|
||||
_versions = Constants.ReleaseVersions.Split(',').Where(item => Version.Parse(item).CompareTo(Version.Parse("2.0.0")) >= 0).ToArray();
|
||||
AddModuleMessage(Localizer["Info.Theme.CreatorIntent"], MessageType.Info);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -40,9 +40,12 @@ else
|
||||
@((MarkupString)PurchaseLink(context.PackageName))
|
||||
</td>
|
||||
<td>
|
||||
@if (UpgradeAvailable(context.PackageName, context.Version))
|
||||
@{
|
||||
var version = UpgradeAvailable(context.PackageName, context.Version);
|
||||
}
|
||||
@if (version != context.Version)
|
||||
{
|
||||
<button type="button" class="btn btn-success" @onclick=@(async () => await DownloadTheme(context.PackageName, context.Version))>@SharedLocalizer["Upgrade"]</button>
|
||||
<button type="button" class="btn btn-success" @onclick=@(async () => await DownloadTheme(context.PackageName, version))>@SharedLocalizer["Upgrade"]</button>
|
||||
}
|
||||
</td>
|
||||
<td></td>
|
||||
@ -94,25 +97,24 @@ else
|
||||
return link;
|
||||
}
|
||||
|
||||
private bool UpgradeAvailable(string packagename, string version)
|
||||
private string UpgradeAvailable(string packagename, string version)
|
||||
{
|
||||
var upgradeavailable = false;
|
||||
if (!string.IsNullOrEmpty(packagename) && _packages != null)
|
||||
{
|
||||
var package = _packages.Where(item => item.PackageId == packagename).FirstOrDefault();
|
||||
if (package != null)
|
||||
if (package != null && Version.Parse(package.Version).CompareTo(Version.Parse(version)) > 0)
|
||||
{
|
||||
upgradeavailable = (Version.Parse(package.Version).CompareTo(Version.Parse(version)) > 0);
|
||||
return package.Version;
|
||||
}
|
||||
}
|
||||
return upgradeavailable;
|
||||
return version;
|
||||
}
|
||||
|
||||
private async Task DownloadTheme(string packagename, string version)
|
||||
{
|
||||
try
|
||||
{
|
||||
await PackageService.DownloadPackageAsync(packagename, version, "Packages");
|
||||
await PackageService.DownloadPackageAsync(packagename, version, Constants.PackagesFolder);
|
||||
await logger.LogInformation("Theme Downloaded {ThemeName} {Version}", packagename, version);
|
||||
await ThemeService.InstallThemesAsync();
|
||||
AddModuleMessage(string.Format(Localizer["Success.Theme.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
|
@ -26,7 +26,7 @@
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" HelpText="Upload A Framework Package And Then Select Upgrade" ResourceKey="Framework">Framework: </Label>
|
||||
<div class="col-sm-9">
|
||||
<FileManager Filter="nupkg" ShowFiles="false" Folder="Packages" />
|
||||
<FileManager Folder="@Constants.PackagesFolder" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -85,8 +85,8 @@
|
||||
{
|
||||
try
|
||||
{
|
||||
await PackageService.DownloadPackageAsync(packageid, version, "Packages");
|
||||
await PackageService.DownloadPackageAsync(Constants.UpdaterPackageId, version, "Packages");
|
||||
await PackageService.DownloadPackageAsync(packageid, version, Constants.PackagesFolder);
|
||||
await PackageService.DownloadPackageAsync(Constants.UpdaterPackageId, version, Constants.PackagesFolder);
|
||||
AddModuleMessage(Localizer["Success.Framework.Download"], MessageType.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
89
Oqtane.Client/Modules/Admin/UrlMappings/Add.razor
Normal file
89
Oqtane.Client/Modules/Admin/UrlMappings/Add.razor
Normal file
@ -0,0 +1,89 @@
|
||||
@namespace Oqtane.Modules.Admin.UrlMappings
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IUrlMappingService UrlMappingService
|
||||
@inject IStringLocalizer<Edit> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="url" HelpText="The fully qualified Url for this site" ResourceKey="Url">Url:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="url" class="form-control" @bind="@_url" maxlength="500" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="mappedurl" HelpText="A fully qualified Url where the user will be redirected" ResourceKey="MappedUrl">Redirect To:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="mappedurl" class="form-control" @bind="@_mappedurl" maxlength="500" required />
|
||||
</div>
|
||||
</div>
|
||||
<br /><br />
|
||||
<button type="button" class="btn btn-success" @onclick="SaveUrlMapping">@SharedLocalizer["Save"]</button>
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@code {
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
|
||||
private string _url = string.Empty;
|
||||
private string _mappedurl = string.Empty;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
private async Task SaveUrlMapping()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
if (_url != _mappedurl)
|
||||
{
|
||||
var url = PageState.Uri.Scheme + "://" + PageState.Uri.Authority + "/";
|
||||
url = url + (!string.IsNullOrEmpty(PageState.Alias.Path) ? PageState.Alias.Path + "/" : "");
|
||||
|
||||
_url = (_url.StartsWith("/")) ? _url.Substring(1) : _url;
|
||||
_url = (!_url.StartsWith("http")) ? url + _url : _url;
|
||||
|
||||
if (_url.StartsWith(url))
|
||||
{
|
||||
var urlmapping = new UrlMapping();
|
||||
urlmapping.SiteId = PageState.Site.SiteId;
|
||||
var route = new Route(_url, PageState.Alias.Path);
|
||||
urlmapping.Url = route.PagePath;
|
||||
urlmapping.MappedUrl = _mappedurl.Replace(url, "");
|
||||
urlmapping.Requests = 0;
|
||||
urlmapping.CreatedOn = DateTime.UtcNow;
|
||||
urlmapping.RequestedOn = DateTime.UtcNow;
|
||||
|
||||
try
|
||||
{
|
||||
urlmapping = await UrlMappingService.AddUrlMappingAsync(urlmapping);
|
||||
await logger.LogInformation("UrlMapping Saved {UrlMapping}", urlmapping);
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving UrlMapping {UrlMapping} {Error}", urlmapping, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.SaveUrlMapping"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.SaveUrlMapping"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.DuplicateUrlMapping"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
}
|
92
Oqtane.Client/Modules/Admin/UrlMappings/Edit.razor
Normal file
92
Oqtane.Client/Modules/Admin/UrlMappings/Edit.razor
Normal file
@ -0,0 +1,92 @@
|
||||
@namespace Oqtane.Modules.Admin.UrlMappings
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IUrlMappingService UrlMappingService
|
||||
@inject IStringLocalizer<Edit> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="url" HelpText="A fully qualified Url for this site" ResourceKey="Url">Url:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="url" class="form-control" @bind="@_url" maxlength="500" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="mappedurl" HelpText="A fully qualified Url where the user will be redirected" ResourceKey="MappedUrl">Redirect To:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="mappedurl" class="form-control" @bind="@_mappedurl" maxlength="500" required />
|
||||
</div>
|
||||
</div>
|
||||
<br /><br />
|
||||
<button type="button" class="btn btn-success" @onclick="SaveUrlMapping">@SharedLocalizer["Save"]</button>
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@code {
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
|
||||
private int _urlmappingid;
|
||||
private string _url = string.Empty;
|
||||
private string _mappedurl = string.Empty;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_urlmappingid = Int32.Parse(PageState.QueryString["id"]);
|
||||
var urlmapping = await UrlMappingService.GetUrlMappingAsync(_urlmappingid);
|
||||
if (urlmapping != null)
|
||||
{
|
||||
_url = urlmapping.Url;
|
||||
_mappedurl = urlmapping.MappedUrl;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading UrlMapping {UrlMappingId} {Error}", _urlmappingid, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.LoadUrlMapping"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveUrlMapping()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
if (_url != _mappedurl)
|
||||
{
|
||||
try
|
||||
{
|
||||
var url = PageState.Uri.Scheme + "://" + PageState.Uri.Authority + "/";
|
||||
url = url + (!string.IsNullOrEmpty(PageState.Alias.Path) ? PageState.Alias.Path + "/" : "");
|
||||
|
||||
var urlmapping = await UrlMappingService.GetUrlMappingAsync(_urlmappingid);
|
||||
urlmapping.MappedUrl = _mappedurl.Replace(url, "");
|
||||
urlmapping = await UrlMappingService.UpdateUrlMappingAsync(urlmapping);
|
||||
await logger.LogInformation("UrlMapping Saved {UrlMapping}", urlmapping);
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving UrlMapping {UrlMappingId} {Error}", _urlmappingid, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.SaveUrlMapping"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.DuplicateUrlMapping"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
}
|
135
Oqtane.Client/Modules/Admin/UrlMappings/Index.razor
Normal file
135
Oqtane.Client/Modules/Admin/UrlMappings/Index.razor
Normal file
@ -0,0 +1,135 @@
|
||||
@namespace Oqtane.Modules.Admin.UrlMappings
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IUrlMappingService UrlMappingService
|
||||
@inject ISiteService SiteService
|
||||
@inject IStringLocalizer<Index> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
@if (_urlMappings == null)
|
||||
{
|
||||
<p><em>@SharedLocalizer["Loading"]</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<TabStrip>
|
||||
<TabPanel Name="Urls" Heading="Urls" ResourceKey="Urls">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<div class="col-sm-6">
|
||||
<ActionLink Action="Add" Text="Add Url Mapping" ResourceKey="AddUrlMapping" />
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<select id="type" class="form-select custom-select" @onchange="(e => MappedChanged(e))">
|
||||
<option value="true">@Localizer["Mapped"]</option>
|
||||
<option value="false">@Localizer["Broken"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<Pager Items="@_urlMappings">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@Localizer["Url"]</th>
|
||||
<th>@Localizer["Requests"]</th>
|
||||
<th>@Localizer["Requested"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.UrlMappingId.ToString())" ResourceKey="Edit" /></td>
|
||||
<td><ActionDialog Header="Delete Url Mapping" Message="@string.Format(Localizer["Confirm.DeleteUrlMapping"], context.Url)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteUrlMapping(context))" ResourceKey="DeleteUrlMapping" /></td>
|
||||
<td>
|
||||
<a href="@Utilities.TenantUrl(PageState.Alias, context.Url)">@context.Url</a>
|
||||
@if (_mapped)
|
||||
{
|
||||
@((MarkupString)"<br />>> ")<a href="@((context.MappedUrl.StartsWith("http") ? context.MappedUrl : Utilities.TenantUrl(PageState.Alias, context.MappedUrl)))">@context.MappedUrl</a>
|
||||
}
|
||||
</td>
|
||||
<td>@context.Requests</td>
|
||||
<td>@context.RequestedOn</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
</TabPanel>
|
||||
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="capturebrokenurls" HelpText="Specify if broken Urls should be captured automatically and saved in Url Mappings" ResourceKey="CaptureBrokenUrls">Capture Broken Urls? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="capturebrokenurls" class="form-select" @bind="@_capturebrokenurls" >
|
||||
<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="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
||||
</TabPanel>
|
||||
</TabStrip>
|
||||
}
|
||||
|
||||
@code {
|
||||
private bool _mapped = true;
|
||||
private List<UrlMapping> _urlMappings;
|
||||
private string _capturebrokenurls;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
await GetUrlMappings();
|
||||
_capturebrokenurls = PageState.Site.CaptureBrokenUrls.ToString();
|
||||
}
|
||||
|
||||
private async void MappedChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_mapped = bool.Parse(e.Value.ToString());
|
||||
await GetUrlMappings();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error On TypeChanged");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DeleteUrlMapping(UrlMapping urlMapping)
|
||||
{
|
||||
try
|
||||
{
|
||||
await UrlMappingService.DeleteUrlMappingAsync(urlMapping.UrlMappingId);
|
||||
await logger.LogInformation("UrlMapping Deleted {UrlMapping}", urlMapping);
|
||||
await GetUrlMappings();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Deleting UrlMapping {UrlMapping} {Error}", urlMapping, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.DeleteUrlMapping"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GetUrlMappings()
|
||||
{
|
||||
_urlMappings = await UrlMappingService.GetUrlMappingsAsync(PageState.Site.SiteId, _mapped);
|
||||
}
|
||||
|
||||
private async Task SaveSiteSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
var site = PageState.Site;
|
||||
site.CaptureBrokenUrls = bool.Parse(_capturebrokenurls);
|
||||
await SiteService.UpdateSiteAsync(site);
|
||||
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving Site Settings {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@
|
||||
<Label Class="col-sm-3" For="to" HelpText="Enter the username you wish to send a message to" ResourceKey="To">To: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="to" class="form-control" @bind="@username" />
|
||||
</div> >
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="subject" HelpText="Enter the subject of the message" ResourceKey="Subject">Subject: </Label>
|
||||
@ -49,7 +49,7 @@
|
||||
var user = await UserService.GetUserAsync(username, PageState.Site.SiteId);
|
||||
if (user != null)
|
||||
{
|
||||
var notification = new Notification(PageState.Site.SiteId, PageState.User, user, subject, body, null);
|
||||
var notification = new Notification(PageState.Site.SiteId, PageState.User, user, subject, body);
|
||||
notification = await NotificationService.AddNotificationAsync(notification);
|
||||
await logger.LogInformation("Notification Created {NotificationId}", notification.NotificationId);
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
@if (PageState.User != null && photo != null)
|
||||
{
|
||||
<img src="@ImageUrl(photofileid, 400, 400, "crop")" alt="@displayname" style="max-width: 400px" class="rounded-circle mx-auto d-block">
|
||||
<img src="@ImageUrl(photofileid, 400, 400)" alt="@displayname" style="max-width: 400px" class="rounded-circle mx-auto d-block">
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -32,15 +32,33 @@ else
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="password" HelpText="If you wish to change your password you can enter it here. Please choose a sufficiently secure password." ResourceKey="Password"></Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="password" type="password" class="form-control" @bind="@password" autocomplete="new-password" />
|
||||
<div class="input-group">
|
||||
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" />
|
||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglepassword</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="confirm" HelpText="If you are changing your password you must enter it again to confirm it matches" ResourceKey="Confirm"></Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="confirm" type="password" class="form-control" @bind="@confirm" autocomplete="new-password" />
|
||||
<div class="input-group">
|
||||
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@confirm" autocomplete="new-password" />
|
||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglepassword</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@if (allowtwofactor)
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="twofactor" HelpText="Indicates if you are using two factor authentication. Two factor authentication requires you to enter a verification code sent via email after you sign in." ResourceKey="TwoFactor"></Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="twofactor" class="form-select" @bind="@twofactor" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="email" HelpText="Your email address where you wish to receive notifications" ResourceKey="Email"></Label>
|
||||
<div class="col-sm-9">
|
||||
@ -142,7 +160,7 @@ else
|
||||
<td><ActionDialog Header="Delete Notification" Message="Are You Sure You Wish To Delete This Notification?" Action="Delete" Security="SecurityAccessLevel.View" Class="btn btn-danger" OnClick="@(async () => await Delete(context))" EditMode="false" ResourceKey="DeleteNotification" /></td>
|
||||
<td>@context.FromDisplayName</td>
|
||||
<td>@context.Subject</td>
|
||||
<td>@context.CreatedOn</td>
|
||||
<td>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</td>
|
||||
</Row>
|
||||
<Detail>
|
||||
<td colspan="2"></td>
|
||||
@ -175,7 +193,7 @@ else
|
||||
<td><ActionDialog Header="Delete Notification" Message="Are You Sure You Wish To Delete This Notification?" Action="Delete" Security="SecurityAccessLevel.View" Class="btn btn-danger" OnClick="@(async () => await Delete(context))" EditMode="false" ResourceKey="DeleteNotification" /></td>
|
||||
<td>@context.ToDisplayName</td>
|
||||
<td>@context.Subject</td>
|
||||
<td>@context.CreatedOn</td>
|
||||
<td>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", @context.CreatedOn)</td>
|
||||
</Row>
|
||||
<Detail>
|
||||
<td colspan="2"></td>
|
||||
@ -193,6 +211,8 @@ else
|
||||
</Detail>
|
||||
</Pager>
|
||||
}
|
||||
<br />
|
||||
<ActionDialog Header="Clear Notifications" Message="Are You Sure You Wish To Permanently Delete All Notifications ?" Action="Delete All Notifications" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteAllNotifications())" ResourceKey="DeleteAllNotifications" />
|
||||
<br /><hr />
|
||||
<select class="form-select" @onchange="(e => FilterChanged(e))">
|
||||
<option value="to">@Localizer["Inbox"]</option>
|
||||
@ -201,11 +221,16 @@ else
|
||||
}
|
||||
</TabPanel>
|
||||
</TabStrip>
|
||||
<br /><br />
|
||||
|
||||
@code {
|
||||
private string username = string.Empty;
|
||||
private string password = string.Empty;
|
||||
private string _password = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private string confirm = string.Empty;
|
||||
private bool allowtwofactor = false;
|
||||
private string twofactor = "False";
|
||||
private string email = string.Empty;
|
||||
private string displayname = string.Empty;
|
||||
private FileManager filemanager;
|
||||
@ -224,9 +249,17 @@ else
|
||||
{
|
||||
try
|
||||
{
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
|
||||
if (PageState.Site.Settings.ContainsKey("LoginOptions:TwoFactor") && !string.IsNullOrEmpty(PageState.Site.Settings["LoginOptions:TwoFactor"]))
|
||||
{
|
||||
allowtwofactor = (PageState.Site.Settings["LoginOptions:TwoFactor"] == "true");
|
||||
}
|
||||
|
||||
if (PageState.User != null)
|
||||
{
|
||||
username = PageState.User.Username;
|
||||
twofactor = PageState.User.TwoFactorRequired.ToString();
|
||||
email = PageState.User.Email;
|
||||
displayname = PageState.User.DisplayName;
|
||||
|
||||
@ -280,11 +313,12 @@ else
|
||||
{
|
||||
if (username != string.Empty && email != string.Empty && ValidateProfiles())
|
||||
{
|
||||
if (password == confirm)
|
||||
if (_password == confirm)
|
||||
{
|
||||
var user = PageState.User;
|
||||
user.Username = username;
|
||||
user.Password = password;
|
||||
user.Password = _password;
|
||||
user.TwoFactorRequired = bool.Parse(twofactor);
|
||||
user.Email = email;
|
||||
user.DisplayName = (displayname == string.Empty ? username : displayname);
|
||||
user.PhotoFileId = filemanager.GetFileId();
|
||||
@ -292,12 +326,23 @@ else
|
||||
{
|
||||
user.PhotoFileId = null;
|
||||
}
|
||||
if (user.PhotoFileId != null)
|
||||
{
|
||||
photofileid = user.PhotoFileId.Value;
|
||||
photo = await FileService.GetFileAsync(photofileid);
|
||||
}
|
||||
else
|
||||
{
|
||||
photofileid = -1;
|
||||
photo = null;
|
||||
}
|
||||
|
||||
await UserService.UpdateUserAsync(user);
|
||||
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
|
||||
await logger.LogInformation("User Profile Saved");
|
||||
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
AddModuleMessage(Localizer["Success.Profile.Update"], MessageType.Success);
|
||||
StateHasChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -380,4 +425,47 @@ else
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task DeleteAllNotifications()
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach(var Notification in notifications)
|
||||
{
|
||||
if (!Notification.IsDeleted)
|
||||
{
|
||||
Notification.IsDeleted = true;
|
||||
await NotificationService.UpdateNotificationAsync(Notification);
|
||||
}
|
||||
else
|
||||
{
|
||||
await NotificationService.DeleteNotificationAsync(Notification.NotificationId);
|
||||
}
|
||||
await logger.LogInformation("Notification Deleted {Notification}", Notification);
|
||||
}
|
||||
await logger.LogInformation("Notifications Permanently Deleted");
|
||||
await LoadNotificationsAsync();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Deleting Notifications {Error}", ex.Message);
|
||||
AddModuleMessage(ex.Message, MessageType.Error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void TogglePassword()
|
||||
{
|
||||
if (_passwordtype == "password")
|
||||
{
|
||||
_passwordtype = "text";
|
||||
_togglepassword = SharedLocalizer["HidePassword"];
|
||||
}
|
||||
else
|
||||
{
|
||||
_passwordtype = "password";
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,13 +21,19 @@
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="password" HelpText="The user's password. Please choose a password which is sufficiently secure." ResourceKey="Password"></Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="password" type="password" class="form-control" @bind="@password" />
|
||||
<div class="input-group">
|
||||
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" required />
|
||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglepassword</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<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">
|
||||
<input id="confirm" type="password" class="form-control" @bind="@confirm" />
|
||||
<div class="input-group">
|
||||
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@confirm" autocomplete="new-password" required />
|
||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglepassword</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
@ -88,7 +94,9 @@
|
||||
|
||||
@code {
|
||||
private string username = string.Empty;
|
||||
private string password = string.Empty;
|
||||
private string _password = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private string confirm = string.Empty;
|
||||
private string email = string.Empty;
|
||||
private string displayname = string.Empty;
|
||||
@ -102,6 +110,7 @@
|
||||
{
|
||||
try
|
||||
{
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
||||
settings = new Dictionary<string, string>();
|
||||
}
|
||||
@ -119,9 +128,9 @@
|
||||
{
|
||||
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 && ValidateProfiles())
|
||||
{
|
||||
if (password == confirm)
|
||||
if (_password == confirm)
|
||||
{
|
||||
var user = await UserService.GetUserAsync(username, PageState.Site.SiteId);
|
||||
if (user == null)
|
||||
@ -129,7 +138,7 @@
|
||||
user = new User();
|
||||
user.SiteId = PageState.Site.SiteId;
|
||||
user.Username = username;
|
||||
user.Password = password;
|
||||
user.Password = _password;
|
||||
user.Email = email;
|
||||
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
|
||||
user.PhotoFileId = null;
|
||||
@ -193,4 +202,17 @@
|
||||
settings = SettingService.SetSetting(settings, SettingName, value);
|
||||
}
|
||||
|
||||
private void TogglePassword()
|
||||
{
|
||||
if (_passwordtype == "password")
|
||||
{
|
||||
_passwordtype = "text";
|
||||
_togglepassword = SharedLocalizer["HidePassword"];
|
||||
}
|
||||
else
|
||||
{
|
||||
_passwordtype = "password";
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,13 +30,19 @@ else
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="password" HelpText="The user's password. Please choose a password which is sufficiently secure." ResourceKey="Password"></Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="password" type="password" class="form-control" @bind="@password" />
|
||||
<div class="input-group">
|
||||
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" />
|
||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglepassword</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<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">
|
||||
<input id="confirm" type="password" class="form-control" @bind="@confirm" />
|
||||
<div class="input-group">
|
||||
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@confirm" autocomplete="new-password" />
|
||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglepassword</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
@ -66,8 +72,19 @@ else
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="lastlogin" HelpText="The date and time when the user last signed in" ResourceKey="LastLogin"></Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="lastlogin" class="form-control" @bind="@lastlogin" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="lastipaddress" HelpText="The IP Address of the user recorded during their last login" ResourceKey="LastIPAddress"></Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="lastipaddress" class="form-control" @bind="@lastipaddress" readonly />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
</TabPanel>
|
||||
<TabPanel Name="Profile" ResourceKey="Profile">
|
||||
@ -133,23 +150,29 @@ else
|
||||
@code {
|
||||
private int userid;
|
||||
private string username = string.Empty;
|
||||
private string password = string.Empty;
|
||||
private string _password = string.Empty;
|
||||
private string _passwordtype = "password";
|
||||
private string _togglepassword = string.Empty;
|
||||
private string confirm = string.Empty;
|
||||
private string email = string.Empty;
|
||||
private string displayname = string.Empty;
|
||||
private FileManager filemanager;
|
||||
private int photofileid = -1;
|
||||
private File photo = null;
|
||||
private string isdeleted;
|
||||
private string lastlogin;
|
||||
private string lastipaddress;
|
||||
|
||||
private List<Profile> profiles;
|
||||
private Dictionary<string, string> settings;
|
||||
private string category = string.Empty;
|
||||
|
||||
private string createdby;
|
||||
private DateTime createdon;
|
||||
private string modifiedby;
|
||||
private DateTime modifiedon;
|
||||
private string deletedby;
|
||||
private DateTime? deletedon;
|
||||
private string isdeleted;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
@ -157,9 +180,9 @@ else
|
||||
{
|
||||
try
|
||||
{
|
||||
// OnParametersSetAsync is called when the edit modal is closed - in which case there is no id parameter
|
||||
if (PageState.QueryString.ContainsKey("id"))
|
||||
{
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
profiles = await ProfileService.GetProfilesAsync(PageState.Site.SiteId);
|
||||
userid = Int32.Parse(PageState.QueryString["id"]);
|
||||
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
|
||||
@ -178,6 +201,10 @@ else
|
||||
photofileid = -1;
|
||||
photo = null;
|
||||
}
|
||||
isdeleted = user.IsDeleted.ToString();
|
||||
lastlogin = string.Format("{0:MMM dd yyyy HH:mm:ss}", user.LastLoginOn);
|
||||
lastipaddress = user.LastIPAddress;
|
||||
|
||||
settings = await SettingService.GetUserSettingsAsync(user.UserId);
|
||||
createdby = user.CreatedBy;
|
||||
createdon = user.CreatedOn;
|
||||
@ -185,7 +212,6 @@ else
|
||||
modifiedon = user.ModifiedOn;
|
||||
deletedby = user.DeletedBy;
|
||||
deletedon = user.DeletedOn;
|
||||
isdeleted = user.IsDeleted.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -205,12 +231,12 @@ else
|
||||
{
|
||||
if (username != string.Empty && email != string.Empty && ValidateProfiles())
|
||||
{
|
||||
if (password == confirm)
|
||||
if (_password == confirm)
|
||||
{
|
||||
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
|
||||
user.SiteId = PageState.Site.SiteId;
|
||||
user.Username = username;
|
||||
user.Password = password;
|
||||
user.Password = _password;
|
||||
user.Email = email;
|
||||
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
|
||||
user.PhotoFileId = null;
|
||||
@ -268,4 +294,17 @@ else
|
||||
settings = SettingService.SetSetting(settings, SettingName, value);
|
||||
}
|
||||
|
||||
private void TogglePassword()
|
||||
{
|
||||
if (_passwordtype == "password")
|
||||
{
|
||||
_passwordtype = "text";
|
||||
_togglepassword = SharedLocalizer["HidePassword"];
|
||||
}
|
||||
else
|
||||
{
|
||||
_passwordtype = "password";
|
||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,12 @@
|
||||
@inject IUserRoleService UserRoleService
|
||||
@inject IUserService UserService
|
||||
@inject ISettingService SettingService
|
||||
@inject ISiteService SiteService
|
||||
@inject IStringLocalizer<Index> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
@inject SiteState SiteState
|
||||
|
||||
@if (userroles == null)
|
||||
@if (users == null)
|
||||
{
|
||||
<p>
|
||||
<em>@SharedLocalizer["Loading"]</em>
|
||||
@ -14,6 +16,8 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<TabStrip>
|
||||
<TabPanel Name="Users" Heading="Users" ResourceKey="Users">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<div class="col-sm-4">
|
||||
@ -23,16 +27,18 @@ else
|
||||
<input class="form-control" @bind="@_search" />
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<button class="btn btn-secondary" @onclick="OnSearch">@SharedLocalizer["Search"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="OnSearch">@SharedLocalizer["Search"]</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Pager Items="@userroles">
|
||||
<Pager Items="@users" RowClass="align-middle">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@SharedLocalizer["Username"]</th>
|
||||
<th>@SharedLocalizer["Name"]</th>
|
||||
<th>@Localizer["LastLoginOn"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td>
|
||||
@ -44,46 +50,435 @@ else
|
||||
<td>
|
||||
<ActionLink Action="Roles" Parameters="@($"id=" + context.UserId.ToString())" ResourceKey="Roles" />
|
||||
</td>
|
||||
<td>@context.User.DisplayName</td>
|
||||
<td>@context.User.Username</td>
|
||||
<td>@((MarkupString)string.Format("<a href=\"mailto:{0}\">{1}</a>", @context.User.Email, @context.User.DisplayName))</td>
|
||||
<td>@string.Format("{0:dd-MMM-yyyy HH:mm:ss}", context.User.LastLoginOn)</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
</TabPanel>
|
||||
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings">
|
||||
<div class="container">
|
||||
<Section Name="User" Heading="User Settings" ResourceKey="UserSettings">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="allowregistration" HelpText="Do you want anonymous visitors to be able to register for an account on the site" ResourceKey="AllowRegistration">Allow User Registration?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="allowregistration" class="form-select" @bind="@_allowregistration">
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@if (_providertype != "")
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="allowsitelogin" HelpText="Do you want to allow users to sign in using a username and password that is managed locally on this site? Note that you should only disable this option if you have already sucessfully configured an external login provider, or else you may lock yourself out of the site." ResourceKey="AllowSiteLogin">Allow Login?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="allowsitelogin" class="form-select" @bind="@_allowsitelogin">
|
||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||
<option value="false">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="allowsitelogin" HelpText="Do you want to allow users to sign in using a username and password that is managed locally on this site? Note that you should only disable this option if you have already sucessfully configured an external login provider, or else you may lock yourself out of the site." ResourceKey="AllowSiteLogin">Allow Login?</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="allowsitelogin" class="form-control" value="@SharedLocalizer["Yes"]" readonly />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="twofactor" HelpText="Do you want users to use two factor authentication? Note that you should use the Disabled option until you have successfully verified that the Notification Job in Scheduled Jobs is enabled and your SMTP options in Site Settings are configured or else you will lock yourself out." ResourceKey="TwoFactor">Two Factor?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="twofactor" class="form-select" @bind="@_twofactor">
|
||||
<option value="false">@Localizer["Disabled"]</option>
|
||||
<option value="true">@Localizer["Optional"]</option>
|
||||
<option value="required">@Localizer["Required"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="cookiename" HelpText="You can choose to use a custom authentication cookie name for each site. However please be aware that if you want to share an authentication cookie between sites on the same domain they need to use a consistent cookie name. Also be aware that changing the authentication cookie name will logout all current users." ResourceKey="CookieName">Cookie Name:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="cookiename" class="form-control" @bind="@_cookiename" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</Section>
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
<Section Name="Password" Heading="Password Settings" ResourceKey="PasswordSettings">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="minimumlength" HelpText="The Minimum Length For A Password" ResourceKey="RequiredLength">Minimum Length:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="minimumlength" class="form-control" @bind="@_minimumlength" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="uniquecharacters" HelpText="The Minimum Number Of Unique Characters Which A Password Must Contain" ResourceKey="UniqueCharacters">Unique Characters:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="uniquecharacters" class="form-control" @bind="@_uniquecharacters" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="requiredigit" HelpText="Indicate If Passwords Must Contain A Digit" ResourceKey="RequireDigit">Require Digit?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="requiredigit" class="form-select" @bind="@_requiredigit" required>
|
||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||
<option value="false">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="requireupper" HelpText="Indicate If Passwords Must Contain An Upper Case Character" ResourceKey="RequireUpper">Require Uppercase?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="requireupper" class="form-select" @bind="@_requireupper" required>
|
||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||
<option value="false">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="requirelower" HelpText="Indicate If Passwords Must Contain A Lower Case Character" ResourceKey="RequireLower">Require Lowercase?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="requirelower" class="form-select" @bind="@_requirelower" required>
|
||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||
<option value="false">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="requirepunctuation" HelpText="Indicate if Passwords Must Contain A Non-alphanumeric Character (ie. Punctuation)" ResourceKey="RequirePunctuation">Require Punctuation?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="requirepunctuation" class="form-select" @bind="@_requirepunctuation" required>
|
||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||
<option value="false">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
<Section Name="Lockout" Heading="Lockout Settings" ResourceKey="LockoutSettings">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="maximum" HelpText="The Maximum Number Of Sign In Attempts Before A User Is Locked Out" ResourceKey="MaximumFailures">Maximum Failures:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="maximum" class="form-control" @bind="@_maximumfailures" required />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="lockoutduration" HelpText="The Number Of Minutes A User Should Be Locked Out" ResourceKey="LockoutDuration">Lockout Duration:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="lockoutduration" class="form-control" @bind="@_lockoutduration" required />
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
<Section Name="ExternalLogin" Heading="External Login Settings" ResourceKey="ExternalLoginSettings">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="providertype" HelpText="Select the external login provider type" ResourceKey="ProviderType">Provider Type:</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="providertype" class="form-select" value="@_providertype" @onchange="(e => ProviderTypeChanged(e))">
|
||||
<option value="" selected>@Localizer["Not Specified"]</option>
|
||||
<option value="@AuthenticationProviderTypes.OpenIDConnect">@Localizer["OpenID Connect"]</option>
|
||||
<option value="@AuthenticationProviderTypes.OAuth2">@Localizer["OAuth 2.0"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@if (_providertype != "")
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="providername" HelpText="The external login provider name which will be displayed on the login page" ResourceKey="ProviderName">Provider Name:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="providername" class="form-control" @bind="@_providername" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@if (_providertype == AuthenticationProviderTypes.OpenIDConnect)
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="authority" HelpText="The Authority Url or Issuer Url associated with the OpenID Connect provider" ResourceKey="Authority">Authority:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="authority" class="form-control" @bind="@_authority" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="metadataurl" HelpText="The discovery endpoint for obtaining metadata for this provider. Only specify if the OpenID Connect provider does not use the standard approach (ie. /.well-known/openid-configuration)" ResourceKey="MetadataUrl">Metadata Url:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="metadataurl" class="form-control" @bind="@_metadataurl" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@if (_providertype == AuthenticationProviderTypes.OAuth2)
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="authorizationurl" HelpText="The endpoint for obtaining an Authorization Code" ResourceKey="AuthorizationUrl">Authorization Url:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="authorizationurl" class="form-control" @bind="@_authorizationurl" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="tokenurl" HelpText="The endpoint for obtaining an Auth Token" ResourceKey="TokenUrl">Token Url:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="tokenurl" class="form-control" @bind="@_tokenurl" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="userinfourl" HelpText="The endpoint for obtaining user information. This should be an API or Page Url which contains the users email address." ResourceKey="UserInfoUrl">User Info Url:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="userinfourl" class="form-control" @bind="@_userinfourl" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@if (_providertype != "")
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="clientid" HelpText="The Client ID from the provider" ResourceKey="ClientID">Client ID:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="clientid" class="form-control" @bind="@_clientid" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="clientsecret" HelpText="The Client Secret from the provider" ResourceKey="ClientSecret">Client Secret:</Label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
<input type="@_clientsecrettype" id="clientsecret" class="form-control" @bind="@_clientsecret" />
|
||||
<button type="button" class="btn btn-secondary" @onclick="@ToggleClientSecret">@_toggleclientsecret</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="scopes" HelpText="A list of Scopes to request from the provider (separated by commas). If none are specified, standard Scopes will be used by default." ResourceKey="Scopes">Scopes:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="scopes" class="form-control" @bind="@_scopes" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="parameters" HelpText="Optionally specify any additional parameters as name/value pairs to send to the provider (separated by commas if there are multiple)." ResourceKey="Parameters">Parameters:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="parameters" class="form-control" @bind="@_parameters" />
|
||||
</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>
|
||||
<div class="col-sm-9">
|
||||
<select id="pkce" class="form-select" @bind="@_pkce" required>
|
||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||
<option value="false">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="redirecturl" HelpText="The Redirect Url (or Callback Url) which usually needs to be registered with the provider" ResourceKey="RedirectUrl">Redirect Url:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="redirecturl" class="form-control" @bind="@_redirecturl" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="identifierclaimtype" HelpText="The name of the unique user identifier claim provided by the provider" ResourceKey="IdentifierClaimType">Identifier Claim:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="identifierclaimtype" class="form-control" @bind="@_identifierclaimtype" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="emailclaimtype" HelpText="The name of the email address claim provided by the provider" ResourceKey="EmailClaimType">Email Claim:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="emailclaimtype" class="form-control" @bind="@_emailclaimtype" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="domainfilter" HelpText="Provide any email domain filter criteria (separated by commas). Domains to exclude should be prefixed with an exclamation point (!). For example 'microsoft.com,!hotmail.com' would include microsoft.com email addresses but not hotmail.com email addresses." ResourceKey="DomainFilter">Domain Filter:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="domainfilter" class="form-control" @bind="@_domainfilter" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="createusers" HelpText="Do you want new users to be created automatically? If you disable this option, users must already be registered on the site in order to sign in with their external login." ResourceKey="CreateUsers">Create New Users?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="createusers" class="form-select" @bind="@_createusers">
|
||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||
<option value="false">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</Section>
|
||||
<Section Name="Token" Heading="Token Settings" ResourceKey="TokenSettings">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="secret" HelpText="If you want to want to provide API access, please specify a secret which will be used to encrypt your tokens. The secret should be 16 characters or more to ensure optimal security. Please note that if you change this secret, all existing tokens will become invalid and will need to be regenerated." ResourceKey="Secret">Secret:</Label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
<input type="@_secrettype" id="secret" class="form-control" @bind="@_secret" />
|
||||
<button type="button" class="btn btn-secondary" @onclick="@ToggleSecret">@_togglesecret</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="issuer" HelpText="Optionally provide the issuer of the token" ResourceKey="Issuer">Issuer:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="issuer" class="form-control" @bind="@_issuer" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="audience" HelpText="Optionally provide the audience for the token" ResourceKey="Audience">Audience:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="audience" class="form-control" @bind="@_audience" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="lifetime" HelpText="The number of minutes for which a token should be valid" ResourceKey="Lifetime">Lifetime:</Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="lifetime" class="form-control" @bind="@_lifetime" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="token" HelpText="Select the Create Token button to generate a long-lived access token (valid for 1 year). Be sure to store this token in a safe location as you will not be able to access it in the future." ResourceKey="Token">Access Token:</Label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
<input id="token" class="form-control" @bind="@_token" />
|
||||
<button type="button" class="btn btn-secondary" @onclick="@CreateToken">@Localizer["CreateToken"]</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
}
|
||||
</div>
|
||||
<br />
|
||||
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
||||
</TabPanel>
|
||||
</TabStrip>
|
||||
}
|
||||
|
||||
@code {
|
||||
private List<UserRole> allroles;
|
||||
private List<UserRole> userroles;
|
||||
private string _search;
|
||||
private List<UserRole> allusers;
|
||||
private List<UserRole> users;
|
||||
private string _search = "";
|
||||
|
||||
private string _allowregistration;
|
||||
private string _allowsitelogin;
|
||||
private string _twofactor;
|
||||
private string _cookiename;
|
||||
|
||||
private string _minimumlength;
|
||||
private string _uniquecharacters;
|
||||
private string _requiredigit;
|
||||
private string _requireupper;
|
||||
private string _requirelower;
|
||||
private string _requirepunctuation;
|
||||
private string _maximumfailures;
|
||||
private string _lockoutduration;
|
||||
|
||||
private string _providertype;
|
||||
private string _providername;
|
||||
private string _authority;
|
||||
private string _metadataurl;
|
||||
private string _authorizationurl;
|
||||
private string _tokenurl;
|
||||
private string _userinfourl;
|
||||
private string _clientid;
|
||||
private string _clientsecret;
|
||||
private string _clientsecrettype = "password";
|
||||
private string _toggleclientsecret = string.Empty;
|
||||
private string _scopes;
|
||||
private string _parameters;
|
||||
private string _pkce;
|
||||
private string _redirecturl;
|
||||
private string _identifierclaimtype;
|
||||
private string _emailclaimtype;
|
||||
private string _domainfilter;
|
||||
private string _createusers;
|
||||
|
||||
private string _secret;
|
||||
private string _secrettype = "password";
|
||||
private string _togglesecret = string.Empty;
|
||||
private string _issuer;
|
||||
private string _audience;
|
||||
private string _lifetime;
|
||||
private string _token;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
allroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId);
|
||||
await LoadSettingsAsync();
|
||||
userroles = Search(_search);
|
||||
await LoadUserSettingsAsync();
|
||||
await LoadUsersAsync(true);
|
||||
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
_allowregistration = PageState.Site.AllowRegistration.ToString();
|
||||
_allowsitelogin = SettingService.GetSetting(settings, "LoginOptions:AllowSiteLogin", "true");
|
||||
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
_twofactor = SettingService.GetSetting(settings, "LoginOptions:TwoFactor", "false");
|
||||
_cookiename = SettingService.GetSetting(settings, "LoginOptions:CookieName", ".AspNetCore.Identity.Application");
|
||||
|
||||
_minimumlength = SettingService.GetSetting(settings, "IdentityOptions:Password:RequiredLength", "6");
|
||||
_uniquecharacters = SettingService.GetSetting(settings, "IdentityOptions:Password:RequiredUniqueChars", "1");
|
||||
_requiredigit = SettingService.GetSetting(settings, "IdentityOptions:Password:RequireDigit", "true");
|
||||
_requireupper = SettingService.GetSetting(settings, "IdentityOptions:Password:RequireUppercase", "true");
|
||||
_requirelower = SettingService.GetSetting(settings, "IdentityOptions:Password:RequireLowercase", "true");
|
||||
_requirepunctuation = SettingService.GetSetting(settings, "IdentityOptions:Password:RequireNonAlphanumeric", "true");
|
||||
|
||||
_maximumfailures = SettingService.GetSetting(settings, "IdentityOptions:Lockout:MaxFailedAccessAttempts", "5");
|
||||
_lockoutduration = TimeSpan.Parse(SettingService.GetSetting(settings, "IdentityOptions:Lockout:DefaultLockoutTimeSpan", "00:05:00")).TotalMinutes.ToString();
|
||||
|
||||
_providertype = SettingService.GetSetting(settings, "ExternalLogin:ProviderType", "");
|
||||
_providername = SettingService.GetSetting(settings, "ExternalLogin:ProviderName", "");
|
||||
_authority = SettingService.GetSetting(settings, "ExternalLogin:Authority", "");
|
||||
_metadataurl = SettingService.GetSetting(settings, "ExternalLogin:MetadataUrl", "");
|
||||
_authorizationurl = SettingService.GetSetting(settings, "ExternalLogin:AuthorizationUrl", "");
|
||||
_tokenurl = SettingService.GetSetting(settings, "ExternalLogin:TokenUrl", "");
|
||||
_userinfourl = SettingService.GetSetting(settings, "ExternalLogin:UserInfoUrl", "");
|
||||
_clientid = SettingService.GetSetting(settings, "ExternalLogin:ClientId", "");
|
||||
_clientsecret = SettingService.GetSetting(settings, "ExternalLogin:ClientSecret", "");
|
||||
_toggleclientsecret = SharedLocalizer["ShowPassword"];
|
||||
_scopes = SettingService.GetSetting(settings, "ExternalLogin:Scopes", "");
|
||||
_parameters = SettingService.GetSetting(settings, "ExternalLogin:Parameters", "");
|
||||
_pkce = SettingService.GetSetting(settings, "ExternalLogin:PKCE", "false");
|
||||
_redirecturl = PageState.Uri.Scheme + "://" + PageState.Alias.Name + "/signin-" + _providertype;
|
||||
_identifierclaimtype = SettingService.GetSetting(settings, "ExternalLogin:IdentifierClaimType", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier");
|
||||
_emailclaimtype = SettingService.GetSetting(settings, "ExternalLogin:EmailClaimType", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress");
|
||||
_domainfilter = SettingService.GetSetting(settings, "ExternalLogin:DomainFilter", "");
|
||||
_createusers = SettingService.GetSetting(settings, "ExternalLogin:CreateUsers", "true");
|
||||
|
||||
_secret = SettingService.GetSetting(settings, "JwtOptions:Secret", "");
|
||||
_togglesecret = SharedLocalizer["ShowPassword"];
|
||||
_issuer = SettingService.GetSetting(settings, "JwtOptions:Issuer", PageState.Uri.Scheme + "://" + PageState.Alias.Name);
|
||||
_audience = SettingService.GetSetting(settings, "JwtOptions:Audience", "");
|
||||
_lifetime = SettingService.GetSetting(settings, "JwtOptions:Lifetime", "20"); }
|
||||
}
|
||||
|
||||
private List<UserRole> Search(string search)
|
||||
private async Task LoadUsersAsync(bool load)
|
||||
{
|
||||
var results = allroles.Where(item => item.Role.Name == RoleNames.Registered || (item.Role.Name == RoleNames.Host && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)));
|
||||
if (load)
|
||||
{
|
||||
allusers = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Registered);
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
var hosts = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Host);
|
||||
allusers.AddRange(hosts);
|
||||
allusers = allusers.OrderBy(u => u.User.DisplayName).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(_search))
|
||||
users = allusers;
|
||||
if (!string.IsNullOrEmpty(_search))
|
||||
{
|
||||
results = results.Where(item =>
|
||||
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)
|
||||
item.User.Username.Contains(_search, StringComparison.OrdinalIgnoreCase) ||
|
||||
item.User.Email.Contains(_search, StringComparison.OrdinalIgnoreCase) ||
|
||||
item.User.DisplayName.Contains(_search, StringComparison.OrdinalIgnoreCase)
|
||||
)
|
||||
);
|
||||
).ToList();
|
||||
}
|
||||
return results.ToList();
|
||||
}
|
||||
|
||||
private async Task OnSearch()
|
||||
{
|
||||
userroles = Search(_search);
|
||||
await UpdateSettingsAsync();
|
||||
await UpdateUserSettingsAsync();
|
||||
await LoadUsersAsync(false);
|
||||
}
|
||||
|
||||
private async Task DeleteUser(UserRole UserRole)
|
||||
@ -95,8 +490,7 @@ else
|
||||
{
|
||||
await UserService.DeleteUserAsync(user.UserId, PageState.Site.SiteId);
|
||||
await logger.LogInformation("User Deleted {User}", UserRole.User);
|
||||
allroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId);
|
||||
userroles = Search(_search);
|
||||
await LoadUsersAsync(true);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
@ -109,17 +503,138 @@ else
|
||||
|
||||
private string settingSearch = "AU-search";
|
||||
|
||||
private async Task LoadSettingsAsync()
|
||||
private async Task LoadUserSettingsAsync()
|
||||
{
|
||||
Dictionary<string, string> settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
|
||||
_search = SettingService.GetSetting(settings, settingSearch, "");
|
||||
}
|
||||
|
||||
private async Task UpdateSettingsAsync()
|
||||
private async Task UpdateUserSettingsAsync()
|
||||
{
|
||||
Dictionary<string, string> settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
|
||||
SettingService.SetSetting(settings, settingSearch, _search);
|
||||
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
|
||||
}
|
||||
|
||||
private async Task SaveSiteSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
var site = PageState.Site;
|
||||
site.AllowRegistration = bool.Parse(_allowregistration);
|
||||
await SiteService.UpdateSiteAsync(site);
|
||||
|
||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||
settings = SettingService.SetSetting(settings, "LoginOptions:AllowSiteLogin", _allowsitelogin, false);
|
||||
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
settings = SettingService.SetSetting(settings, "LoginOptions:TwoFactor", _twofactor, false);
|
||||
settings = SettingService.SetSetting(settings, "LoginOptions:CookieName", _cookiename, true);
|
||||
|
||||
settings = SettingService.SetSetting(settings, "IdentityOptions:Password:RequiredLength", _minimumlength, true);
|
||||
settings = SettingService.SetSetting(settings, "IdentityOptions:Password:RequiredUniqueChars", _uniquecharacters, true);
|
||||
settings = SettingService.SetSetting(settings, "IdentityOptions:Password:RequireDigit", _requiredigit, true);
|
||||
settings = SettingService.SetSetting(settings, "IdentityOptions:Password:RequireUppercase", _requireupper, true);
|
||||
settings = SettingService.SetSetting(settings, "IdentityOptions:Password:RequireLowercase", _requirelower, true);
|
||||
settings = SettingService.SetSetting(settings, "IdentityOptions:Password:RequireNonAlphanumeric", _requirepunctuation, true);
|
||||
|
||||
settings = SettingService.SetSetting(settings, "IdentityOptions:Lockout:MaxFailedAccessAttempts", _maximumfailures, true);
|
||||
settings = SettingService.SetSetting(settings, "IdentityOptions:Lockout:DefaultLockoutTimeSpan", TimeSpan.FromMinutes(Convert.ToInt64(_lockoutduration)).ToString(), true);
|
||||
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:ProviderType", _providertype, false);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:ProviderName", _providername, false);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:Authority", _authority, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:MetadataUrl", _metadataurl, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:AuthorizationUrl", _authorizationurl, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:TokenUrl", _tokenurl, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:UserInfoUrl", _userinfourl, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:ClientId", _clientid, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:ClientSecret", _clientsecret, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:Scopes", _scopes, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:Parameters", _parameters, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:PKCE", _pkce, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:IdentifierClaimType", _identifierclaimtype, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:EmailClaimType", _emailclaimtype, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:DomainFilter", _domainfilter, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:CreateUsers", _createusers, true);
|
||||
|
||||
if (!string.IsNullOrEmpty(_secret) && _secret.Length < 16) _secret = (_secret + "????????????????").Substring(0, 16);
|
||||
settings = SettingService.SetSetting(settings, "JwtOptions:Secret", _secret, true);
|
||||
settings = SettingService.SetSetting(settings, "JwtOptions:Issuer", _issuer, true);
|
||||
settings = SettingService.SetSetting(settings, "JwtOptions:Audience", _audience, true);
|
||||
settings = SettingService.SetSetting(settings, "JwtOptions:Lifetime", _lifetime, true);
|
||||
}
|
||||
|
||||
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
|
||||
await SettingService.ClearSiteSettingsCacheAsync();
|
||||
|
||||
if (!string.IsNullOrEmpty(_secret))
|
||||
{
|
||||
SiteState.AuthorizationToken = await UserService.GetTokenAsync();
|
||||
}
|
||||
|
||||
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving Site Settings {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProviderTypeChanged(ChangeEventArgs e)
|
||||
{
|
||||
_providertype = (string)e.Value;
|
||||
if (string.IsNullOrEmpty(_providername))
|
||||
{
|
||||
if (_providertype == AuthenticationProviderTypes.OpenIDConnect)
|
||||
{
|
||||
_scopes = "openid,profile,email";
|
||||
_identifierclaimtype = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier";
|
||||
_emailclaimtype = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress";
|
||||
}
|
||||
else
|
||||
{
|
||||
_scopes = "";
|
||||
_identifierclaimtype = "sub";
|
||||
_emailclaimtype = "email";
|
||||
}
|
||||
}
|
||||
_redirecturl = PageState.Uri.Scheme + "://" + PageState.Alias.Name + "/signin-" + _providertype;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task CreateToken()
|
||||
{
|
||||
_token = await UserService.GetPersonalAccessTokenAsync();
|
||||
}
|
||||
|
||||
private void ToggleClientSecret()
|
||||
{
|
||||
if (_clientsecrettype == "password")
|
||||
{
|
||||
_clientsecrettype = "text";
|
||||
_toggleclientsecret = SharedLocalizer["HidePassword"];
|
||||
}
|
||||
else
|
||||
{
|
||||
_clientsecrettype = "password";
|
||||
_toggleclientsecret = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
}
|
||||
|
||||
private void ToggleSecret()
|
||||
{
|
||||
if (_secrettype == "password")
|
||||
{
|
||||
_secrettype = "text";
|
||||
_togglesecret = SharedLocalizer["HidePassword"];
|
||||
}
|
||||
else
|
||||
{
|
||||
_secrettype = "password";
|
||||
_togglesecret = SharedLocalizer["ShowPassword"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -110,8 +110,7 @@ else
|
||||
{
|
||||
try
|
||||
{
|
||||
userroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId);
|
||||
userroles = userroles.Where(item => item.UserId == userid).ToList();
|
||||
userroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, userid);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
140
Oqtane.Client/Modules/Admin/Visitors/Detail.razor
Normal file
140
Oqtane.Client/Modules/Admin/Visitors/Detail.razor
Normal file
@ -0,0 +1,140 @@
|
||||
@namespace Oqtane.Modules.Admin.Visitors
|
||||
@using System.Globalization
|
||||
@inherits ModuleBase
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IVisitorService VisitorService
|
||||
@inject IUserService UserService
|
||||
@inject IStringLocalizer<Detail> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
@if (_initialized)
|
||||
{
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="ip" HelpText="The last recorded IP address for this visitor" ResourceKey="IP">IP Address: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="ip" class="form-control" @bind="@_ip" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="language" HelpText="The last recorded language for this visitor" ResourceKey="Language">Language: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="language" class="form-control" @bind="@_language" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="useragent" HelpText="The last recorded user agent for this visitor" ResourceKey="UserAgent">User Agent: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="useragent" class="form-control" @bind="@_useragent" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="url" HelpText="The last recorded url for this visitor" ResourceKey="Url">Url: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="url" class="form-control" @bind="@_url" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="referrer" HelpText="The last recorded referrer for this visitor" ResourceKey="Referrer">Referrer: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="referrer" class="form-control" @bind="@_referrer" readonly />
|
||||
</div>
|
||||
</div>
|
||||
@if (_user != string.Empty)
|
||||
{
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="user" HelpText="The last recorded user associated with this visitor" ResourceKey="User">User: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="user" class="form-control" @bind="@_user" readonly />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="visits" HelpText="The total number of visits by this visitor all time" ResourceKey="Visits">Visits: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="visits" class="form-control" @bind="@_visits" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="visited" HelpText="The last recorded date/time when the visitor visited the site" ResourceKey="Visited">Visited: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="visited" class="form-control" @bind="@_visited" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="created" HelpText="The first recorded date/time when this visitor visited the site" ResourceKey="Created">Created: </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="created" class="form-control" @bind="@_created" readonly />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<NavLink class="btn btn-secondary" href="@CloseUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
|
||||
@code {
|
||||
private bool _initialized = false;
|
||||
private int _visitorId;
|
||||
private string _ip = string.Empty;
|
||||
private string _language = string.Empty;
|
||||
private string _useragent = string.Empty;
|
||||
private string _url = string.Empty;
|
||||
private string _referrer = string.Empty;
|
||||
private string _user = string.Empty;
|
||||
private string _visits = string.Empty;
|
||||
private string _visited = string.Empty;
|
||||
private string _created = string.Empty;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_visitorId = Int32.Parse(PageState.QueryString["id"]);
|
||||
var visitor = await VisitorService.GetVisitorAsync(_visitorId);
|
||||
if (visitor != null)
|
||||
{
|
||||
_ip = visitor.IPAddress;
|
||||
_language = visitor.Language;
|
||||
_useragent = visitor.UserAgent;
|
||||
_url = visitor.Url;
|
||||
_referrer = visitor.Referrer;
|
||||
_visits = visitor.Visits.ToString();
|
||||
_visited = visitor.VisitedOn.ToString(CultureInfo.CurrentCulture);
|
||||
_created = visitor.CreatedOn.ToString(CultureInfo.CurrentCulture);
|
||||
|
||||
if (visitor.UserId != null)
|
||||
{
|
||||
var user = await UserService.GetUserAsync(visitor.UserId.Value, PageState.Site.SiteId);
|
||||
if (user != null)
|
||||
{
|
||||
_user = user.DisplayName;
|
||||
}
|
||||
}
|
||||
_initialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Error.LoadVisitor"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Visitor {VisitorId} {Error}", _visitorId, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.LoadVisitor"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private string CloseUrl()
|
||||
{
|
||||
if (!PageState.QueryString.ContainsKey("type"))
|
||||
{
|
||||
return NavigateUrl();
|
||||
}
|
||||
else
|
||||
{
|
||||
return NavigateUrl(PageState.Page.Path, "type=" + PageState.QueryString["type"] + "&days=" + PageState.QueryString["days"] + "&page=" + PageState.QueryString["page"]);
|
||||
}
|
||||
}
|
||||
}
|
200
Oqtane.Client/Modules/Admin/Visitors/Index.razor
Normal file
200
Oqtane.Client/Modules/Admin/Visitors/Index.razor
Normal file
@ -0,0 +1,200 @@
|
||||
@namespace Oqtane.Modules.Admin.Visitors
|
||||
@inherits ModuleBase
|
||||
@inject IVisitorService VisitorService
|
||||
@inject ISiteService SiteService
|
||||
@inject ISettingService SettingService
|
||||
@inject IStringLocalizer<Index> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
@if (_visitors == null)
|
||||
{
|
||||
<p><em>@SharedLocalizer["Loading"]</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<TabStrip>
|
||||
<TabPanel Name="Visitors" Heading="Visitors" ResourceKey="Visitors">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<div class="col-sm-6">
|
||||
<select id="type" class="form-select custom-select" value="@_type" @onchange="(e => TypeChanged(e))">
|
||||
<option value="visitors">@Localizer["AllVisitors"]</option>
|
||||
<option value="users">@Localizer["UsersOnly"]</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<select id="days" class="form-select custom-select" value="@_days" @onchange="(e => DaysChanged(e))">
|
||||
<option value="1">@Localizer["PastDay"]</option>
|
||||
<option value="7">@Localizer["PastWeek"]</option>
|
||||
<option value="30">@Localizer["PastMonth"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<Pager Items="@_visitors" CurrentPage="@_page.ToString()" OnPageChange="OnPageChange">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@Localizer["IP"]</th>
|
||||
<th>@Localizer["User"]</th>
|
||||
<th>@Localizer["Language"]</th>
|
||||
<th>@Localizer["Visits"]</th>
|
||||
<th>@Localizer["Visited"]</th>
|
||||
<th>@Localizer["Created"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="Detail" Parameters="@($"id=" + context.VisitorId.ToString() + "&type=" + _type.ToString() + "&days=" + _days.ToString() + "&page=" + _page.ToString())" ResourceKey="Details" /></td>
|
||||
<td>@context.IPAddress</td>
|
||||
<td>
|
||||
@if (context.UserId != null)
|
||||
{
|
||||
@context.User.DisplayName
|
||||
}
|
||||
</td>
|
||||
<td>@context.Language</td>
|
||||
<td>@context.Visits</td>
|
||||
<td>@context.VisitedOn</td>
|
||||
<td>@context.CreatedOn</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
</TabPanel>
|
||||
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="tracking" HelpText="Specify if visitor tracking is enabled" ResourceKey="Tracking">Tracking Enabled? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="tracking" class="form-select" @bind="@_tracking" >
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="filter" HelpText="Comma delimited list of terms which may exist in IP addresses, user agents, or languages identifying visitors which should not be tracked" ResourceKey="Filter">Filter: </Label>
|
||||
<div class="col-sm-9">
|
||||
<textarea id="filter" class="form-control" @bind="@_filter" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="retention" HelpText="Number of days of visitor activity to retain" ResourceKey="Retention">Retention (Days): </Label>
|
||||
<div class="col-sm-9">
|
||||
<input id="retention" class="form-control" @bind="@_retention" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="correlation" HelpText="Indicate if new visitors to this site should be correlated based on their IP Address" ResourceKey="Correlation">Correlate Visitors? </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="correlation" class="form-select" @bind="@_correlation">
|
||||
<option value="true">@SharedLocalizer["True"]</option>
|
||||
<option value="false">@SharedLocalizer["False"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<button type="button" class="btn btn-success" @onclick="SaveSiteSettings">@SharedLocalizer["Save"]</button>
|
||||
</TabPanel>
|
||||
</TabStrip>
|
||||
}
|
||||
|
||||
@code {
|
||||
private string _type = "visitors";
|
||||
private int _days = 1;
|
||||
private int _page = 1;
|
||||
private List<Visitor> _visitors;
|
||||
private string _tracking;
|
||||
private string _filter = "";
|
||||
private string _retention = "";
|
||||
private string _correlation = "true";
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
if (PageState.QueryString.ContainsKey("type"))
|
||||
{
|
||||
_type = PageState.QueryString["type"];
|
||||
}
|
||||
if (PageState.QueryString.ContainsKey("days") && int.TryParse(PageState.QueryString["days"], out int days))
|
||||
{
|
||||
_days = days;
|
||||
}
|
||||
if (PageState.QueryString.ContainsKey("page") && int.TryParse(PageState.QueryString["page"], out int page))
|
||||
{
|
||||
_page = page;
|
||||
}
|
||||
|
||||
await GetVisitors();
|
||||
|
||||
_tracking = PageState.Site.VisitorTracking.ToString();
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
_filter = SettingService.GetSetting(settings, "VisitorFilter", Constants.DefaultVisitorFilter);
|
||||
_retention = SettingService.GetSetting(settings, "VisitorRetention", "30");
|
||||
_correlation = SettingService.GetSetting(settings, "VisitorCorrelation", "true");
|
||||
}
|
||||
|
||||
private async void TypeChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_type = e.Value.ToString();
|
||||
await GetVisitors();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error On TypeChanged");
|
||||
}
|
||||
}
|
||||
|
||||
private async void DaysChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_days = int.Parse(e.Value.ToString());
|
||||
await GetVisitors();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error On DateChanged");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GetVisitors()
|
||||
{
|
||||
_visitors = await VisitorService.GetVisitorsAsync(PageState.Site.SiteId, DateTime.UtcNow.AddDays(-_days));
|
||||
if (_type == "users")
|
||||
{
|
||||
_visitors = _visitors.Where(item => item.UserId != null).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveSiteSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
var site = PageState.Site;
|
||||
site.VisitorTracking = bool.Parse(_tracking);
|
||||
await SiteService.UpdateSiteAsync(site);
|
||||
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
settings = SettingService.SetSetting(settings, "VisitorFilter", _filter, true);
|
||||
settings = SettingService.SetSetting(settings, "VisitorRetention", _retention, true);
|
||||
settings = SettingService.SetSetting(settings, "VisitorCorrelation", _correlation, true);
|
||||
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
||||
|
||||
AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Saving Site Settings {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPageChange(int page)
|
||||
{
|
||||
_page = page;
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@
|
||||
<div class="modal-footer">
|
||||
@if (!string.IsNullOrEmpty(Action))
|
||||
{
|
||||
<button type="button" class="@Class" @onclick="Confirm">@((MarkupString)_iconSpan) @Localize(Action)</button>
|
||||
<button type="button" class="@Class" @onclick="Confirm">@((MarkupString)_iconSpan) @Text</button>
|
||||
}
|
||||
<button type="button" class="btn btn-secondary" @onclick="DisplayModal">@Localize("Cancel")</button>
|
||||
</div>
|
||||
@ -30,16 +30,17 @@
|
||||
{
|
||||
if (Disabled)
|
||||
{
|
||||
<button class="@Class" disabled>@((MarkupString)_iconSpan) @Text</button>
|
||||
<button type="button" class="@Class" disabled>@((MarkupString)_iconSpan) @Text</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button class="@Class" @onclick="DisplayModal">@((MarkupString)_iconSpan) @Text</button>
|
||||
<button type="button" class="@Class" @onclick="DisplayModal">@((MarkupString)_iconSpan) @Text</button>
|
||||
}
|
||||
}
|
||||
|
||||
@code {
|
||||
private bool _visible = false;
|
||||
private string _permissions = string.Empty;
|
||||
private bool _editmode = false;
|
||||
private bool _authorized = false;
|
||||
private string _iconSpan = string.Empty;
|
||||
@ -59,6 +60,9 @@
|
||||
[Parameter]
|
||||
public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel
|
||||
|
||||
[Parameter]
|
||||
public string Permissions { get; set; } // optional - can be used to specify a permission string
|
||||
|
||||
[Parameter]
|
||||
public string Class { get; set; } // optional
|
||||
|
||||
@ -105,6 +109,7 @@
|
||||
Header = Localize(nameof(Header), Header);
|
||||
Message = Localize(nameof(Message), Message);
|
||||
|
||||
_permissions = (string.IsNullOrEmpty(Permissions)) ? ModuleState.Permissions : Permissions;
|
||||
_authorized = IsAuthorized();
|
||||
}
|
||||
|
||||
@ -138,10 +143,10 @@
|
||||
authorized = true;
|
||||
break;
|
||||
case SecurityAccessLevel.View:
|
||||
authorized = UserSecurity.IsAuthorized(PageState.User,PermissionNames.View, ModuleState.Permissions);
|
||||
authorized = UserSecurity.IsAuthorized(PageState.User,PermissionNames.View, _permissions);
|
||||
break;
|
||||
case SecurityAccessLevel.Edit:
|
||||
authorized = UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, ModuleState.Permissions);
|
||||
authorized = UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, _permissions);
|
||||
break;
|
||||
case SecurityAccessLevel.Admin:
|
||||
authorized = UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin);
|
||||
|
@ -6,41 +6,52 @@
|
||||
{
|
||||
if (Disabled)
|
||||
{
|
||||
<button class="@_classname" style="@_style" disabled>@((MarkupString)_iconSpan) @_text</button>
|
||||
<button type="button" class="@_classname" style="@_style" disabled>@((MarkupString)_iconSpan) @_text</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
if (OnClick == null)
|
||||
{
|
||||
<NavLink class="@_classname" href="@_url" style="@_style">@((MarkupString)_iconSpan) @_text</NavLink>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="button" class="@_classname" style="@_style" onclick="@OnClick">@((MarkupString)_iconSpan) @_text</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@code {
|
||||
private string _text = string.Empty;
|
||||
private string _url = string.Empty;
|
||||
private string _parameters = string.Empty;
|
||||
private string _classname = "btn btn-primary";
|
||||
private string _style = string.Empty;
|
||||
private string _url = string.Empty;
|
||||
private string _permissions = string.Empty;
|
||||
private bool _editmode = false;
|
||||
private bool _authorized = false;
|
||||
private string _classname = "btn btn-primary";
|
||||
private string _style = string.Empty;
|
||||
private string _iconSpan = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
public string Action { get; set; } // required
|
||||
|
||||
[Parameter]
|
||||
public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel
|
||||
|
||||
[Parameter]
|
||||
public string Text { get; set; } // optional - defaults to Action if not specified
|
||||
|
||||
[Parameter]
|
||||
public string Parameters { get; set; } // optional - querystring parameter should be in the form of "id=x&name=y"
|
||||
public string Parameters { get; set; } // optional - querystring parameters should be in the form of "id=x&name=y"
|
||||
|
||||
[Parameter]
|
||||
public string Class { get; set; } // optional - defaults to primary if not specified
|
||||
public int ModuleId { get; set; } = -1; // optional - allows the link to target a specific moduleid
|
||||
|
||||
[Parameter]
|
||||
public string Style { get; set; } // optional
|
||||
public Action OnClick { get; set; } = null; // optional - executes a method in the calling component
|
||||
|
||||
[Parameter]
|
||||
public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel
|
||||
|
||||
[Parameter]
|
||||
public string Permissions { get; set; } // optional - can be used to specify a permission string
|
||||
|
||||
[Parameter]
|
||||
public bool Disabled { get; set; } // optional
|
||||
@ -48,6 +59,12 @@
|
||||
[Parameter]
|
||||
public string EditMode { get; set; } // optional - specifies if an authorized user must be in edit mode to see the action - default is false.
|
||||
|
||||
[Parameter]
|
||||
public string Class { get; set; } // optional - defaults to primary if not specified
|
||||
|
||||
[Parameter]
|
||||
public string Style { get; set; } // optional
|
||||
|
||||
[Parameter]
|
||||
public string IconName { get; set; } // optional - specifies an icon for the link - default is no icon
|
||||
|
||||
@ -96,11 +113,11 @@
|
||||
IconName = "oi oi-" + IconName;
|
||||
}
|
||||
_iconSpan = $"<span class=\"{IconName}\"></span>{(IconOnly ? "" : " ")}";
|
||||
|
||||
}
|
||||
|
||||
_permissions = (string.IsNullOrEmpty(Permissions)) ? ModuleState.Permissions : Permissions;
|
||||
_text = Localize(nameof(Text), _text);
|
||||
_url = EditUrl(Action, _parameters);
|
||||
_url = (ModuleId == -1) ? EditUrl(Action, _parameters) : EditUrl(ModuleId, Action, _parameters);
|
||||
_authorized = IsAuthorized();
|
||||
}
|
||||
|
||||
@ -136,10 +153,10 @@
|
||||
authorized = true;
|
||||
break;
|
||||
case SecurityAccessLevel.View:
|
||||
authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, ModuleState.Permissions);
|
||||
authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, _permissions);
|
||||
break;
|
||||
case SecurityAccessLevel.Edit:
|
||||
authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, ModuleState.Permissions);
|
||||
authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, _permissions);
|
||||
break;
|
||||
case SecurityAccessLevel.Admin:
|
||||
authorized = UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin);
|
||||
|
@ -35,6 +35,9 @@
|
||||
[Parameter]
|
||||
public string Style { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string DateTimeFormat { get; set; } = "MMM dd yyyy HH:mm:ss";
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
_text = string.Empty;
|
||||
@ -49,7 +52,7 @@
|
||||
|
||||
if (CreatedOn != null)
|
||||
{
|
||||
_text += $" {Localizer["On"]} <b>{CreatedOn.Value.ToString("MMM dd yyyy HH:mm:ss")}</b>";
|
||||
_text += $" {Localizer["On"]} <b>{CreatedOn.Value.ToString(DateTimeFormat)}</b>";
|
||||
}
|
||||
|
||||
_text += "</p>";
|
||||
@ -66,7 +69,7 @@
|
||||
|
||||
if (ModifiedOn != null)
|
||||
{
|
||||
_text += $" {Localizer["on"]} <b>{ModifiedOn.Value.ToString("MMM dd yyyy HH:mm:ss")}</b>";
|
||||
_text += $" {Localizer["on"]} <b>{ModifiedOn.Value.ToString(DateTimeFormat)}</b>";
|
||||
}
|
||||
|
||||
_text += "</p>";
|
||||
@ -83,7 +86,7 @@
|
||||
|
||||
if (DeletedOn != null)
|
||||
{
|
||||
_text += $" {Localizer["On"]} <b>{DeletedOn.Value.ToString("MMM dd yyyy HH:mm:ss")}</b>";
|
||||
_text += $" {Localizer["On"]} <b>{DeletedOn.Value.ToString(DateTimeFormat)}</b>";
|
||||
}
|
||||
|
||||
_text += "</p>";
|
||||
|
@ -10,24 +10,25 @@
|
||||
<div id="@Id" class="container-fluid px-0">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
@if (ShowFolders || FolderId <= 0)
|
||||
<div class="container-fluid px-0">
|
||||
@if (ShowFolders)
|
||||
{
|
||||
<div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<select class="form-select" value="@FolderId" @onchange="(e => FolderChanged(e))">
|
||||
@if (string.IsNullOrEmpty(Folder))
|
||||
{
|
||||
<option value="-1"><@Localizer["Folder.Select"]></option>
|
||||
}
|
||||
@foreach (Folder folder in _folders)
|
||||
{
|
||||
<option value="@(folder.FolderId)">@(new string('-', folder.Level * 2))@(folder.Name)</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@if (ShowFiles)
|
||||
{
|
||||
<div>
|
||||
<div class="row mt-1">
|
||||
<div class="col">
|
||||
<select class="form-select" value="@FileId" @onchange="(e => FileChanged(e))">
|
||||
<option value="-1"><@Localizer["File.Select"]></option>
|
||||
@foreach (File file in _files)
|
||||
@ -36,10 +37,12 @@
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@if (ShowUpload && _haseditpermission)
|
||||
{
|
||||
<div>
|
||||
<div class="row">
|
||||
<div class="col mt-2">
|
||||
@if (UploadMultiple)
|
||||
{
|
||||
<input type="file" id="@_fileinputid" name="file" accept="@_filter" multiple />
|
||||
@ -48,17 +51,22 @@
|
||||
{
|
||||
<input type="file" id="@_fileinputid" name="file" accept="@_filter" />
|
||||
}
|
||||
<span id="@_progressinfoid"></span><progress id="@_progressbarid" style="width: 150px; visibility: hidden;"></progress>
|
||||
<span class="float-end">
|
||||
</div>
|
||||
<div class="col mt-2 text-end">
|
||||
<button type="button" class="btn btn-success" @onclick="UploadFile">@SharedLocalizer["Upload"]</button>
|
||||
@if (ShowFiles && GetFileId() != -1)
|
||||
{
|
||||
<button type="button" class="btn btn-danger" @onclick="DeleteFile">@SharedLocalizer["Delete"]</button>
|
||||
<button type="button" class="btn btn-danger mx-1" @onclick="DeleteFile">@SharedLocalizer["Delete"]</button>
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col mt-1"><span id="@_progressinfoid" style="display: none;"></span></div>
|
||||
<div class="col text-center mt-1"><progress id="@_progressbarid" class="mt-1" style="display: none;"></progress></div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@if (_image != string.Empty)
|
||||
{
|
||||
<div class="col-auto">
|
||||
@ -68,8 +76,8 @@
|
||||
</div>
|
||||
@if (!string.IsNullOrEmpty(_message))
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col mt-2">
|
||||
<div class="row mt-1">
|
||||
<div class="col">
|
||||
<ModuleMessage Message="@_message" Type="@_messagetype" />
|
||||
</div>
|
||||
</div>
|
||||
@ -96,10 +104,16 @@
|
||||
public string Id { get; set; } // optional - for setting the id of the FileManager component for accessibility
|
||||
|
||||
[Parameter]
|
||||
public string Folder { get; set; } // optional - for setting a specific folder by default ( only relevant for host functions )
|
||||
public int FolderId { get; set; } = -1; // optional - for setting a specific default folder by folderid
|
||||
|
||||
[Parameter]
|
||||
public int FolderId { get; set; } = -1; // optional - for setting a specific folderid by default
|
||||
public string Folder { get; set; } = ""; // optional - for setting a specific default folder by folder path
|
||||
|
||||
[Parameter]
|
||||
public int FileId { get; set; } = -1; // optional - for selecting a specific file by default
|
||||
|
||||
[Parameter]
|
||||
public string Filter { get; set; } // optional - comma delimited list of file types that can be selected or uploaded ie. "jpg,gif"
|
||||
|
||||
[Parameter]
|
||||
public bool ShowFiles { get; set; } = true; // optional - for indicating whether a list of files should be displayed - default is true
|
||||
@ -114,10 +128,7 @@
|
||||
public bool ShowImage { get; set; } = true; // optional - for indicating whether an image thumbnail should be displayed - default is true
|
||||
|
||||
[Parameter]
|
||||
public int FileId { get; set; } = -1; // optional - for selecting a specific file by default
|
||||
|
||||
[Parameter]
|
||||
public string Filter { get; set; } // optional - comma delimited list of file types that can be selected or uploaded ie. "jpg,gif"
|
||||
public bool ShowSuccess { get; set; } = false; // optional - for indicating whether a success message should be displayed upon successful upload - default is false
|
||||
|
||||
[Parameter]
|
||||
public bool UploadMultiple { get; set; } = false; // optional - enable multiple file uploads - default false
|
||||
@ -138,19 +149,35 @@
|
||||
_id = Id;
|
||||
}
|
||||
|
||||
// packages folder is a framework folder for uploading installable nuget packages
|
||||
if (Folder == Constants.PackagesFolder)
|
||||
{
|
||||
ShowFiles = false;
|
||||
ShowFolders = false;
|
||||
Filter = "nupkg";
|
||||
ShowSuccess = true;
|
||||
}
|
||||
|
||||
if (!ShowFiles)
|
||||
{
|
||||
ShowImage = false;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(Folder))
|
||||
_folders = await FolderService.GetFoldersAsync(ModuleState.SiteId);
|
||||
|
||||
if (!string.IsNullOrEmpty(Folder) && Folder != Constants.PackagesFolder)
|
||||
{
|
||||
_folders = new List<Folder> { new Folder { FolderId = -1, Name = Folder } };
|
||||
FolderId = -1;
|
||||
Folder folder = await FolderService.GetFolderAsync(ModuleState.SiteId, Folder);
|
||||
if (folder != null)
|
||||
{
|
||||
FolderId = folder.FolderId;
|
||||
}
|
||||
else
|
||||
{
|
||||
_folders = await FolderService.GetFoldersAsync(ModuleState.SiteId);
|
||||
FolderId = -1;
|
||||
_message = "Folder Path " + Folder + "Does Not Exist";
|
||||
_messagetype = MessageType.Error;
|
||||
}
|
||||
}
|
||||
|
||||
if (FileId != -1)
|
||||
@ -164,6 +191,8 @@
|
||||
else
|
||||
{
|
||||
FileId = -1; // file does not exist
|
||||
_message = "FileId " + FileId.ToString() + "Does Not Exist";
|
||||
_messagetype = MessageType.Error;
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,10 +215,10 @@
|
||||
private async Task GetFiles()
|
||||
{
|
||||
_haseditpermission = false;
|
||||
if (!string.IsNullOrEmpty(Folder))
|
||||
if (Folder == Constants.PackagesFolder)
|
||||
{
|
||||
_haseditpermission = UserSecurity.IsAuthorized(PageState.User, RoleNames.Host);
|
||||
_files = await FileService.GetFilesAsync(Folder);
|
||||
_files = new List<File>();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -234,7 +263,6 @@
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Files {Error}", ex.Message);
|
||||
|
||||
_message = Localizer["Error.File.Load"];
|
||||
_messagetype = MessageType.Error;
|
||||
}
|
||||
@ -286,7 +314,7 @@
|
||||
try
|
||||
{
|
||||
string result;
|
||||
if (!string.IsNullOrEmpty(Folder))
|
||||
if (Folder == Constants.PackagesFolder)
|
||||
{
|
||||
result = await FileService.UploadFilesAsync(Folder, upload, _guid);
|
||||
}
|
||||
@ -298,9 +326,11 @@
|
||||
if (result == string.Empty)
|
||||
{
|
||||
await logger.LogInformation("File Upload Succeeded {Files}", upload);
|
||||
|
||||
if (ShowSuccess)
|
||||
{
|
||||
_message = Localizer["Success.File.Upload"];
|
||||
_messagetype = MessageType.Success;
|
||||
}
|
||||
|
||||
// set FileId to first file in upload collection
|
||||
await GetFiles();
|
||||
@ -364,5 +394,7 @@
|
||||
|
||||
public int GetFileId() => FileId;
|
||||
|
||||
public int GetFolderId() => FolderId;
|
||||
|
||||
public File GetFile() => _file;
|
||||
}
|
||||
|
@ -25,8 +25,8 @@ else
|
||||
[Parameter]
|
||||
public string HelpText { get; set; } // optional - tooltip for this label
|
||||
|
||||
private string _spanclass = "app-tooltip";
|
||||
private string _labelclass = "form-label";
|
||||
private string _spanclass;
|
||||
private string _labelclass;
|
||||
private string _helptext = string.Empty;
|
||||
|
||||
protected override void OnParametersSet()
|
||||
@ -36,11 +36,15 @@ else
|
||||
if (!string.IsNullOrEmpty(HelpText))
|
||||
{
|
||||
_helptext = Localize(nameof(HelpText), HelpText);
|
||||
_spanclass += (!string.IsNullOrEmpty(Class)) ? " " + Class : "";
|
||||
_labelclass = "form-label";
|
||||
|
||||
var spanclass = (!string.IsNullOrEmpty(Class)) ? " " + Class : "";
|
||||
_spanclass = "app-tooltip" + spanclass;
|
||||
}
|
||||
else
|
||||
{
|
||||
_labelclass += (!string.IsNullOrEmpty(Class)) ? " " + Class : "";
|
||||
var labelclass = (!string.IsNullOrEmpty(Class)) ? " " + Class : "";
|
||||
_labelclass = "form-label" + labelclass;
|
||||
}
|
||||
|
||||
var text = Localize("Text", String.Empty);
|
||||
|
@ -13,6 +13,9 @@ namespace Oqtane.Modules.Controls
|
||||
[Parameter]
|
||||
public string ResourceKey { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string ResourceType { get; set; }
|
||||
|
||||
protected bool IsLocalizable { get; private set; }
|
||||
|
||||
protected string Localize(string name) => _localizer?[name] ?? name;
|
||||
@ -50,9 +53,14 @@ namespace Oqtane.Modules.Controls
|
||||
{
|
||||
IsLocalizable = false;
|
||||
|
||||
if (!String.IsNullOrEmpty(ResourceKey) && ModuleState?.ModuleType != null)
|
||||
if (string.IsNullOrEmpty(ResourceType))
|
||||
{
|
||||
var moduleType = Type.GetType(ModuleState.ModuleType);
|
||||
ResourceType = ModuleState?.ModuleType;
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(ResourceKey) && !string.IsNullOrEmpty(ResourceType))
|
||||
{
|
||||
var moduleType = Type.GetType(ResourceType);
|
||||
if (moduleType != null)
|
||||
{
|
||||
using (var scope = ServiceActivator.GetScope())
|
||||
|
@ -4,13 +4,13 @@
|
||||
|
||||
@if (ItemList != null)
|
||||
{
|
||||
@if (Toolbar == "Top" && _pages > 0 && Items.Count() > _maxItems)
|
||||
@if ((Toolbar == "Top" || Toolbar == "Both") && _pages > 0 && Items.Count() > _maxItems)
|
||||
{
|
||||
<ul class="pagination justify-content-center my-2">
|
||||
<li class="page-item@((_page > 1) ? "" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
@if (_pages > _displayPages)
|
||||
@if (_pages > _displayPages && _displayPages > 1)
|
||||
{
|
||||
<li class="page-item@((_page > _displayPages) ? "" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => SkipPages("back"))><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
||||
@ -38,7 +38,7 @@
|
||||
<li class="page-item@((_page < _pages) ? "" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => NavigateToPage("next"))><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
@if (_pages > _displayPages)
|
||||
@if (_pages > _displayPages && _displayPages > 1)
|
||||
{
|
||||
<li class="page-item@((_endPage < _pages) ? "" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => SkipPages("forward"))><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
||||
@ -48,20 +48,21 @@
|
||||
<a class="page-link" @onclick=@(async () => UpdateList(_pages))><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link">Page @_page of @_pages</a>
|
||||
<a class="page-link" style="white-space: nowrap;">Page @_page of @_pages</a>
|
||||
</li>
|
||||
</ul>
|
||||
}
|
||||
@if (Format == "Table" && Row != null)
|
||||
{
|
||||
<div class="table-responsive">
|
||||
<table class="@Class">
|
||||
<thead>
|
||||
<tr>@Header</tr>
|
||||
<tr class="@RowClass">@Header</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in ItemList)
|
||||
{
|
||||
<tr>@Row(item)</tr>
|
||||
<tr class="@RowClass">@Row(item)</tr>
|
||||
@if (Detail != null)
|
||||
{
|
||||
<tr>@Detail(item)</tr>
|
||||
@ -69,45 +70,55 @@
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
@if (Format == "Grid" && Row != null)
|
||||
{
|
||||
int count = 0;
|
||||
int rows = 0;
|
||||
int cols = 0;
|
||||
if (ItemList != null)
|
||||
{
|
||||
if (_columns == 0)
|
||||
{
|
||||
count = ItemList.Count();
|
||||
rows = 1;
|
||||
cols = count;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = (int)Math.Ceiling(ItemList.Count() / (decimal)_columns) * _columns;
|
||||
rows = count / _columns;
|
||||
cols = _columns;
|
||||
}
|
||||
}
|
||||
<div class="@Class">
|
||||
@if (Header != null)
|
||||
@for (int row = 0; row < rows; row++)
|
||||
{
|
||||
<div class="row"><div class="col">@Header</div></div>
|
||||
}
|
||||
@for (int row = 0; row < (count / _columns); row++)
|
||||
{
|
||||
<div class="row">
|
||||
@for (int col = 0; col < _columns; col++)
|
||||
<div class="@RowClass">
|
||||
@for (int col = 0; col < cols; col++)
|
||||
{
|
||||
int index = (row * _columns) + col;
|
||||
if (index < ItemList.Count())
|
||||
{
|
||||
<div class="col">@Row(ItemList.ElementAt(index))</div>
|
||||
<div class="@ColumnClass">@Row(ItemList.ElementAt(index))</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="col"> </div>
|
||||
<div> </div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@if (Toolbar == "Bottom" && _pages > 0 && Items.Count() > _maxItems)
|
||||
@if ((Toolbar == "Bottom" || Toolbar == "Both") && _pages > 0 && Items.Count() > _maxItems)
|
||||
{
|
||||
<ul class="pagination justify-content-center my-2">
|
||||
<li class="page-item@((_page > 1) ? "" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
@if (_pages > _displayPages)
|
||||
@if (_pages > _displayPages && _displayPages > 1)
|
||||
{
|
||||
<li class="page-item@((_page > _displayPages) ? "" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => SkipPages("back"))><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
||||
@ -135,7 +146,7 @@
|
||||
<li class="page-item@((_page < _pages) ? "" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => NavigateToPage("next"))><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
@if (_pages > _displayPages)
|
||||
@if (_pages > _displayPages && _displayPages > 1)
|
||||
{
|
||||
<li class="page-item@((_endPage < _pages) ? "" : " disabled")">
|
||||
<a class="page-link" @onclick=@(async () => SkipPages("forward"))><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
||||
@ -145,7 +156,7 @@
|
||||
<a class="page-link" @onclick=@(async () => UpdateList(_pages))><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
||||
</li>
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link">Page @_page of @_pages</a>
|
||||
<a class="page-link" style="white-space: nowrap;">Page @_page of @_pages</a>
|
||||
</li>
|
||||
</ul>
|
||||
}
|
||||
@ -158,19 +169,19 @@
|
||||
private int _displayPages = 5;
|
||||
private int _startPage = 0;
|
||||
private int _endPage = 0;
|
||||
private int _columns = 1;
|
||||
private int _columns = 0;
|
||||
|
||||
[Parameter]
|
||||
public string Format { get; set; } // Table or Grid
|
||||
|
||||
[Parameter]
|
||||
public string Toolbar { get; set; } // Top or Bottom
|
||||
public string Toolbar { get; set; } // Top, Bottom or Both
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment Header { get; set; } = null;
|
||||
public RenderFragment Header { get; set; } = null; // only applicable to Table layouts
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment<TableItem> Row { get; set; } = null;
|
||||
public RenderFragment<TableItem> Row { get; set; } = null; // required
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment<TableItem> Detail { get; set; } = null; // only applicable to Table layouts
|
||||
@ -182,16 +193,25 @@
|
||||
public string PageSize { get; set; } // number of items to display on a page
|
||||
|
||||
[Parameter]
|
||||
public string Columns { get; set; } // only applicable to Grid layouts
|
||||
public string Columns { get; set; } // only applicable to Grid layouts - default is zero indicating use responsive behavior
|
||||
|
||||
[Parameter]
|
||||
public string CurrentPage { get; set; } // optional property to set the initial page to display
|
||||
public string CurrentPage { get; set; } // sets the initial page to display
|
||||
|
||||
[Parameter]
|
||||
public string DisplayPages { get; set; } // maximum number of page numbers to display for user selection
|
||||
|
||||
[Parameter]
|
||||
public string Class { get; set; }
|
||||
public string Class { get; set; } // class for the containing element - ie. <table> for Table or <div> for Grid
|
||||
|
||||
[Parameter]
|
||||
public string RowClass { get; set; } // class for row element - ie. <tr> for Table or <div> for Grid
|
||||
|
||||
[Parameter]
|
||||
public string ColumnClass { get; set; } // class for column element - only applicable to Grid format
|
||||
|
||||
[Parameter]
|
||||
public Action<int> OnPageChange { get; set; } // a method to be executed in the calling component when the page changes
|
||||
|
||||
private IEnumerable<TableItem> ItemList { get; set; }
|
||||
|
||||
@ -215,7 +235,31 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
Class = "container";
|
||||
Class = "container-fluid";
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(RowClass))
|
||||
{
|
||||
if (Format == "Table")
|
||||
{
|
||||
RowClass = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
RowClass = "row";
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(ColumnClass))
|
||||
{
|
||||
if (Format == "Table")
|
||||
{
|
||||
ColumnClass = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
ColumnClass = "col";
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,6 +310,7 @@
|
||||
{
|
||||
_endPage = _pages;
|
||||
}
|
||||
OnPageChange?.Invoke(_page);
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
|
@ -129,6 +129,10 @@
|
||||
|
||||
_roles = await RoleService.GetRolesAsync(ModuleState.SiteId);
|
||||
_roles.Insert(0, new Role { Name = RoleNames.Everyone });
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
_roles.Add(new Role { Name = RoleNames.Host });
|
||||
}
|
||||
|
||||
_permissions = new List<PermissionString>();
|
||||
|
||||
@ -186,9 +190,7 @@
|
||||
}
|
||||
|
||||
private bool GetPermissionDisabled(string roleName)
|
||||
=> roleName == RoleNames.Admin
|
||||
? true
|
||||
: false;
|
||||
=> (roleName == RoleNames.Admin && !UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) ? true : false;
|
||||
|
||||
private async Task AddUser()
|
||||
{
|
||||
@ -250,9 +252,19 @@
|
||||
for (int i = 0; i < _permissions.Count; i++)
|
||||
{
|
||||
permission = _permissions[i];
|
||||
List<string> ids = permission.Permissions.Split(';').ToList();
|
||||
List<string> ids = permission.Permissions.Split(';', StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
ids.Remove("!" + RoleNames.Everyone); // remove deny all users
|
||||
ids.Remove("!" + RoleNames.Registered); // remove deny registered users
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
ids.Remove("!" + RoleNames.Admin); // remove deny administrators
|
||||
ids.Remove("!" + RoleNames.Host); // remove deny host users
|
||||
if (!ids.Contains(RoleNames.Host) && !ids.Contains(RoleNames.Admin))
|
||||
{
|
||||
// add administrators role if host user role is not assigned
|
||||
ids.Add(RoleNames.Admin);
|
||||
}
|
||||
}
|
||||
permission.Permissions = string.Join(";", ids.ToArray());
|
||||
_permissions[i] = permission;
|
||||
}
|
||||
|
@ -71,11 +71,11 @@
|
||||
</div>
|
||||
@if (ReadOnly)
|
||||
{
|
||||
<textarea class="form-control" placeholder="@Placeholder" @bind="@_content" rows="10" readonly></textarea>
|
||||
<textarea class="form-control" placeholder="@Placeholder" @bind="@_rawhtml" rows="10" readonly></textarea>
|
||||
}
|
||||
else
|
||||
{
|
||||
<textarea class="form-control" placeholder="@Placeholder" @bind="@_content" rows="10"></textarea>
|
||||
<textarea class="form-control" placeholder="@Placeholder" @bind="@_rawhtml" rows="10"></textarea>
|
||||
}
|
||||
</TabPanel>
|
||||
</TabStrip>
|
||||
@ -87,8 +87,10 @@
|
||||
private ElementReference _toolBar;
|
||||
private bool _filemanagervisible = false;
|
||||
private FileManager _fileManager;
|
||||
private string _content = string.Empty;
|
||||
private string _original = string.Empty;
|
||||
private string _richhtml = string.Empty;
|
||||
private string _originalrichhtml = string.Empty;
|
||||
private string _rawhtml = string.Empty;
|
||||
private string _originalrawhtml = string.Empty;
|
||||
private string _message = string.Empty;
|
||||
|
||||
[Parameter]
|
||||
@ -115,24 +117,26 @@
|
||||
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
{
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill1.3.6.min.js" },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill.min.js" },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-blot-formatter.min.js" },
|
||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.js" }
|
||||
};
|
||||
|
||||
protected override void OnInitialized()
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
_content = Content; // raw HTML
|
||||
_richhtml = Content;
|
||||
_rawhtml = Content;
|
||||
_originalrawhtml = _rawhtml; // preserve for comparison later
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
|
||||
if (firstRender)
|
||||
{
|
||||
await interop.CreateEditor(
|
||||
_editorElement,
|
||||
_toolBar,
|
||||
@ -141,12 +145,14 @@
|
||||
Theme,
|
||||
DebugLevel);
|
||||
|
||||
await interop.LoadEditorContent(_editorElement, Content);
|
||||
await interop.LoadEditorContent(_editorElement, _richhtml);
|
||||
|
||||
_content = Content; // raw HTML
|
||||
|
||||
// preserve a copy of the rich text content ( Quill sanitizes content so we need to retrieve it from the editor )
|
||||
_original = await interop.GetHtml(_editorElement);
|
||||
// preserve a copy of the rich text content (Quill sanitizes content so we need to retrieve it from the editor)
|
||||
_originalrichhtml = await interop.GetHtml(_editorElement);
|
||||
}
|
||||
else
|
||||
{
|
||||
await interop.LoadEditorContent(_editorElement, _richhtml);
|
||||
}
|
||||
}
|
||||
|
||||
@ -157,34 +163,40 @@
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
public async Task RefreshRichText()
|
||||
public void RefreshRichText()
|
||||
{
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
await interop.LoadEditorContent(_editorElement, _content);
|
||||
_richhtml = _rawhtml;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
public async Task RefreshRawHtml()
|
||||
{
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
_content = await interop.GetHtml(_editorElement);
|
||||
_rawhtml = await interop.GetHtml(_editorElement);
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
public async Task<string> GetHtml()
|
||||
{
|
||||
// get rich text content
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
string content = await interop.GetHtml(_editorElement);
|
||||
|
||||
if (_original != content)
|
||||
// evaluate raw html content as first priority
|
||||
if (_rawhtml != _originalrawhtml)
|
||||
{
|
||||
// rich text content has changed - return it
|
||||
return content;
|
||||
return _rawhtml;
|
||||
}
|
||||
else
|
||||
{
|
||||
// return raw html content
|
||||
return _content;
|
||||
// return rich text content if it has changed
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
var richhtml = await interop.GetHtml(_editorElement);
|
||||
if (richhtml != _originalrichhtml)
|
||||
{
|
||||
return richhtml;
|
||||
}
|
||||
else
|
||||
{
|
||||
// return original raw html content
|
||||
return _originalrawhtml;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -211,23 +223,4 @@
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
// other rich text editor methods which can be used by developers
|
||||
public async Task<string> GetText()
|
||||
{
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
return await interop.GetText(_editorElement);
|
||||
}
|
||||
|
||||
public async Task<string> GetContent()
|
||||
{
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
return await interop.GetContent(_editorElement);
|
||||
}
|
||||
|
||||
public async Task EnableEditor(bool mode)
|
||||
{
|
||||
var interop = new RichTextEditorInterop(JSRuntime);
|
||||
await interop.EnableEditor(_editorElement, mode);
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ else
|
||||
|
||||
if (string.IsNullOrEmpty(Heading))
|
||||
{
|
||||
Name = Localize(nameof(Name), Name);
|
||||
Heading = Localize(nameof(Name), Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -43,16 +43,12 @@
|
||||
[Parameter]
|
||||
public bool Refresh { get; set; } // optional - used in scenarios where TabPanels are added/removed dynamically within a parent form. ActiveTab may need to be reset as well when this property is used.
|
||||
|
||||
protected override void OnInitialized()
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
if (PageState.QueryString.ContainsKey("tab"))
|
||||
{
|
||||
ActiveTab = PageState.QueryString["tab"];
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
if (_tabPanels == null || Refresh)
|
||||
{
|
||||
_tabPanels = new List<TabPanel>();
|
||||
|
@ -9,9 +9,12 @@
|
||||
@inject IStringLocalizer<Edit> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
@if (_content != null)
|
||||
{
|
||||
<TabStrip>
|
||||
<TabPanel Name="Edit" Heading="Edit" ResourceKey="Edit">
|
||||
@if (_content != null)
|
||||
{
|
||||
<RichTextEditor Content="@_content" AllowFileManagement="@_allowfilemanagement" @ref="@RichTextEditorHtml"></RichTextEditor>
|
||||
<br />
|
||||
<button type="button" class="btn btn-success" @onclick="SaveContent">@SharedLocalizer["Save"]</button>
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
@if (!string.IsNullOrEmpty(_content))
|
||||
@ -20,7 +23,28 @@
|
||||
<br />
|
||||
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon"></AuditInfo>
|
||||
}
|
||||
}
|
||||
}
|
||||
</TabPanel>
|
||||
<TabPanel Name="Versions" Heading="Versions" ResourceKey="Versions">
|
||||
<Pager Items="@_htmltexts">
|
||||
<Header>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th style="width: 1px;"> </th>
|
||||
<th>@SharedLocalizer["CreatedOn"]</th>
|
||||
<th>@SharedLocalizer["CreatedBy"]</th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionLink Action="View" Security="SecurityAccessLevel.Edit" OnClick="@(async () => await View(context))" ResourceKey="View" /></td>
|
||||
<td><ActionDialog Header="Restore Version" Message="@string.Format(Localizer["Confirm.Restore"], context.CreatedOn)" Action="Restore" Security="SecurityAccessLevel.Edit" Class="btn btn-success" OnClick="@(async () => await Restore(context))" ResourceKey="Restore" /></td>
|
||||
<td><ActionDialog Header="Delete Version" Message="@string.Format(Localizer["Confirm.Delete"], context.CreatedOn)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await Delete(context))" ResourceKey="Delete" /></td>
|
||||
<td>@context.CreatedOn</td>
|
||||
<td>@context.CreatedBy</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
@((MarkupString)_view)
|
||||
</TabPanel>
|
||||
</TabStrip>
|
||||
|
||||
@code {
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||
@ -28,10 +52,10 @@
|
||||
public override string Title => "Edit Html/Text";
|
||||
|
||||
public override List<Resource> Resources => new List<Resource>()
|
||||
{
|
||||
{
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" },
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill1.3.6.bubble.css" },
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill1.3.6.snow.css" }
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill.bubble.css" },
|
||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill.snow.css" }
|
||||
};
|
||||
|
||||
private RichTextEditor RichTextEditorHtml;
|
||||
@ -41,13 +65,25 @@
|
||||
private DateTime _createdon;
|
||||
private string _modifiedby;
|
||||
private DateTime _modifiedon;
|
||||
private List<Models.HtmlText> _htmltexts;
|
||||
private string _view = "";
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_allowfilemanagement = bool.Parse(SettingService.GetSetting(ModuleState.Settings, "AllowFileManagement", "true"));
|
||||
await LoadContent();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Content {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Content.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadContent()
|
||||
{
|
||||
var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
|
||||
if (htmltext != null)
|
||||
{
|
||||
@ -62,12 +98,11 @@
|
||||
{
|
||||
_content = string.Empty;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "An Error Occurred Loading Html/Text Content. " + ex.Message);
|
||||
AddModuleMessage(ex.Message, MessageType.Error);
|
||||
}
|
||||
|
||||
_htmltexts = await HtmlTextService.GetHtmlTextsAsync(ModuleState.ModuleId);
|
||||
_htmltexts = _htmltexts.OrderByDescending(item => item.CreatedOn).ToList();
|
||||
|
||||
_view = "";
|
||||
}
|
||||
|
||||
private async Task SaveContent()
|
||||
@ -77,21 +112,12 @@
|
||||
|
||||
try
|
||||
{
|
||||
var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
|
||||
if (htmltext != null)
|
||||
{
|
||||
htmltext.Content = content;
|
||||
await HtmlTextService.UpdateHtmlTextAsync(htmltext);
|
||||
}
|
||||
else
|
||||
{
|
||||
htmltext = new HtmlText();
|
||||
var htmltext = new HtmlText();
|
||||
htmltext.ModuleId = ModuleState.ModuleId;
|
||||
htmltext.Content = content;
|
||||
await HtmlTextService.AddHtmlTextAsync(htmltext);
|
||||
}
|
||||
|
||||
await logger.LogInformation("Html/Text Content Saved {HtmlText}", htmltext);
|
||||
await logger.LogInformation("Content Saved {HtmlText}", htmltext);
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -100,4 +126,69 @@
|
||||
AddModuleMessage(Localizer["Error.Content.Save"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task View(Models.HtmlText htmltext)
|
||||
{
|
||||
try
|
||||
{
|
||||
htmltext = await HtmlTextService.GetHtmlTextAsync(htmltext.HtmlTextId, htmltext.ModuleId);
|
||||
if (htmltext != null)
|
||||
{
|
||||
_view = htmltext.Content;
|
||||
_view = Utilities.FormatContent(_view, PageState.Alias, "render");
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Viewing Content {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Content.View"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Restore(Models.HtmlText htmltext)
|
||||
{
|
||||
try
|
||||
{
|
||||
htmltext = await HtmlTextService.GetHtmlTextAsync(htmltext.HtmlTextId, ModuleState.ModuleId);
|
||||
if (htmltext != null)
|
||||
{
|
||||
var content = htmltext.Content;
|
||||
htmltext = new HtmlText();
|
||||
htmltext.ModuleId = ModuleState.ModuleId;
|
||||
htmltext.Content = content;
|
||||
await HtmlTextService.AddHtmlTextAsync(htmltext);
|
||||
await logger.LogInformation("Content Restored {HtmlText}", htmltext);
|
||||
AddModuleMessage(Localizer["Message.Content.Restored"], MessageType.Success);
|
||||
await LoadContent();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Restoring Content {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Content.Restore"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Delete(Models.HtmlText htmltext)
|
||||
{
|
||||
try
|
||||
{
|
||||
htmltext = await HtmlTextService.GetHtmlTextAsync(htmltext.HtmlTextId, ModuleState.ModuleId);
|
||||
if (htmltext != null)
|
||||
{
|
||||
await HtmlTextService.DeleteHtmlTextAsync(htmltext.HtmlTextId, htmltext.ModuleId);
|
||||
await logger.LogInformation("Content Deleted {HtmlText}", htmltext);
|
||||
AddModuleMessage(Localizer["Message.Content.Deleted"], MessageType.Success);
|
||||
await LoadContent();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Deleting Content {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Content.Delete"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,8 +35,8 @@
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "An Error Occurred Loading Html/Text Content. " + ex.Message);
|
||||
AddModuleMessage(ex.Message, MessageType.Error);
|
||||
await logger.LogError(ex, "Error Loading Content {Error}", ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Content.Load"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Models;
|
||||
|
||||
namespace Oqtane.Modules.HtmlText
|
||||
{
|
||||
[PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")]
|
||||
public class ModuleInfo : IModule
|
||||
{
|
||||
public ModuleDefinition ModuleDefinition => new ModuleDefinition
|
||||
|
@ -1,34 +1,43 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Services;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Modules.HtmlText.Services
|
||||
{
|
||||
[PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")]
|
||||
public class HtmlTextService : ServiceBase, IHtmlTextService, IService
|
||||
{
|
||||
public HtmlTextService(HttpClient http, SiteState siteState) : base(http, siteState) {}
|
||||
|
||||
private string ApiUrl => CreateApiUrl("HtmlText");
|
||||
|
||||
public async Task<List<Models.HtmlText>> GetHtmlTextsAsync(int moduleId)
|
||||
{
|
||||
return await GetJsonAsync<List<Models.HtmlText>>(CreateAuthorizationPolicyUrl($"{ApiUrl}?moduleid={moduleId}", EntityNames.Module, moduleId));
|
||||
}
|
||||
|
||||
public async Task<Models.HtmlText> GetHtmlTextAsync(int moduleId)
|
||||
{
|
||||
return await GetJsonAsync<Models.HtmlText>(CreateAuthorizationPolicyUrl($"{ApiUrl}/{moduleId}", EntityNames.Module, moduleId));
|
||||
}
|
||||
|
||||
public async Task<Models.HtmlText> GetHtmlTextAsync(int htmlTextId, int moduleId)
|
||||
{
|
||||
return await GetJsonAsync<Models.HtmlText>(CreateAuthorizationPolicyUrl($"{ApiUrl}/{htmlTextId}/{moduleId}", EntityNames.Module, moduleId));
|
||||
}
|
||||
|
||||
public async Task AddHtmlTextAsync(Models.HtmlText htmlText)
|
||||
{
|
||||
await PostJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}", EntityNames.Module, htmlText.ModuleId), htmlText);
|
||||
}
|
||||
|
||||
public async Task UpdateHtmlTextAsync(Models.HtmlText htmlText)
|
||||
public async Task DeleteHtmlTextAsync(int htmlTextId, int moduleId)
|
||||
{
|
||||
await PutJsonAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{htmlText.HtmlTextId}", EntityNames.Module, htmlText.ModuleId), htmlText);
|
||||
}
|
||||
|
||||
public async Task DeleteHtmlTextAsync(int moduleId)
|
||||
{
|
||||
await DeleteAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{moduleId}", EntityNames.Module, moduleId));
|
||||
await DeleteAsync(CreateAuthorizationPolicyUrl($"{ApiUrl}/{htmlTextId}/{moduleId}", EntityNames.Module, moduleId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Oqtane.Modules.HtmlText.Models;
|
||||
using Oqtane.Documentation;
|
||||
|
||||
namespace Oqtane.Modules.HtmlText.Services
|
||||
{
|
||||
[PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")]
|
||||
public interface IHtmlTextService
|
||||
{
|
||||
Task<Models.HtmlText> GetHtmlTextAsync(int ModuleId);
|
||||
Task<List<Models.HtmlText>> GetHtmlTextsAsync(int moduleId);
|
||||
|
||||
Task<Models.HtmlText> GetHtmlTextAsync(int moduleId);
|
||||
|
||||
Task<Models.HtmlText> GetHtmlTextAsync(int htmlTextId, int moduleId);
|
||||
|
||||
Task AddHtmlTextAsync(Models.HtmlText htmltext);
|
||||
|
||||
Task UpdateHtmlTextAsync(Models.HtmlText htmltext);
|
||||
|
||||
Task DeleteHtmlTextAsync(int ModuleId);
|
||||
Task DeleteHtmlTextAsync(int htmlTextId, int moduleId);
|
||||
}
|
||||
}
|
||||
|
@ -5,9 +5,9 @@
|
||||
@inject IStringLocalizer<Settings> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
<div class="container">
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="files" ResourceKey="Allow File Management" HelpText="Specify If Editors Can Upload and Select Files">Allow File Management: </Label>
|
||||
<Label Class="col-sm-3" For="files" ResourceKey="AllowFileManagement" ResourceType="@resourceType" HelpText="Specify If Editors Can Upload and Select Files">Allow File Management: </Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="files" class="form-select" @bind="@_allowfilemanagement">
|
||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
||||
@ -15,9 +15,10 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
@code {
|
||||
private string resourceType = "Oqtane.Modules.HtmlText.Settings, Oqtane.Client"; // for localization
|
||||
private string _allowfilemanagement;
|
||||
|
||||
protected override void OnInitialized()
|
||||
@ -36,7 +37,7 @@
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = ModuleState.Settings;
|
||||
var settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId);
|
||||
settings = SettingService.SetSetting(settings, "AllowFileManagement", _allowfilemanagement);
|
||||
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
|
||||
}
|
||||
@ -45,4 +46,4 @@
|
||||
ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,8 +30,8 @@ namespace Oqtane.Modules
|
||||
[CascadingParameter]
|
||||
protected Module ModuleState { get; set; }
|
||||
|
||||
[CascadingParameter]
|
||||
protected ModuleInstance ModuleInstance { get; set; }
|
||||
[Parameter]
|
||||
public ModuleInstance ModuleInstance { get; set; }
|
||||
|
||||
// optional interface properties
|
||||
public virtual SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.View; } set { } } // default security
|
||||
@ -53,9 +53,9 @@ namespace Oqtane.Modules
|
||||
if (Resources != null && Resources.Exists(item => item.ResourceType == ResourceType.Script))
|
||||
{
|
||||
var scripts = new List<object>();
|
||||
foreach (Resource resource in Resources.Where(item => item.ResourceType == ResourceType.Script && item.Declaration != ResourceDeclaration.Global))
|
||||
foreach (Resource resource in Resources.Where(item => item.ResourceType == ResourceType.Script))
|
||||
{
|
||||
scripts.Add(new { href = resource.Url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "" });
|
||||
scripts.Add(new { href = resource.Url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", es6module = resource.ES6Module });
|
||||
}
|
||||
if (scripts.Any())
|
||||
{
|
||||
@ -134,9 +134,19 @@ namespace Oqtane.Modules
|
||||
return Utilities.ContentUrl(PageState.Alias, fileid, asAttachment);
|
||||
}
|
||||
|
||||
public string ImageUrl(int fileid, int width, int height)
|
||||
{
|
||||
return ImageUrl(fileid, width, height, "");
|
||||
}
|
||||
|
||||
public string ImageUrl(int fileid, int width, int height, string mode)
|
||||
{
|
||||
return Utilities.ImageUrl(PageState.Alias, fileid, width, height, mode);
|
||||
return ImageUrl(fileid, width, height, mode, "", "", 0, false);
|
||||
}
|
||||
|
||||
public string ImageUrl(int fileid, int width, int height, string mode, string position, string background, int rotate, bool recreate)
|
||||
{
|
||||
return Utilities.ImageUrl(PageState.Alias, fileid, width, height, mode, position, background, rotate, recreate);
|
||||
}
|
||||
|
||||
public virtual Dictionary<string, string> GetUrlParameters(string parametersTemplate = "")
|
||||
|
@ -1,11 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RazorLangVersion>3.0</RazorLangVersion>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Version>2.3.1</Version>
|
||||
<Version>3.1.2</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -13,7 +13,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v2.3.1</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.2</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RootNamespace>Oqtane</RootNamespace>
|
||||
@ -22,23 +22,19 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.4" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.4" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="5.0.4" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="6.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="6.0.3" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="6.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="5.0.4" />
|
||||
<PackageReference Include="System.Net.Http.Json" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="6.0.3" />
|
||||
<PackageReference Include="System.Net.Http.Json" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Oqtane.Shared\Oqtane.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Resources\" />
|
||||
<Folder Include="Resources\Themes\Controls\Theme\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<TrimmerRootAssembly Include="System.Runtime" />
|
||||
<TrimmerRootAssembly Include="System.Linq.Parallel" />
|
||||
|
@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||
using Microsoft.AspNetCore.Localization;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.JSInterop;
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Modules;
|
||||
using Oqtane.Services;
|
||||
using Oqtane.Shared;
|
||||
@ -19,16 +20,17 @@ using Oqtane.UI;
|
||||
|
||||
namespace Oqtane.Client
|
||||
{
|
||||
[PrivateApi("Mark Entry-Program as private, since it's not very useful in the public docs")]
|
||||
public class Program
|
||||
{
|
||||
public static async Task Main(string[] args)
|
||||
{
|
||||
var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
||||
builder.RootComponents.Add<App>("app");
|
||||
|
||||
var httpClient = new HttpClient {BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)};
|
||||
|
||||
builder.Services.AddSingleton(httpClient);
|
||||
builder.Services.AddHttpClient(); // IHttpClientFactory for calling remote services via RemoteServiceBase
|
||||
|
||||
builder.Services.AddOptions();
|
||||
|
||||
// Register localization services
|
||||
|
@ -153,4 +153,22 @@
|
||||
<data name="Integrated" xml:space="preserve">
|
||||
<value>Integrated</value>
|
||||
</data>
|
||||
<data name="Encryption,Text" xml:space="preserve">
|
||||
<value>Encryption:</value>
|
||||
</data>
|
||||
<data name="Encryption.HelpText" xml:space="preserve">
|
||||
<value>Specify if you are using an encrypted database connection. It is highly recommended to use encryption in a production environment.</value>
|
||||
</data>
|
||||
<data name="Self Signed" xml:space="preserve">
|
||||
<value>Self Signed</value>
|
||||
</data>
|
||||
<data name="TrustServerCertificate.HelpText" xml:space="preserve">
|
||||
<value>Specify the type of certificate you are using for encryption</value>
|
||||
</data>
|
||||
<data name="TrustServerCertificate.Text" xml:space="preserve">
|
||||
<value>Trust Server Certificate:</value>
|
||||
</data>
|
||||
<data name="Verifiable" xml:space="preserve">
|
||||
<value>Verifiable</value>
|
||||
</data>
|
||||
</root>
|
@ -130,10 +130,13 @@
|
||||
<value>Install Now</value>
|
||||
</data>
|
||||
<data name="Error.DbConfig.Load" xml:space="preserve">
|
||||
<value>Error loading Database Configuration Control</value>
|
||||
<value>Error Loading Database Configuration Control</value>
|
||||
</data>
|
||||
<data name="Message.Require.DbInfo" xml:space="preserve">
|
||||
<value>Please Enter All Required Fields. Ensure Passwords Match And Are Greater Than 5 Characters In Length. Ensure Email Address Provided Is Valid.</value>
|
||||
<value>Please Enter All Required Fields. Ensure Passwords Match And Email Address Provided Is Valid.</value>
|
||||
</data>
|
||||
<data name="Message.Password.Invalid" xml:space="preserve">
|
||||
<value>The Password Provided Does Not Meet The Password Policy. Please Verify The Minimum Password Length And Complexity Requirements.</value>
|
||||
</data>
|
||||
<data name="Register" xml:space="preserve">
|
||||
<value>Please Register Me For Major Product Updates And Security Bulletins</value>
|
||||
|
@ -159,4 +159,10 @@
|
||||
<data name="Type" xml:space="preserve">
|
||||
<value>Type</value>
|
||||
</data>
|
||||
<data name="DeleteFile.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="UploadFiles.Text" xml:space="preserve">
|
||||
<value>Upload Files</value>
|
||||
</data>
|
||||
</root>
|
@ -186,4 +186,10 @@
|
||||
<data name="NextExecution.Text" xml:space="preserve">
|
||||
<value>Next Execution: </value>
|
||||
</data>
|
||||
<data name="Week(s)" xml:space="preserve">
|
||||
<value>Week(s)</value>
|
||||
</data>
|
||||
<data name="Once" xml:space="preserve">
|
||||
<value>Execute Once</value>
|
||||
</data>
|
||||
</root>
|
@ -133,19 +133,16 @@
|
||||
<value>Every</value>
|
||||
</data>
|
||||
<data name="Minute" xml:space="preserve">
|
||||
<value>Minute</value>
|
||||
<value>Minute(s)</value>
|
||||
</data>
|
||||
<data name="Hour" xml:space="preserve">
|
||||
<value>Hour</value>
|
||||
<value>Hour(s)</value>
|
||||
</data>
|
||||
<data name="Day" xml:space="preserve">
|
||||
<value>Day</value>
|
||||
<value>Day(s)</value>
|
||||
</data>
|
||||
<data name="Month" xml:space="preserve">
|
||||
<value>Month</value>
|
||||
</data>
|
||||
<data name="s" xml:space="preserve">
|
||||
<value>s</value>
|
||||
<value>Month(s)</value>
|
||||
</data>
|
||||
<data name="Error.Job.Delete" xml:space="preserve">
|
||||
<value>Error Deleting Job</value>
|
||||
@ -168,4 +165,31 @@
|
||||
<data name="Stop" xml:space="preserve">
|
||||
<value>Stop</value>
|
||||
</data>
|
||||
<data name="DeleteJob.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="EditJob.Text" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
<data name="JobLog.Text" xml:space="preserve">
|
||||
<value>Log</value>
|
||||
</data>
|
||||
<data name="Error.Job.Start" xml:space="preserve">
|
||||
<value>An error occurred when starting the job</value>
|
||||
</data>
|
||||
<data name="Error.Job.Stop" xml:space="preserve">
|
||||
<value>An error occurred when stopping the job</value>
|
||||
</data>
|
||||
<data name="Message.Job.Start" xml:space="preserve">
|
||||
<value>The process responsible for executing this job has been started. The next execution will be based on the schedule criteria for the job.</value>
|
||||
</data>
|
||||
<data name="Message.Job.Stop" xml:space="preserve">
|
||||
<value>The process responsible for executing this job has been stopped. In order to restart the process you will need to use the Start button or restart the application.</value>
|
||||
</data>
|
||||
<data name="Week" xml:space="preserve">
|
||||
<value>Week(s)</value>
|
||||
</data>
|
||||
<data name="Once" xml:space="preserve">
|
||||
<value>Execute Once</value>
|
||||
</data>
|
||||
</root>
|
@ -153,4 +153,19 @@
|
||||
<data name="Search.NoResults" xml:space="preserve">
|
||||
<value>No Translations Match The Criteria Provided Or Package Service Is Disabled</value>
|
||||
</data>
|
||||
<data name="Download.Heading" xml:space="preserve">
|
||||
<value>Download</value>
|
||||
</data>
|
||||
<data name="LanguageUpload.HelpText" xml:space="preserve">
|
||||
<value>Upload one or more translations. Once they are uploaded click Install to complete the installation.</value>
|
||||
</data>
|
||||
<data name="LanguageUpload.Text" xml:space="preserve">
|
||||
<value>Upload Language</value>
|
||||
</data>
|
||||
<data name="Manage.Heading" xml:space="preserve">
|
||||
<value>Manage</value>
|
||||
</data>
|
||||
<data name="Upload.Heading" xml:space="preserve">
|
||||
<value>Upload</value>
|
||||
</data>
|
||||
</root>
|
@ -141,4 +141,7 @@
|
||||
<data name="Default" xml:space="preserve">
|
||||
<value>Default</value>
|
||||
</data>
|
||||
<data name="DeleteLanguage.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
</root>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
@ -117,25 +117,112 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="RememberMe" xml:space="preserve">
|
||||
<value>Remember Me?</value>
|
||||
</data>
|
||||
<data name="ForgotPassword" xml:space="preserve">
|
||||
<value>Forgot Password</value>
|
||||
</data>
|
||||
<data name="Success.Account.Verified" xml:space="preserve">
|
||||
<value>User Account Verified Successfully. You Can Now Login With Your Username And Password Below.</value>
|
||||
</data>
|
||||
<data name="Message.Account.NotVerfied" xml:space="preserve">
|
||||
<data name="Message.Account.NotVerified" xml:space="preserve">
|
||||
<value>User Account Could Not Be Verified. Please Contact Your Administrator For Further Instructions.</value>
|
||||
</data>
|
||||
<data name="Success.Account.Linked" xml:space="preserve">
|
||||
<value>User Account Linked Successfully. You Can Now Login With Your External Login Below.</value>
|
||||
</data>
|
||||
<data name="Message.Account.NotLinked" xml:space="preserve">
|
||||
<value>External Login Could Not Be Linked. Please Contact Your Administrator For Further Instructions.</value>
|
||||
</data>
|
||||
<data name="Error.Login.Fail" xml:space="preserve">
|
||||
<value>Login Failed. Please Remember That Passwords Are Case Sensitive And User Accounts Require Verification When They Are Initially Created So You May Wish To Check Your Email.</value>
|
||||
<value>Login Failed. Please Remember That Passwords Are Case Sensitive. If You Have Attempted To Sign In Multiple Times Unsuccessfully, Your Account Will Be Locked Out For A Period Of Time. Note That User Accounts Require Verification When They Are Initially Created So You May Wish To Check Your Email If You Are A New User.</value>
|
||||
</data>
|
||||
<data name="Message.Required.UserInfo" xml:space="preserve">
|
||||
<value>Please Provide Your Username And Password</value>
|
||||
<value>Please Provide All Required Fields</value>
|
||||
</data>
|
||||
<data name="Info.SignedIn" xml:space="preserve">
|
||||
<value>You Are Already Signed In</value>
|
||||
</data>
|
||||
<data name="Message.ForgotPassword" xml:space="preserve">
|
||||
<value>Please Enter The Username Related To Your Account And Then Select The Forgot Password Option Again</value>
|
||||
</data>
|
||||
<data name="Message.ForgotUser" xml:space="preserve">
|
||||
<value>Please Check The Email Address Associated To Your User Account For A Password Reset Notification</value>
|
||||
</data>
|
||||
<data name="Message.UserDoesNotExist" xml:space="preserve">
|
||||
<value>User Does Not Exist</value>
|
||||
</data>
|
||||
<data name="Code.HelpText" xml:space="preserve">
|
||||
<value>Please Enter The Secure Verification Code Which Was Sent To You By Email.</value>
|
||||
</data>
|
||||
<data name="Code.Placeholder" xml:space="preserve">
|
||||
<value>Verification Code</value>
|
||||
</data>
|
||||
<data name="Code.Text" xml:space="preserve">
|
||||
<value>Verification Code:</value>
|
||||
</data>
|
||||
<data name="Error.TwoFactor.Fail" xml:space="preserve">
|
||||
<value>Verification Failed. Please Ensure You Entered The Code Exactly In The Form Provided In Your Email. If You Wish To Request A New Verification Code Please Select The Cancel Option And Sign In Again. </value>
|
||||
</data>
|
||||
<data name="Message.TwoFactor" xml:space="preserve">
|
||||
<value>A Secure Verification Code Has Been Sent To Your Email Address. Please Enter The Code That You Received. If You Do Not Receive The Code Or You Have Lost Access To Your Email, Please Contact Your Administrator.</value>
|
||||
</data>
|
||||
<data name="Password.HelpText" xml:space="preserve">
|
||||
<value>Please Enter The Password Related To Your Account. Remember That Passwords Are Case Sensitive. If You Attempt Unsuccessfully To Log In To Your Account Multiple Times, You Will Be Locked Out For A Period Of Time.</value>
|
||||
</data>
|
||||
<data name="Password.Placeholder" xml:space="preserve">
|
||||
<value>Password</value>
|
||||
</data>
|
||||
<data name="Password.Text" xml:space="preserve">
|
||||
<value>Password:</value>
|
||||
</data>
|
||||
<data name="Remember.HelpText" xml:space="preserve">
|
||||
<value>Specify If You Would Like To Be Signed Back In Automatically The Next Time You Visit This Site</value>
|
||||
</data>
|
||||
<data name="Remember.Text" xml:space="preserve">
|
||||
<value>Remember Me?</value>
|
||||
</data>
|
||||
<data name="Username.HelpText" xml:space="preserve">
|
||||
<value>Please Enter The Username Related To Your Account</value>
|
||||
</data>
|
||||
<data name="Username.Placeholder" xml:space="preserve">
|
||||
<value>Username</value>
|
||||
</data>
|
||||
<data name="Username.Text" xml:space="preserve">
|
||||
<value>Username:</value>
|
||||
</data>
|
||||
<data name="Use" xml:space="preserve">
|
||||
<value>Use</value>
|
||||
</data>
|
||||
<data name="Error.LoadLogin" xml:space="preserve">
|
||||
<value>Error Loading Login</value>
|
||||
</data>
|
||||
<data name="Error.Login" xml:space="preserve">
|
||||
<value>Error Performing Login</value>
|
||||
</data>
|
||||
<data name="Error.ResetPassword" xml:space="preserve">
|
||||
<value>Error Resetting Password</value>
|
||||
</data>
|
||||
<data name="ExternalLoginStatus.DuplicateEmail" xml:space="preserve">
|
||||
<value>Multiple User Accounts Already Exist With The Email Address Of Your External Login. Please Contact Your Administrator For Further Instructions.</value>
|
||||
</data>
|
||||
<data name="ExternalLoginStatus.InvalidEmail" xml:space="preserve">
|
||||
<value>The External Login Provider Did Not Provide A Valid Email Address For Your Account. Please Contact Your Administrator For Further Instructions.</value>
|
||||
</data>
|
||||
<data name="ExternalLoginStatus.ProviderKeyMismatch" xml:space="preserve">
|
||||
<value>An Error Occurred Verifying Your External Login. Please Contact Your Administrator For Further Instructions.</value>
|
||||
</data>
|
||||
<data name="ExternalLoginStatus.UserDoesNotExist" xml:space="preserve">
|
||||
<value>A User Account Matching The Email Address Of Your External Login Does Not Exist. Please Contact Your Administrator For Further Instructions.</value>
|
||||
</data>
|
||||
<data name="ExternalLoginStatus.UserNotCreated" xml:space="preserve">
|
||||
<value>A User Account Could Not Be Created For Your External Login. Please Contact Your Administrator For Further Instructions.</value>
|
||||
</data>
|
||||
<data name="ExternalLoginStatus.VerificationRequired" xml:space="preserve">
|
||||
<value>In Order To Link Your External Login With Your User Account You Must Verify Your Identity. Please Check Your Email For Further Instructions.</value>
|
||||
</data>
|
||||
<data name="ExternalLoginStatus.AccessDenied" xml:space="preserve">
|
||||
<value>Your External Login Was Denied Access. Please Contact Your Administrator For Further Instructions.</value>
|
||||
</data>
|
||||
<data name="ExternalLoginStatus.RemoteFailure" xml:space="preserve">
|
||||
<value>Your External Login Failed. Please Contact Your Administrator For Further Instructions.</value>
|
||||
</data>
|
||||
</root>
|
@ -189,4 +189,25 @@
|
||||
<data name="Create" xml:space="preserve">
|
||||
<value>Create</value>
|
||||
</data>
|
||||
<data name="LogDetails.Text" xml:space="preserve">
|
||||
<value>Details</value>
|
||||
</data>
|
||||
<data name="Error.SaveSiteSettings" xml:space="preserve">
|
||||
<value>Error Saving Settings</value>
|
||||
</data>
|
||||
<data name="Events.Heading" xml:space="preserve">
|
||||
<value>Events</value>
|
||||
</data>
|
||||
<data name="Retention.HelpText" xml:space="preserve">
|
||||
<value>Number of days of events to retain</value>
|
||||
</data>
|
||||
<data name="Retention.Text" xml:space="preserve">
|
||||
<value>Retention (Days):</value>
|
||||
</data>
|
||||
<data name="Settings.Heading" xml:space="preserve">
|
||||
<value>Settings</value>
|
||||
</data>
|
||||
<data name="Success.SaveSiteSettings" xml:space="preserve">
|
||||
<value>Settings Saved Successfully</value>
|
||||
</data>
|
||||
</root>
|
@ -138,4 +138,10 @@
|
||||
<data name="Search.NoResults" xml:space="preserve">
|
||||
<value>No Modules Match The Criteria Provided Or Package Service Is Disabled</value>
|
||||
</data>
|
||||
<data name="Download.Heading" xml:space="preserve">
|
||||
<value>Download</value>
|
||||
</data>
|
||||
<data name="Upload.Heading" xml:space="preserve">
|
||||
<value>Upload</value>
|
||||
</data>
|
||||
</root>
|
@ -183,7 +183,16 @@
|
||||
<data name="Runtimes.Text" xml:space="preserve">
|
||||
<value>Runtimes: </value>
|
||||
</data>
|
||||
<data name="Definition.Name" xml:space="preserve">
|
||||
<data name="Definition.Heading" xml:space="preserve">
|
||||
<value>Definition</value>
|
||||
</data>
|
||||
<data name="Information.Heading" xml:space="preserve">
|
||||
<value>Information</value>
|
||||
</data>
|
||||
<data name="Permissions.Heading" xml:space="preserve">
|
||||
<value>Permissions</value>
|
||||
</data>
|
||||
<data name="Information.Text" xml:space="preserve">
|
||||
<value>Information</value>
|
||||
</data>
|
||||
</root>
|
@ -144,4 +144,10 @@
|
||||
<data name="DeleteModule.Header" xml:space="preserve">
|
||||
<value>Delete Module</value>
|
||||
</data>
|
||||
<data name="InUse" xml:space="preserve">
|
||||
<value>In Use</value>
|
||||
</data>
|
||||
<data name="EditModule.Text" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
</root>
|
@ -181,7 +181,7 @@
|
||||
<value>Select whether the page is part of the site navigation or hidden</value>
|
||||
</data>
|
||||
<data name="UrlPath.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter a url path for this page (ie. home ). If you do not provide a url path, the page name will be used.</value>
|
||||
<value>Optionally enter a url path for this page (ie. home ). If you do not provide a url path, the page name will be used. If the page is intended to be the root path specify '/'.</value>
|
||||
</data>
|
||||
<data name="Redirect.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter a url which this page should redirect to when a user navigates to it</value>
|
||||
@ -231,4 +231,10 @@
|
||||
<data name="Message.Page.Deleted" xml:space="preserve">
|
||||
<value>A page with path {0} already exists for the selected parent page in the Recycle Bin. Either recover the page or remove from the Recycle Bin and create it again.</value>
|
||||
</data>
|
||||
<data name="Meta.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter meta tags (in exactly the form you want them to be included in the page output).</value>
|
||||
</data>
|
||||
<data name="Meta.Text" xml:space="preserve">
|
||||
<value>Meta:</value>
|
||||
</data>
|
||||
</root>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
@ -169,7 +169,7 @@
|
||||
<value>Select whether the page is part of the site navigation or hidden</value>
|
||||
</data>
|
||||
<data name="UrlPath.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter a url path for this page (ie. home ). If you do not provide a url path, the page name will be used.</value>
|
||||
<value>Optionally enter a url path for this page (ie. home ). If you do not provide a url path, the page name will be used. If the page is intended to be the root path specify '/'.</value>
|
||||
</data>
|
||||
<data name="Redirect.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter a url which this page should redirect to when a user navigates to it</value>
|
||||
@ -210,7 +210,7 @@
|
||||
<data name="Personalizable.Text" xml:space="preserve">
|
||||
<value>Personalizable? </value>
|
||||
</data>
|
||||
<data name="Appearance.Name" xml:space="preserve">
|
||||
<data name="Appearance.Heading" xml:space="preserve">
|
||||
<value>Appearance</value>
|
||||
</data>
|
||||
<data name="ThisLocation.Keep" xml:space="preserve">
|
||||
@ -231,4 +231,43 @@
|
||||
<data name="Move.Text" xml:space="preserve">
|
||||
<value>Move: </value>
|
||||
</data>
|
||||
<data name="ModuleDefinition" xml:space="preserve">
|
||||
<value>Module</value>
|
||||
</data>
|
||||
<data name="ModuleTitle" xml:space="preserve">
|
||||
<value>Title</value>
|
||||
</data>
|
||||
<data name="PageModules.Heading" xml:space="preserve">
|
||||
<value>Modules</value>
|
||||
</data>
|
||||
<data name="ModuleSettings.Text" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
<data name="DeleteModule.Header" xml:space="preserve">
|
||||
<value>Delete Module</value>
|
||||
</data>
|
||||
<data name="DeleteModule.Message" xml:space="preserve">
|
||||
<value>Are You Sure You Wish To Delete This Module?</value>
|
||||
</data>
|
||||
<data name="DeleteModule.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="Permissions.Heading" xml:space="preserve">
|
||||
<value>Permissions</value>
|
||||
</data>
|
||||
<data name="ThemeSettings.Heading" xml:space="preserve">
|
||||
<value>Theme Settings</value>
|
||||
</data>
|
||||
<data name="Clickable.HelpText" xml:space="preserve">
|
||||
<value>Select whether the link in the site navigation is enabled or disabled</value>
|
||||
</data>
|
||||
<data name="Clickable.Text" xml:space="preserve">
|
||||
<value>Clickable?</value>
|
||||
</data>
|
||||
<data name="Meta.HelpText" xml:space="preserve">
|
||||
<value>Optionally enter meta tags (in exactly the form you want them to be included in the page output).</value>
|
||||
</data>
|
||||
<data name="Meta.Text" xml:space="preserve">
|
||||
<value>Meta:</value>
|
||||
</data>
|
||||
</root>
|
@ -129,4 +129,13 @@
|
||||
<data name="DeletePage.Header" xml:space="preserve">
|
||||
<value>Delete Page</value>
|
||||
</data>
|
||||
<data name="Browse" xml:space="preserve">
|
||||
<value>Browse</value>
|
||||
</data>
|
||||
<data name="DeletePage.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="EditPage.Text" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
</root>
|
@ -132,4 +132,10 @@
|
||||
<data name="DeleteProfile.Header" xml:space="preserve">
|
||||
<value>Delete Profile</value>
|
||||
</data>
|
||||
<data name="DeleteProfile.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="EditProfile.Text" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
</root>
|
@ -177,7 +177,10 @@
|
||||
<data name="DeleteAllModules.Message" xml:space="preserve">
|
||||
<value>Are You Sure You Wish To Permanently Delete All Modules?</value>
|
||||
</data>
|
||||
<data name="Pages.Name" xml:space="preserve">
|
||||
<data name="Pages.Heading" xml:space="preserve">
|
||||
<value>Pages</value>
|
||||
</data>
|
||||
<data name="Modules.Heading" xml:space="preserve">
|
||||
<value>Modules</value>
|
||||
</data>
|
||||
</root>
|
@ -117,22 +117,37 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Password.Confirm" xml:space="preserve">
|
||||
<value>Confirm Password:</value>
|
||||
</data>
|
||||
<data name="Message.Password.NoMatch" xml:space="preserve">
|
||||
<value>Passwords Entered Do Not Match</value>
|
||||
</data>
|
||||
<data name="Message.Required.UserInfo" xml:space="preserve">
|
||||
<value>You Must Provide A Username, Password, and Email Address</value>
|
||||
<value>You Must Provide The Password And Confirmation</value>
|
||||
</data>
|
||||
<data name="Password.Reset" xml:space="preserve">
|
||||
<value>Reset Password</value>
|
||||
</data>
|
||||
<data name="Error.Password.ResetInfo" xml:space="preserve">
|
||||
<value>Error Resetting User Password. Please Ensure Password Meets Complexity Requirements.</value>
|
||||
<value>Error Resetting User Password. Please Ensure The Request To Reset Your Password Was Made Within The Past 24 Hours And The New Password Meets The Complexity Requirements.</value>
|
||||
</data>
|
||||
<data name="Error.Password.Reset" xml:space="preserve">
|
||||
<value>Error Resetting User Password</value>
|
||||
</data>
|
||||
<data name="Confirm.Text" xml:space="preserve">
|
||||
<value>Confirm:</value>
|
||||
</data>
|
||||
<data name="Conform.HelpText" xml:space="preserve">
|
||||
<value>Enter the password again. It must exactly match the password entered above.</value>
|
||||
</data>
|
||||
<data name="Password.HelpText" xml:space="preserve">
|
||||
<value>The new password. It must satisfy complexity rules for the site.</value>
|
||||
</data>
|
||||
<data name="Password.Text" xml:space="preserve">
|
||||
<value>Password:</value>
|
||||
</data>
|
||||
<data name="Username.HelpText" xml:space="preserve">
|
||||
<value>Your username will be populated from the link you received in the password reset notification</value>
|
||||
</data>
|
||||
<data name="Username.Text" xml:space="preserve">
|
||||
<value>Username:</value>
|
||||
</data>
|
||||
</root>
|
@ -129,4 +129,13 @@
|
||||
<data name="DeleteRole.Header" xml:space="preserve">
|
||||
<value>Delete Role</value>
|
||||
</data>
|
||||
<data name="DeleteRole.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="Edit.Text" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
<data name="Users.Text" xml:space="preserve">
|
||||
<value>Users</value>
|
||||
</data>
|
||||
</root>
|
@ -129,9 +129,6 @@
|
||||
<data name="DefaultContainer.Text" xml:space="preserve">
|
||||
<value>Default Container: </value>
|
||||
</data>
|
||||
<data name="Appearance.Name" xml:space="preserve">
|
||||
<value>Appearance</value>
|
||||
</data>
|
||||
<data name="DefaultAdminContainer" xml:space="preserve">
|
||||
<value>Default Admin Container</value>
|
||||
</data>
|
||||
@ -145,7 +142,7 @@
|
||||
<value>Site Settings Saved</value>
|
||||
</data>
|
||||
<data name="Message.Aliases.Taken" xml:space="preserve">
|
||||
<value>An Alias Specified Has Already Been Used For Another Site</value>
|
||||
<value>The Default Alias Has Not Been Specified Or An Alias Was Specified That Has Already Been Used For Another Site</value>
|
||||
</data>
|
||||
<data name="Message.Required.SiteName" xml:space="preserve">
|
||||
<value>You Must Provide A Site Name, Alias, And Default Theme/Container</value>
|
||||
@ -169,10 +166,7 @@
|
||||
<value>Enter the tenant for the site</value>
|
||||
</data>
|
||||
<data name="Aliases.HelpText" xml:space="preserve">
|
||||
<value>Enter the alias for the server</value>
|
||||
</data>
|
||||
<data name="AllowRegistration.HelpText" xml:space="preserve">
|
||||
<value>Do you want the users to be able to register for an account on the site</value>
|
||||
<value>The aliases for the site. An alias can be a domain name (www.site.com) or a virtual folder (ie. www.site.com/folder). If a site has multiple aliases they should be separated by commas.</value>
|
||||
</data>
|
||||
<data name="IsDeleted.HelpText" xml:space="preserve">
|
||||
<value>Is this site deleted?</value>
|
||||
@ -225,11 +219,8 @@
|
||||
<data name="Aliases.Text" xml:space="preserve">
|
||||
<value>Aliases: </value>
|
||||
</data>
|
||||
<data name="AllowRegistration.Text" xml:space="preserve">
|
||||
<value>Allow User Registration? </value>
|
||||
</data>
|
||||
<data name="IsDeleted.Text" xml:space="preserve">
|
||||
<value>Is Deleted? </value>
|
||||
<value>Deleted? </value>
|
||||
</data>
|
||||
<data name="Logo.Text" xml:space="preserve">
|
||||
<value>Logo: </value>
|
||||
@ -282,4 +273,55 @@
|
||||
<data name="Theme.Select" xml:space="preserve">
|
||||
<value>Select Theme</value>
|
||||
</data>
|
||||
<data name="Hosting.Heading" xml:space="preserve">
|
||||
<value>Hosting Model</value>
|
||||
</data>
|
||||
<data name="Prerender.HelpText" xml:space="preserve">
|
||||
<value>Specifies if the site should be prerendered (for search crawlers, etc...)</value>
|
||||
</data>
|
||||
<data name="Prerender.Text" xml:space="preserve">
|
||||
<value>Prerender? </value>
|
||||
</data>
|
||||
<data name="Runtime.HelpText" xml:space="preserve">
|
||||
<value>The Blazor runtime hosting model</value>
|
||||
</data>
|
||||
<data name="Runtime.Text" xml:space="preserve">
|
||||
<value>Runtime: </value>
|
||||
</data>
|
||||
<data name="Browse" xml:space="preserve">
|
||||
<value>Browse</value>
|
||||
</data>
|
||||
<data name="TenantInformation.Heading" xml:space="preserve">
|
||||
<value>Tenant Information</value>
|
||||
</data>
|
||||
<data name="PWASettings.Heading" xml:space="preserve">
|
||||
<value>PWA Settings</value>
|
||||
</data>
|
||||
<data name="SMTPSettings.Heading" xml:space="preserve">
|
||||
<value>SMTP Settings</value>
|
||||
</data>
|
||||
<data name="ConnectionString.Text" xml:space="preserve">
|
||||
<value>Connection:</value>
|
||||
</data>
|
||||
<data name="Database.Text" xml:space="preserve">
|
||||
<value>Database:</value>
|
||||
</data>
|
||||
<data name="ConnectionString.HelpText" xml:space="preserve">
|
||||
<value>The connection information for the database</value>
|
||||
</data>
|
||||
<data name="Database.HelpText" xml:space="preserve">
|
||||
<value>The database for the tenant</value>
|
||||
</data>
|
||||
<data name="DeleteSite.Text" xml:space="preserve">
|
||||
<value>Delete Site</value>
|
||||
</data>
|
||||
<data name="DefaultAlias.HelpText" xml:space="preserve">
|
||||
<value>The default alias for the site. Requests for non-default aliases will be redirected to the default alias.</value>
|
||||
</data>
|
||||
<data name="DefaultAlias.Text" xml:space="preserve">
|
||||
<value>Default Alias: </value>
|
||||
</data>
|
||||
<data name="Aliases.Heading" xml:space="preserve">
|
||||
<value>Aliases</value>
|
||||
</data>
|
||||
</root>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
@ -217,10 +217,10 @@
|
||||
<value>Enter the password for the integrated security</value>
|
||||
</data>
|
||||
<data name="HostUsername.HelpText" xml:space="preserve">
|
||||
<value>Enter a valid host username</value>
|
||||
<value>Enter the username of an existing host user</value>
|
||||
</data>
|
||||
<data name="HostPassword.HelpText" xml:space="preserve">
|
||||
<value>Enter a valid host password</value>
|
||||
<value>Enter the password of an existing host user</value>
|
||||
</data>
|
||||
<data name="Name.Text" xml:space="preserve">
|
||||
<value>Site Name: </value>
|
||||
@ -258,4 +258,16 @@
|
||||
<data name="Error.Database.LoadConfig" xml:space="preserve">
|
||||
<value>Error loading Database Configuration Control</value>
|
||||
</data>
|
||||
<data name="Prerender.HelpText" xml:space="preserve">
|
||||
<value>Specifies if the site should be prerendered (for search crawlers, etc...)</value>
|
||||
</data>
|
||||
<data name="Prerender.Text" xml:space="preserve">
|
||||
<value>Prerender? </value>
|
||||
</data>
|
||||
<data name="Runtime.HelpText" xml:space="preserve">
|
||||
<value>The Blazor runtime hosting model</value>
|
||||
</data>
|
||||
<data name="Runtime.Text" xml:space="preserve">
|
||||
<value>Runtime: </value>
|
||||
</data>
|
||||
</root>
|
@ -123,38 +123,32 @@
|
||||
<data name="FrameworkVersion.HelpText" xml:space="preserve">
|
||||
<value>Framework Version</value>
|
||||
</data>
|
||||
<data name="BlazorRuntime.HelpText" xml:space="preserve">
|
||||
<value>Blazor Runtime (Server or WebAssembly)</value>
|
||||
</data>
|
||||
<data name="CLRVersion.HelpText" xml:space="preserve">
|
||||
<value>Common Language Runtime Version</value>
|
||||
</data>
|
||||
<data name="OSVersion.HelpText" xml:space="preserve">
|
||||
<value>Operating System Version</value>
|
||||
</data>
|
||||
<data name="ServerPath.HelpText" xml:space="preserve">
|
||||
<value>Server Path</value>
|
||||
<data name="ContentRootPath.HelpText" xml:space="preserve">
|
||||
<value>Server Root Path</value>
|
||||
</data>
|
||||
<data name="ServerTime.HelpText" xml:space="preserve">
|
||||
<value>Server Time</value>
|
||||
<value>Server Date/Time (in UTC)</value>
|
||||
</data>
|
||||
<data name="FrameworkVersion.Text" xml:space="preserve">
|
||||
<value>Framework Version: </value>
|
||||
</data>
|
||||
<data name="BlazorRuntime.Text" xml:space="preserve">
|
||||
<value>Blazor Runtime: </value>
|
||||
</data>
|
||||
<data name="CLRVersion.Text" xml:space="preserve">
|
||||
<value>CLR Version: </value>
|
||||
</data>
|
||||
<data name="OSVersion.Text" xml:space="preserve">
|
||||
<value>OS Version: </value>
|
||||
</data>
|
||||
<data name="ServerPath.Text" xml:space="preserve">
|
||||
<value>Server Path: </value>
|
||||
<data name="ContentRootPath.Text" xml:space="preserve">
|
||||
<value>Root Path: </value>
|
||||
</data>
|
||||
<data name="ServerTime.Text" xml:space="preserve">
|
||||
<value>Server Time: </value>
|
||||
<value>Server Date/Time: </value>
|
||||
</data>
|
||||
<data name="RestartApplication.Header" xml:space="preserve">
|
||||
<value>Restart Application</value>
|
||||
@ -165,18 +159,9 @@
|
||||
<data name="Error.UpdateConfig" xml:space="preserve">
|
||||
<value>An Error Occurred Updating The Configuration</value>
|
||||
</data>
|
||||
<data name="Server" xml:space="preserve">
|
||||
<value>Server</value>
|
||||
</data>
|
||||
<data name="ServerPrerendered" xml:space="preserve">
|
||||
<value>ServerPrerendered</value>
|
||||
</data>
|
||||
<data name="Success.UpdateConfig.Restart" xml:space="preserve">
|
||||
<value>Configuration Updated. Please Select Restart Application For These Changes To Be Activated.</value>
|
||||
</data>
|
||||
<data name="WebAssembly" xml:space="preserve">
|
||||
<value>WebAssembly</value>
|
||||
</data>
|
||||
<data name="InstallationId.Text" xml:space="preserve">
|
||||
<value>Installation ID: </value>
|
||||
</data>
|
||||
@ -219,10 +204,10 @@
|
||||
<data name="Critical" xml:space="preserve">
|
||||
<value>Critical</value>
|
||||
</data>
|
||||
<data name="Info" xml:space="preserve">
|
||||
<data name="Info.Heading" xml:space="preserve">
|
||||
<value>Info</value>
|
||||
</data>
|
||||
<data name="Options" xml:space="preserve">
|
||||
<data name="Options.Heading" xml:space="preserve">
|
||||
<value>Options</value>
|
||||
</data>
|
||||
<data name="Register" xml:space="preserve">
|
||||
@ -243,4 +228,46 @@
|
||||
<data name="Swagger.Text" xml:space="preserve">
|
||||
<value>Swagger Enabled?</value>
|
||||
</data>
|
||||
<data name="RestartApplication.Text" xml:space="preserve">
|
||||
<value>Restart Application</value>
|
||||
</data>
|
||||
<data name="None" xml:space="preserve">
|
||||
<value>None</value>
|
||||
</data>
|
||||
<data name="NotificationLevel.HelpText" xml:space="preserve">
|
||||
<value>The Minimum Logging Level For Which Notifications Should Be Sent To Host Users.</value>
|
||||
</data>
|
||||
<data name="NotificationLevel.Text" xml:space="preserve">
|
||||
<value>Notification Level:</value>
|
||||
</data>
|
||||
<data name="IPAddress.HelpText" xml:space="preserve">
|
||||
<value>Server IP Address</value>
|
||||
</data>
|
||||
<data name="IPAddress.Text" xml:space="preserve">
|
||||
<value>IP Address:</value>
|
||||
</data>
|
||||
<data name="MachineName.HelpText" xml:space="preserve">
|
||||
<value>Server Machine Name</value>
|
||||
</data>
|
||||
<data name="MachineName.Text" xml:space="preserve">
|
||||
<value>Machine Name:</value>
|
||||
</data>
|
||||
<data name="TickCount.HelpText" xml:space="preserve">
|
||||
<value>Amount Of Time The Service Has Been Available And Operational</value>
|
||||
</data>
|
||||
<data name="TickCount.Text" xml:space="preserve">
|
||||
<value>Service Uptime:</value>
|
||||
</data>
|
||||
<data name="WebRootPath.HelpText" xml:space="preserve">
|
||||
<value>Server Web Root Path</value>
|
||||
</data>
|
||||
<data name="WebRootPath.Text" xml:space="preserve">
|
||||
<value>Web Path:</value>
|
||||
</data>
|
||||
<data name="WorkingSet.HelpText" xml:space="preserve">
|
||||
<value>Memory Allocation Of Service (in MB)</value>
|
||||
</data>
|
||||
<data name="WorkingSet.Text" xml:space="preserve">
|
||||
<value>Memory Allocation:</value>
|
||||
</data>
|
||||
</root>
|
@ -138,4 +138,10 @@
|
||||
<data name="DeleteTheme.Header" xml:space="preserve">
|
||||
<value>Delete Theme</value>
|
||||
</data>
|
||||
<data name="CreateTheme.Text" xml:space="preserve">
|
||||
<value>Create Theme</value>
|
||||
</data>
|
||||
<data name="ViewTheme.Text" xml:space="preserve">
|
||||
<value>View</value>
|
||||
</data>
|
||||
</root>
|
@ -135,4 +135,10 @@
|
||||
<data name="Success.Framework.Download" xml:space="preserve">
|
||||
<value>Framework Downloaded Successfully... Please Select Upgrade To Complete the Process</value>
|
||||
</data>
|
||||
<data name="Download.Heading" xml:space="preserve">
|
||||
<value>Download</value>
|
||||
</data>
|
||||
<data name="Upload.Heading" xml:space="preserve">
|
||||
<value>Upload</value>
|
||||
</data>
|
||||
</root>
|
144
Oqtane.Client/Resources/Modules/Admin/UrlMappings/Add.resx
Normal file
144
Oqtane.Client/Resources/Modules/Admin/UrlMappings/Add.resx
Normal file
@ -0,0 +1,144 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="MappedUrl.Text" xml:space="preserve">
|
||||
<value>Redirect To:</value>
|
||||
</data>
|
||||
<data name="MappedUrl.HelpText" xml:space="preserve">
|
||||
<value>A relative or absolute Url where the user will be redirected</value>
|
||||
</data>
|
||||
<data name="Url.HelpText" xml:space="preserve">
|
||||
<value>An absolute Url identifying a path to a specific page in the site</value>
|
||||
</data>
|
||||
<data name="Url.Text" xml:space="preserve">
|
||||
<value>Url:</value>
|
||||
</data>
|
||||
<data name="Error.SaveUrlMapping" xml:space="preserve">
|
||||
<value>Error Saving Url Mapping</value>
|
||||
</data>
|
||||
<data name="Message.InfoRequired" xml:space="preserve">
|
||||
<value>Please Provide All Required Information</value>
|
||||
</data>
|
||||
<data name="Message.DuplicateUrlMapping" xml:space="preserve">
|
||||
<value>The Url and Redirect To cannot be the same</value>
|
||||
</data>
|
||||
<data name="Message.SaveUrlMapping" xml:space="preserve">
|
||||
<value>The Url must belong to the current site</value>
|
||||
</data>
|
||||
</root>
|
144
Oqtane.Client/Resources/Modules/Admin/UrlMappings/Edit.resx
Normal file
144
Oqtane.Client/Resources/Modules/Admin/UrlMappings/Edit.resx
Normal file
@ -0,0 +1,144 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="MappedUrl.Text" xml:space="preserve">
|
||||
<value>Redirect To:</value>
|
||||
</data>
|
||||
<data name="MappedUrl.HelpText" xml:space="preserve">
|
||||
<value>A relative or absolute Url where the user will be redirected</value>
|
||||
</data>
|
||||
<data name="Url.HelpText" xml:space="preserve">
|
||||
<value>A relative Url identifying a path to a specific page in the site</value>
|
||||
</data>
|
||||
<data name="Url.Text" xml:space="preserve">
|
||||
<value>Url:</value>
|
||||
</data>
|
||||
<data name="Error.LoadUrlMapping" xml:space="preserve">
|
||||
<value>Error Loading Url Mapping</value>
|
||||
</data>
|
||||
<data name="Error.SaveUrlMapping" xml:space="preserve">
|
||||
<value>Error Saving Url Mapping</value>
|
||||
</data>
|
||||
<data name="Message.InfoRequired" xml:space="preserve">
|
||||
<value>Please Provide All Required Information</value>
|
||||
</data>
|
||||
<data name="Message.DuplicateUrlMapping" xml:space="preserve">
|
||||
<value>The Url and Redirect To cannot be the same</value>
|
||||
</data>
|
||||
</root>
|
162
Oqtane.Client/Resources/Modules/Admin/UrlMappings/Index.resx
Normal file
162
Oqtane.Client/Resources/Modules/Admin/UrlMappings/Index.resx
Normal file
@ -0,0 +1,162 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Confirm.DeleteUrlMapping" xml:space="preserve">
|
||||
<value>Are You Sure You Wish To Delete {0}?</value>
|
||||
</data>
|
||||
<data name="AddUrlMapping.Text" xml:space="preserve">
|
||||
<value>Add Url Mapping</value>
|
||||
</data>
|
||||
<data name="DeleteUrlMapping.Header" xml:space="preserve">
|
||||
<value>Delete Url Mapping</value>
|
||||
</data>
|
||||
<data name="Requested" xml:space="preserve">
|
||||
<value>Requested</value>
|
||||
</data>
|
||||
<data name="Requests" xml:space="preserve">
|
||||
<value>Requests</value>
|
||||
</data>
|
||||
<data name="Mapped" xml:space="preserve">
|
||||
<value>Mapped Urls</value>
|
||||
</data>
|
||||
<data name="Broken" xml:space="preserve">
|
||||
<value>Broken Urls</value>
|
||||
</data>
|
||||
<data name="CaptureBrokenUrls.HelpText" xml:space="preserve">
|
||||
<value>Specify if broken Urls should be captured automatically and saved in Url Mappings</value>
|
||||
</data>
|
||||
<data name="CaptureBrokenUrls.Text" xml:space="preserve">
|
||||
<value>Capture Broken Urls?</value>
|
||||
</data>
|
||||
<data name="Error.SaveSiteSettings" xml:space="preserve">
|
||||
<value>Error Saving Settings</value>
|
||||
</data>
|
||||
<data name="Settings.Heading" xml:space="preserve">
|
||||
<value>Settings</value>
|
||||
</data>
|
||||
<data name="Success.SaveSiteSettings" xml:space="preserve">
|
||||
<value>Settings Saved Successfully</value>
|
||||
</data>
|
||||
<data name="Urls.Heading" xml:space="preserve">
|
||||
<value>Urls</value>
|
||||
</data>
|
||||
<data name="Url" xml:space="preserve">
|
||||
<value>Url</value>
|
||||
</data>
|
||||
</root>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
@ -169,10 +169,10 @@
|
||||
<value>Identity</value>
|
||||
</data>
|
||||
<data name="Confirm.HelpText" xml:space="preserve">
|
||||
<value>If you are changing your password you must enter it again to confirm it matches</value>
|
||||
<value>If you are changing your password you must enter it again to confirm it matches the value entered above</value>
|
||||
</data>
|
||||
<data name="Confirm.Text" xml:space="preserve">
|
||||
<value>Confirm Password:</value>
|
||||
<value>Confirmation:</value>
|
||||
</data>
|
||||
<data name="DisplayName.HelpText" xml:space="preserve">
|
||||
<value>Your full name</value>
|
||||
@ -204,4 +204,19 @@
|
||||
<data name="Username.Text" xml:space="preserve">
|
||||
<value>Username:</value>
|
||||
</data>
|
||||
<data name="TwoFactor.HelpText" xml:space="preserve">
|
||||
<value>Indicates if you are using two factor authentication. Two factor authentication requires you to enter a verification code sent via email after you sign in.</value>
|
||||
</data>
|
||||
<data name="TwoFactor.Text" xml:space="preserve">
|
||||
<value>Two Factor?</value>
|
||||
</data>
|
||||
<data name="DeleteAllNotifications.Header" xml:space="preserve">
|
||||
<value>Clear Notifications</value>
|
||||
</data>
|
||||
<data name="DeleteAllNotifications.Message" xml:space="preserve">
|
||||
<value>Are You Sure You Wish To Permanently Delete All Notifications?</value>
|
||||
</data>
|
||||
<data name="DeleteAllNotifications.Text" xml:space="preserve">
|
||||
<value>Delete ALL Notifications</value>
|
||||
</data>
|
||||
</root>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
@ -168,4 +168,7 @@
|
||||
<data name="Username.Text" xml:space="preserve">
|
||||
<value>Username:</value>
|
||||
</data>
|
||||
<data name="Password.Placeholder" xml:space="preserve">
|
||||
<value>Password</value>
|
||||
</data>
|
||||
</root>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
@ -177,4 +177,25 @@
|
||||
<data name="Username.Text" xml:space="preserve">
|
||||
<value>Username:</value>
|
||||
</data>
|
||||
<data name="Identity.Heading" xml:space="preserve">
|
||||
<value>Identity</value>
|
||||
</data>
|
||||
<data name="Profile.Heading" xml:space="preserve">
|
||||
<value>Profile</value>
|
||||
</data>
|
||||
<data name="Password.Placeholder" xml:space="preserve">
|
||||
<value>Password</value>
|
||||
</data>
|
||||
<data name="LastIPAddress.HelpText" xml:space="preserve">
|
||||
<value>The IP Address of the user recorded during their last login</value>
|
||||
</data>
|
||||
<data name="LastIPAddress.Text" xml:space="preserve">
|
||||
<value>Last IP Address: </value>
|
||||
</data>
|
||||
<data name="LastLogin.HelpText" xml:space="preserve">
|
||||
<value>The date and time when the user last signed in</value>
|
||||
</data>
|
||||
<data name="LastLogin.Text" xml:space="preserve">
|
||||
<value>Last Login:</value>
|
||||
</data>
|
||||
</root>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
@ -126,4 +126,262 @@
|
||||
<data name="DeleteUser.Header" xml:space="preserve">
|
||||
<value>Delete User</value>
|
||||
</data>
|
||||
<data name="AllowRegistration.HelpText" xml:space="preserve">
|
||||
<value>Do you want anonymous visitors to be able to register for an account on the site</value>
|
||||
</data>
|
||||
<data name="AllowRegistration.Text" xml:space="preserve">
|
||||
<value>Allow Registration? </value>
|
||||
</data>
|
||||
<data name="Error.SaveSiteSettings" xml:space="preserve">
|
||||
<value>Error Saving Settings</value>
|
||||
</data>
|
||||
<data name="Settings.Heading" xml:space="preserve">
|
||||
<value>Settings</value>
|
||||
</data>
|
||||
<data name="Success.SaveSiteSettings" xml:space="preserve">
|
||||
<value>Settings Saved Successfully</value>
|
||||
</data>
|
||||
<data name="Users.Heading" xml:space="preserve">
|
||||
<value>Users</value>
|
||||
</data>
|
||||
<data name="DeleteUser.Text" xml:space="preserve">
|
||||
<value>Delete</value>
|
||||
</data>
|
||||
<data name="EditUser.Text" xml:space="preserve">
|
||||
<value>Edit</value>
|
||||
</data>
|
||||
<data name="Roles.Text" xml:space="preserve">
|
||||
<value>Roles</value>
|
||||
</data>
|
||||
<data name="LockoutDuration.HelpText" xml:space="preserve">
|
||||
<value>The number of minutes a user should be locked out</value>
|
||||
</data>
|
||||
<data name="LockoutDuration.Text" xml:space="preserve">
|
||||
<value>Lockout Duration:</value>
|
||||
</data>
|
||||
<data name="MaximumFailures.HelpText" xml:space="preserve">
|
||||
<value>The maximum number of sign in attempts before a user is locked out</value>
|
||||
</data>
|
||||
<data name="MaximumFailures.Text" xml:space="preserve">
|
||||
<value>Maximum Failures:</value>
|
||||
</data>
|
||||
<data name="RequireDigit.HelpText" xml:space="preserve">
|
||||
<value>Indicate if passwords must contain a digit</value>
|
||||
</data>
|
||||
<data name="RequireDigit.Text" xml:space="preserve">
|
||||
<value>Require Digit?</value>
|
||||
</data>
|
||||
<data name="RequiredLength.HelpText" xml:space="preserve">
|
||||
<value>The minimum length for a password</value>
|
||||
</data>
|
||||
<data name="RequiredLength.Text" xml:space="preserve">
|
||||
<value>Minimum Length:</value>
|
||||
</data>
|
||||
<data name="RequireLower.HelpText" xml:space="preserve">
|
||||
<value>Indicate if passwords must contain a lower case character</value>
|
||||
</data>
|
||||
<data name="RequireLower.Text" xml:space="preserve">
|
||||
<value>Require Lowercase?</value>
|
||||
</data>
|
||||
<data name="RequirePunctuation.HelpText" xml:space="preserve">
|
||||
<value>Indicate if passwords must contain a non-alphanumeric character (ie. punctuation)</value>
|
||||
</data>
|
||||
<data name="RequirePunctuation.Text" xml:space="preserve">
|
||||
<value>Require Punctuation?</value>
|
||||
</data>
|
||||
<data name="RequireUpper.HelpText" xml:space="preserve">
|
||||
<value>Indicate if passwords must contain an upper case character</value>
|
||||
</data>
|
||||
<data name="RequireUpper.Text" xml:space="preserve">
|
||||
<value>Require Uppercase?</value>
|
||||
</data>
|
||||
<data name="Success.UpdateConfig.Restart" xml:space="preserve">
|
||||
<value>Configuration Updated. Please Select Restart Application For These Changes To Be Activated.</value>
|
||||
</data>
|
||||
<data name="UniqueCharacters.HelpText" xml:space="preserve">
|
||||
<value>The minimum number of unique characters which a password must contain</value>
|
||||
</data>
|
||||
<data name="UniqueCharacters.Text" xml:space="preserve">
|
||||
<value>Unique Characters:</value>
|
||||
</data>
|
||||
<data name="AllowSiteLogin.HelpText" xml:space="preserve">
|
||||
<value>Do you want to allow users to sign in using a username and password that is managed locally on this site? Note that you should only disable this option if you have already sucessfully configured an external login provider, or else you may lock yourself out of the site.</value>
|
||||
</data>
|
||||
<data name="AllowSiteLogin.Text" xml:space="preserve">
|
||||
<value>Allow Login?</value>
|
||||
</data>
|
||||
<data name="Authority.HelpText" xml:space="preserve">
|
||||
<value>The Authority Url or Issuer Url associated with the OpenID Connect provider</value>
|
||||
</data>
|
||||
<data name="Authority.Text" xml:space="preserve">
|
||||
<value>Authority:</value>
|
||||
</data>
|
||||
<data name="AuthorizationUrl.HelpText" xml:space="preserve">
|
||||
<value>The endpoint for obtaining an Authorization Code</value>
|
||||
</data>
|
||||
<data name="AuthorizationUrl.Text" xml:space="preserve">
|
||||
<value>Authorization Url:</value>
|
||||
</data>
|
||||
<data name="ClientID.HelpText" xml:space="preserve">
|
||||
<value>The Client ID from the provider</value>
|
||||
</data>
|
||||
<data name="ClientID.Text" xml:space="preserve">
|
||||
<value>Client ID:</value>
|
||||
</data>
|
||||
<data name="ClientSecret.HelpText" xml:space="preserve">
|
||||
<value>The Client Secret from the provider</value>
|
||||
</data>
|
||||
<data name="ClientSecret.Text" xml:space="preserve">
|
||||
<value>Client Secret:</value>
|
||||
</data>
|
||||
<data name="CreateUsers.HelpText" xml:space="preserve">
|
||||
<value>Do you want new users to be created automatically? If you disable this option, users must already be registered on the site in order to sign in with their external login.</value>
|
||||
</data>
|
||||
<data name="CreateUsers.Text" xml:space="preserve">
|
||||
<value>Create New Users?</value>
|
||||
</data>
|
||||
<data name="DomainFilter.HelpText" xml:space="preserve">
|
||||
<value>Provide any email domain filter criteria (separated by commas). Domains to exclude should be prefixed with an exclamation point (!). For example 'microsoft.com,!hotmail.com' would include microsoft.com email addresses but not hotmail.com email addresses.</value>
|
||||
</data>
|
||||
<data name="DomainFilter.Text" xml:space="preserve">
|
||||
<value>Domain Filter:</value>
|
||||
</data>
|
||||
<data name="EmailClaimType.HelpText" xml:space="preserve">
|
||||
<value>The name of the email address claim provided by the provider</value>
|
||||
</data>
|
||||
<data name="EmailClaimType.Text" xml:space="preserve">
|
||||
<value>Email Claim:</value>
|
||||
</data>
|
||||
<data name="ExternalLoginSettings.Heading" xml:space="preserve">
|
||||
<value>External Login Settings</value>
|
||||
</data>
|
||||
<data name="LockoutSettings.Heading" xml:space="preserve">
|
||||
<value>Lockout Settings</value>
|
||||
</data>
|
||||
<data name="MetadataUrl.HelpText" xml:space="preserve">
|
||||
<value>The discovery endpoint for obtaining metadata for this provider. Only specify if the OpenID Connect provider does not use the standard approach (ie. /.well-known/openid-configuration)</value>
|
||||
</data>
|
||||
<data name="MetadataUrl.Text" xml:space="preserve">
|
||||
<value>Metadata Url:</value>
|
||||
</data>
|
||||
<data name="PasswordSettings.Heading" xml:space="preserve">
|
||||
<value>Password Settings</value>
|
||||
</data>
|
||||
<data name="PKCE.HelpText" xml:space="preserve">
|
||||
<value>Indicate if the provider supports Proof Key for Code Exchange (PKCE)</value>
|
||||
</data>
|
||||
<data name="PKCE.Text" xml:space="preserve">
|
||||
<value>Use PKCE?</value>
|
||||
</data>
|
||||
<data name="ProviderName.HelpText" xml:space="preserve">
|
||||
<value>The external login provider name which will be displayed on the login page</value>
|
||||
</data>
|
||||
<data name="ProviderName.Text" xml:space="preserve">
|
||||
<value>Provider Name:</value>
|
||||
</data>
|
||||
<data name="ProviderType.HelpText" xml:space="preserve">
|
||||
<value>Select the external login provider type</value>
|
||||
</data>
|
||||
<data name="ProviderType.Text" xml:space="preserve">
|
||||
<value>Provider Type:</value>
|
||||
</data>
|
||||
<data name="RedirectUrl.HelpText" xml:space="preserve">
|
||||
<value>The Redirect Url (or Callback Url) which usually needs to be registered with the provider</value>
|
||||
</data>
|
||||
<data name="RedirectUrl.Text" xml:space="preserve">
|
||||
<value>Redirect Url:</value>
|
||||
</data>
|
||||
<data name="Scopes.HelpText" xml:space="preserve">
|
||||
<value>A list of Scopes to request from the provider (separated by commas). If none are specified, standard Scopes will be used by default.</value>
|
||||
</data>
|
||||
<data name="Scopes.Text" xml:space="preserve">
|
||||
<value>Scopes:</value>
|
||||
</data>
|
||||
<data name="TokenUrl.HelpText" xml:space="preserve">
|
||||
<value>The endpoint for obtaining an Auth Token</value>
|
||||
</data>
|
||||
<data name="TokenUrl.Text" xml:space="preserve">
|
||||
<value>Token Url:</value>
|
||||
</data>
|
||||
<data name="UserInfoUrl.HelpText" xml:space="preserve">
|
||||
<value>The endpoint for obtaining user information. This should be an API or Page Url which contains the users email address.</value>
|
||||
</data>
|
||||
<data name="UserInfoUrl.Text" xml:space="preserve">
|
||||
<value>User Info Url:</value>
|
||||
</data>
|
||||
<data name="Audience.HelpText" xml:space="preserve">
|
||||
<value>Optionally provide the audience for the token</value>
|
||||
</data>
|
||||
<data name="Audience.Text" xml:space="preserve">
|
||||
<value>Audience:</value>
|
||||
</data>
|
||||
<data name="UserSettings.Heading" xml:space="preserve">
|
||||
<value>User Settings</value>
|
||||
</data>
|
||||
<data name="CookieName.HelpText" xml:space="preserve">
|
||||
<value>You can choose to use a custom authentication cookie name for each site. However please be aware that if you want to share an authentication cookie between sites on the same domain they need to use a consistent cookie name. Also be aware that changing the authentication cookie name will logout all current users.</value>
|
||||
</data>
|
||||
<data name="CookieName.Text" xml:space="preserve">
|
||||
<value>Cookie Name:</value>
|
||||
</data>
|
||||
<data name="CreateToken" xml:space="preserve">
|
||||
<value>Create Token</value>
|
||||
</data>
|
||||
<data name="Issuer.HelpText" xml:space="preserve">
|
||||
<value>Optionally provide the issuer of the token</value>
|
||||
</data>
|
||||
<data name="Issuer.Text" xml:space="preserve">
|
||||
<value>Issuer:</value>
|
||||
</data>
|
||||
<data name="Lifetime.HelpText" xml:space="preserve">
|
||||
<value>The number of minutes for which a token should be valid</value>
|
||||
</data>
|
||||
<data name="Lifetime.Text" xml:space="preserve">
|
||||
<value>Lifetime:</value>
|
||||
</data>
|
||||
<data name="Secret.HelpText" xml:space="preserve">
|
||||
<value>If you want to want to provide API access, please specify a secret which will be used to encrypt your tokens. The secret should be 16 characters or more to ensure optimal security. Please note that if you change this secret, all existing tokens will become invalid and will need to be regenerated.</value>
|
||||
</data>
|
||||
<data name="Secret.Text" xml:space="preserve">
|
||||
<value>Secret:</value>
|
||||
</data>
|
||||
<data name="Token.HelpText" xml:space="preserve">
|
||||
<value>Select the Create Token button to generate a long-lived access token (valid for 1 year). Be sure to store this token in a safe location as you will not be able to access it in the future.</value>
|
||||
</data>
|
||||
<data name="Token.Text" xml:space="preserve">
|
||||
<value>Token:</value>
|
||||
</data>
|
||||
<data name="TokenSettings.Heading" xml:space="preserve">
|
||||
<value>Token Settings</value>
|
||||
</data>
|
||||
<data name="TwoFactor.HelpText" xml:space="preserve">
|
||||
<value>Do you want users to use two factor authentication? Note that you should use the Disabled option until you have successfully verified that the Notification Job in Scheduled Jobs is enabled and your SMTP options in Site Settings are configured or else you will lock yourself out.</value>
|
||||
</data>
|
||||
<data name="TwoFactor.Text" xml:space="preserve">
|
||||
<value>Two Factor?</value>
|
||||
</data>
|
||||
<data name="Disabled" xml:space="preserve">
|
||||
<value>Disabled</value>
|
||||
</data>
|
||||
<data name="Optional" xml:space="preserve">
|
||||
<value>Optional</value>
|
||||
</data>
|
||||
<data name="Required" xml:space="preserve">
|
||||
<value>Required</value>
|
||||
</data>
|
||||
<data name="LastLoginOn" xml:space="preserve">
|
||||
<value>Last Login</value>
|
||||
</data>
|
||||
<data name="IdentifierClaimType.HelpText" xml:space="preserve">
|
||||
<value>The name of the unique user identifier claim provided by the provider</value>
|
||||
</data>
|
||||
<data name="IdentifierClaimType.Text" xml:space="preserve">
|
||||
<value>Identifier Claim:</value>
|
||||
</data>
|
||||
<data name="Parameters.HelpText" xml:space="preserve">
|
||||
<value>Optionally specify any additional parameters as name/value pairs to send to the provider (separated by commas if there are multiple).</value>
|
||||
</data>
|
||||
<data name="Parameters.Text" xml:space="preserve">
|
||||
<value>Parameters:</value>
|
||||
</data>
|
||||
</root>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user