Compare commits
338 Commits
Author | SHA1 | Date | |
---|---|---|---|
ec0a5377b3 | |||
b876da069d | |||
f06063d7eb | |||
c6ba4f4bee | |||
89da4ab2a1 | |||
99ac0a3cab | |||
a964c30705 | |||
2334d0297d | |||
e444c6bcf0 | |||
601582fc98 | |||
e939dbe24e | |||
143ad85fd5 | |||
20377e9789 | |||
e4a24df7b4 | |||
e88ca00658 | |||
2312c612d7 | |||
3aee52482d | |||
32248e0be6 | |||
6c18c320bd | |||
e31f32e5aa | |||
a856390566 | |||
64b8291487 | |||
2ebd1310c9 | |||
09118fcb42 | |||
5d5167abbc | |||
bf43dea060 | |||
6ebab830c5 | |||
9a9a78e0bd | |||
418eff7d21 | |||
d39869ca8e | |||
7829168ea7 | |||
dd83e3ee67 | |||
c3ac0e365d | |||
2986625605 | |||
8beaeabf09 | |||
fa9b4b6112 | |||
d81fbe4585 | |||
536c044139 | |||
376531195e | |||
abf4ff71d7 | |||
d25debcea3 | |||
948c186cb5 | |||
ba27e70fe3 | |||
c93d2576af | |||
e0b0156640 | |||
a3ca6a3071 | |||
b20157450b | |||
7e4f0923d7 | |||
e0c2b2982f | |||
9a231c28af | |||
94a02b7bf9 | |||
22c8fb411a | |||
cf46210ff8 | |||
f32d988297 | |||
7fe4577158 | |||
8985dcb4c0 | |||
d346444c51 | |||
ef27a0d6b0 | |||
627158cb5d | |||
648edcabba | |||
0f34c6efc5 | |||
cc3cc55269 | |||
a503a9d5bc | |||
789baf99ff | |||
036279a54c | |||
481f18cf1c | |||
2f1e386554 | |||
1e0c7cf43d | |||
7978c89731 | |||
82221f54c5 | |||
2e23e6e4d5 | |||
3a79fa074a | |||
696c63c6d2 | |||
8f6dc52430 | |||
c8a9ad9807 | |||
a0933d07d8 | |||
6bf61e2008 | |||
36ecc55578 | |||
47065299ca | |||
0f707a7607 | |||
7590c5550f | |||
3d23a5c79a | |||
9aa0374dc2 | |||
058a191673 | |||
5fbb9160f1 | |||
2c3dad0592 | |||
00f039d31e | |||
497ef1750b | |||
7d4cd04ce9 | |||
04c0b9d37d | |||
b9c16c0727 | |||
0a30f2b7e8 | |||
dbb1d53202 | |||
2c88f36e3d | |||
d91dcad774 | |||
6eb4ea2a2d | |||
ff6187c336 | |||
1253dfe0c8 | |||
c1f2f9a970 | |||
8d5e7ed69f | |||
3d3540f090 | |||
61f1fcb99c | |||
c7b576d6d3 | |||
ab3b1d5e46 | |||
ddff3faba9 | |||
f7bb8444da | |||
92128974bb | |||
4eb15d4806 | |||
39cb3780c8 | |||
81030f468b | |||
2032cb1ace | |||
5e4c91440e | |||
13bbad863f | |||
3065ed5094 | |||
9eb75cfff0 | |||
9305c99577 | |||
9078da6937 | |||
4c579639b9 | |||
b86472ab52 | |||
5e1ac485a0 | |||
527c1a12f4 | |||
ef4e99b3a7 | |||
12a9635309 | |||
78adb24a75 | |||
49955cf642 | |||
af3b289331 | |||
d11591e5aa | |||
9c6174e3f2 | |||
09c2f74d52 | |||
7d7e0254cb | |||
fe767afe9c | |||
3378f0e4ee | |||
c0341798ea | |||
fc114dc5db | |||
7107d844e1 | |||
59af0a817e | |||
9615eded85 | |||
c51fa23fcb | |||
8737fd6f1e | |||
0f109ab93a | |||
63df2742db | |||
7b7811f8ad | |||
80f74b9939 | |||
1f29f77f66 | |||
dd7da5f354 | |||
49b30da697 | |||
90ed767d75 | |||
7871f0f3ce | |||
a60cf40a3c | |||
f4eb2f6726 | |||
cfe87a802e | |||
6c90ec812f | |||
196d611c1c | |||
ff41cb2735 | |||
fb11674301 | |||
b9e7f4530c | |||
27049687bf | |||
13503edc63 | |||
d33f82d969 | |||
177632eee0 | |||
ca0de5258e | |||
1de788bc26 | |||
2b41909d47 | |||
e23a9f22dd | |||
465b7850b7 | |||
a0f2eedd7f | |||
8605e3ca5a | |||
dd893e6d48 | |||
c4cd1a5a54 | |||
94152651fc | |||
563ea76192 | |||
4913fab0b3 | |||
b49d011edf | |||
6e04281b03 | |||
f2df8e96db | |||
c6dd7605b2 | |||
71dd00da0f | |||
da48ca884d | |||
8c6c66fb11 | |||
f333b57310 | |||
d1d00e6c98 | |||
52300e680a | |||
b3f7353582 | |||
7db6b82a1a | |||
a50a13374f | |||
3952fe5a72 | |||
2e61a43e4f | |||
ebe03e9310 | |||
11dd3ce110 | |||
1919c24959 | |||
aa80f31e52 | |||
6d8400e72f | |||
fa8d0c91fc | |||
e91ff95712 | |||
0883a8dbff | |||
0db297d1cd | |||
db73052ee5 | |||
8b95069610 | |||
2a12744cd5 | |||
1df4059284 | |||
475894b680 | |||
1663bf8e52 | |||
ffca1d2486 | |||
eb876845ff | |||
02c134bf4b | |||
af55c11aa0 | |||
33bc6adcb5 | |||
56e4dcc11e | |||
467cf7620e | |||
85ac8dd701 | |||
1f2ad4e884 | |||
cf2d9af664 | |||
7a105047e9 | |||
bc8bdef37d | |||
fd0519b955 | |||
d5ffb56fa8 | |||
d6cce9e2d8 | |||
08ec46637f | |||
f596795792 | |||
2c56bfd4aa | |||
755615da30 | |||
4cc0060c67 | |||
52af015c2f | |||
eae6d13284 | |||
2a20a7cf21 | |||
27251005ec | |||
90a9b2e5a1 | |||
cd1f12e9b4 | |||
734b9b6458 | |||
a120449c8d | |||
b005a1da56 | |||
afc75a09d9 | |||
c6e6c98875 | |||
fa1a5ab913 | |||
b671b590ad | |||
a46c98eed3 | |||
7ab5ed5bcb | |||
5e609edc31 | |||
ac466429f8 | |||
2804c50c8a | |||
c4315c25bc | |||
e2d5fa48cf | |||
c2375c897d | |||
49f181583b | |||
ea463a6548 | |||
1a567dbdc1 | |||
e4ec10ef49 | |||
3db4fc687a | |||
e136972cd7 | |||
7b1b32e16f | |||
1616f94b86 | |||
7043d1f3bf | |||
7bebfe1919 | |||
d33ded0426 | |||
66aa67581f | |||
3a95c05db9 | |||
67046e9d36 | |||
6f2965a5b0 | |||
197db449a1 | |||
f4800bb7f0 | |||
6a213561f6 | |||
8f8d31f0c9 | |||
f8cfdacc26 | |||
07223e27a4 | |||
4c6f46ad17 | |||
39dc288f9c | |||
467e88ef55 | |||
0965db5d57 | |||
c30339d9b8 | |||
369adcb173 | |||
d837b981d4 | |||
f455461c1e | |||
0087b188a1 | |||
98602f49d8 | |||
70466e5626 | |||
cc7f98a6fe | |||
fd13ad1fca | |||
5077f6fbca | |||
9b15ce6d29 | |||
5a8ca24566 | |||
d3f982cae1 | |||
28b58b9048 | |||
cb10dde97d | |||
2c179867e8 | |||
44fc6de82b | |||
f671af43cd | |||
8c0dc6422e | |||
c91e285475 | |||
642e41530e | |||
b09a3ccdae | |||
a1aab62cea | |||
e8b1aca45c | |||
3de98873d6 | |||
c030ede12c | |||
67f740c264 | |||
9b68337047 | |||
2bae971b92 | |||
c5c5fd859f | |||
15c46fd157 | |||
424950bd3e | |||
39a9968971 | |||
075a09f0df | |||
26e628e189 | |||
7489d9d186 | |||
7db5b6c7f3 | |||
9b7fa8cac2 | |||
5028051a34 | |||
83b3767df6 | |||
6182b96d16 | |||
a719382563 | |||
2aa6eb90e2 | |||
d2495455cd | |||
23d1dd23d1 | |||
573acd6a5d | |||
40ddbbfbb7 | |||
1b488b298b | |||
54b45943db | |||
89b3ae4c74 | |||
fe97a76d00 | |||
78094f69d7 | |||
4499d55464 | |||
4c12ca0607 | |||
1daa9575db | |||
f7c9961f8c | |||
e27a625069 | |||
42b1669cce | |||
74571afc9e | |||
f678f11c59 | |||
e685252b1d | |||
bb75fcb5a3 | |||
7653f36f31 | |||
0670148064 | |||
368b900a6e | |||
6378a78cbd | |||
d3bcdec0f2 | |||
82c074ce2e | |||
a313e2d386 | |||
578cb2f7e3 |
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2018-2022 .NET Foundation
|
Copyright (c) 2018-2023 .NET Foundation
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -55,7 +55,7 @@
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="connectionstring" HelpText="Enter a complete connection string including all parameters and delimiters" ResourceKey="ConnectionString">String:</Label>
|
<Label Class="col-sm-3" For="connectionstring" HelpText="Enter a complete connection string including all parameters and delimiters" ResourceKey="ConnectionString">Settings:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<textarea id="connectionstring" class="form-control" @bind="@_connectionString" rows="3"></textarea>
|
<textarea id="connectionstring" class="form-control" @bind="@_connectionString" rows="3"></textarea>
|
||||||
</div>
|
</div>
|
||||||
@ -77,7 +77,7 @@
|
|||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="password" type="@_passwordType" class="form-control" @bind="@_hostPassword" autocomplete="new-password" />
|
<input id="password" type="@_passwordType" class="form-control" @bind="@_hostPassword" autocomplete="new-password" />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglePassword</button>
|
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglePassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -86,7 +86,7 @@
|
|||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="confirm" type="@_confirmPasswordType" class="form-control" @bind="@_confirmPassword" autocomplete="new-password" />
|
<input id="confirm" type="@_confirmPasswordType" class="form-control" @bind="@_confirmPassword" autocomplete="new-password" />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@ToggleConfirmPassword">@_toggleConfirmPassword</button>
|
<button type="button" class="btn btn-secondary" @onclick="@ToggleConfirmPassword" tabindex="-1">@_toggleConfirmPassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,29 +4,35 @@
|
|||||||
@inject IUserService UserService
|
@inject IUserService UserService
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
<div class="row">
|
@if (_pages != null)
|
||||||
@foreach (var p in _pages)
|
{
|
||||||
{
|
<div class="row">
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
@foreach (var p in _pages)
|
||||||
{
|
{
|
||||||
string url = NavigateUrl(p.Path);
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||||
<div class="col-md-2 mx-auto text-center mb-3">
|
{
|
||||||
<NavLink class="nav-link text-primary" href="@url" Match="NavLinkMatch.All">
|
string url = NavigateUrl(p.Path);
|
||||||
<h2><span class="@p.Icon" aria-hidden="true"></span></h2>@SharedLocalizer[p.Name]
|
<div class="col-md-2 mx-auto text-center mb-3">
|
||||||
</NavLink>
|
<NavLink class="nav-link text-primary" href="@url" Match="NavLinkMatch.All">
|
||||||
</div>
|
<h2><span class="@p.Icon" aria-hidden="true"></span></h2>@SharedLocalizer[p.Name]
|
||||||
|
</NavLink>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
</div>
|
||||||
</div>
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<Page> _pages;
|
private List<Page> _pages;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
var admin = PageState.Pages.FirstOrDefault(item => item.Path == "admin");
|
var admin = PageState.Pages.FirstOrDefault(item => item.Path == "admin");
|
||||||
_pages = PageState.Pages.Where(item => item.ParentId == admin?.PageId).ToList();
|
if (admin != null)
|
||||||
|
{
|
||||||
|
_pages = PageState.Pages.Where(item => item.ParentId == admin.PageId).ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,8 +62,7 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<Label Class="col-sm-3" For="permissions" HelpText="Select the permissions you want for the folder" ResourceKey="Permissions">Permissions: </Label>
|
<Label Class="col-sm-3" For="permissions" HelpText="Select the permissions you want for the folder" ResourceKey="Permissions">Permissions: </Label>
|
||||||
<PermissionGrid EntityName="@EntityNames.Folder" PermissionNames="@(PermissionNames.Browse + "," + PermissionNames.View + "," + PermissionNames.Edit)" Permissions="@_permissions" @ref="_permissionGrid" />
|
<PermissionGrid EntityName="@EntityNames.Folder" PermissionNames="@(PermissionNames.Browse + "," + PermissionNames.View + "," + PermissionNames.Edit)" PermissionList="@_permissions" @ref="_permissionGrid" />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -99,7 +98,7 @@
|
|||||||
private string _imagesizes = string.Empty;
|
private string _imagesizes = string.Empty;
|
||||||
private string _capacity = "0";
|
private string _capacity = "0";
|
||||||
private bool _isSystem;
|
private bool _isSystem;
|
||||||
private string _permissions = string.Empty;
|
private List<Permission> _permissions = null;
|
||||||
private string _createdBy;
|
private string _createdBy;
|
||||||
private DateTime _createdOn;
|
private DateTime _createdOn;
|
||||||
private string _modifiedBy;
|
private string _modifiedBy;
|
||||||
@ -131,7 +130,7 @@
|
|||||||
_imagesizes = folder.ImageSizes;
|
_imagesizes = folder.ImageSizes;
|
||||||
_capacity = folder.Capacity.ToString();
|
_capacity = folder.Capacity.ToString();
|
||||||
_isSystem = folder.IsSystem;
|
_isSystem = folder.IsSystem;
|
||||||
_permissions = folder.Permissions;
|
_permissions = folder.PermissionList;
|
||||||
_createdBy = folder.CreatedBy;
|
_createdBy = folder.CreatedBy;
|
||||||
_createdOn = folder.CreatedOn;
|
_createdOn = folder.CreatedOn;
|
||||||
_modifiedBy = folder.ModifiedBy;
|
_modifiedBy = folder.ModifiedBy;
|
||||||
@ -196,7 +195,7 @@
|
|||||||
folder.ImageSizes = _imagesizes;
|
folder.ImageSizes = _imagesizes;
|
||||||
folder.Capacity = int.Parse(_capacity);
|
folder.Capacity = int.Parse(_capacity);
|
||||||
folder.IsSystem = _isSystem;
|
folder.IsSystem = _isSystem;
|
||||||
folder.Permissions = _permissionGrid.GetPermissions();
|
folder.PermissionList = _permissionGrid.GetPermissionList();
|
||||||
|
|
||||||
if (_folderId != -1)
|
if (_folderId != -1)
|
||||||
{
|
{
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
@inject IStringLocalizer<Add> Localizer
|
@inject IStringLocalizer<Add> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
@if (_supportedCultures == null)
|
@if (_cultures == null)
|
||||||
{
|
{
|
||||||
<p><em>@SharedLocalizer["Loading"]</em></p>
|
<p><em>@SharedLocalizer["Loading"]</em></p>
|
||||||
}
|
}
|
||||||
@ -17,335 +17,112 @@ else
|
|||||||
{
|
{
|
||||||
<TabStrip>
|
<TabStrip>
|
||||||
<TabPanel Name="Manage" ResourceKey="Manage">
|
<TabPanel Name="Manage" ResourceKey="Manage">
|
||||||
@if (_availableCultures.Count() == 0)
|
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||||
{
|
<div class="container">
|
||||||
<ModuleMessage Type="MessageType.Info" Message="@_message"></ModuleMessage>
|
<div class="row mb-1 align-items-center">
|
||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
<Label Class="col-sm-3" For="name" HelpText="Name Of The Language" ResourceKey="Name">Name:</Label>
|
||||||
}
|
<div class="col-sm-9">
|
||||||
else
|
<select id="_code" class="form-select" @bind="@_code" required>
|
||||||
{
|
<option value="-"><@SharedLocalizer["Not Specified"]></option>
|
||||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
@foreach (var culture in _cultures)
|
||||||
<div class="container">
|
{
|
||||||
<div class="row mb-1 align-items-center">
|
<option value="@culture.Name">@(culture.DisplayName + " (" + culture.Name + ")")</option>
|
||||||
<Label Class="col-sm-3" For="name" HelpText="Name Of The Language" ResourceKey="Name">Name:</Label>
|
}
|
||||||
<div class="col-sm-9">
|
</select>
|
||||||
<select id="_code" class="form-select" @bind="@_code" required>
|
|
||||||
@foreach (var culture in _availableCultures)
|
|
||||||
{
|
|
||||||
<option value="@culture.Name">@(culture.DisplayName + " (" + culture.Name + ")")</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="default" HelpText="Indicates Whether Or Not This Language Is The Default For The Site" ResourceKey="IsDefault">Default?</Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<select id="default" class="form-select" @bind="@_isDefault" required>
|
|
||||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
|
||||||
<option value="False">@SharedLocalizer["No"]</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success" @onclick="SaveLanguage">@SharedLocalizer["Save"]</button>
|
<div class="row mb-1 align-items-center">
|
||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
<Label Class="col-sm-3" For="default" HelpText="Indicates Whether Or Not This Language Is The Default For The Site" ResourceKey="IsDefault">Default?</Label>
|
||||||
</form>
|
<div class="col-sm-9">
|
||||||
}
|
<select id="default" class="form-select" @bind="@_default" required>
|
||||||
</TabPanel>
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||||
<TabPanel Name="Translations" Heading="Translations" ResourceKey="Download" Security="SecurityAccessLevel.Host">
|
<option value="False">@SharedLocalizer["No"]</option>
|
||||||
<div class="row justify-content-center mb-3">
|
</select>
|
||||||
<div class="col-sm-6">
|
</div>
|
||||||
<div class="input-group">
|
|
||||||
<select id="price" class="form-select custom-select" @onchange="(e => PriceChanged(e))">
|
|
||||||
<option value="free">@SharedLocalizer["Free"]</option>
|
|
||||||
<option value="paid">@SharedLocalizer["Paid"]</option>
|
|
||||||
</select>
|
|
||||||
<input id="search" class="form-control" placeholder="@SharedLocalizer["Search.Hint"]" @bind="@_search" />
|
|
||||||
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>
|
|
||||||
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<button type="button" class="btn btn-success" @onclick="SaveLanguage">@SharedLocalizer["Save"]</button>
|
||||||
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
@if (_packages != null)
|
</form>
|
||||||
{
|
|
||||||
@if (_packages.Count > 0)
|
|
||||||
{
|
|
||||||
<Pager Items="@_packages">
|
|
||||||
<Row>
|
|
||||||
<td>
|
|
||||||
<h3 style="display: inline;"><a href="@context.ProductUrl" target="_new">@context.Name</a></h3> by: <strong><a href="@context.OwnerUrl" target="new">@context.Owner</a></strong><br />
|
|
||||||
@(context.Description.Length > 400 ? (context.Description.Substring(0, 400) + "...") : context.Description)<br />
|
|
||||||
<strong>@(String.Format("{0:n0}", context.Downloads))</strong> @SharedLocalizer["Search.Downloads"] |
|
|
||||||
@SharedLocalizer["Search.Released"]: <strong>@context.ReleaseDate.ToString("MMM dd, yyyy")</strong> |
|
|
||||||
@SharedLocalizer["Search.Version"]: <strong>@context.Version</strong>
|
|
||||||
@((MarkupString)(!string.IsNullOrEmpty(context.PackageUrl) ? " | " + SharedLocalizer["Search.Source"] + ": <strong>" + new Uri(context.PackageUrl).Host + "</strong>" : ""))
|
|
||||||
@((MarkupString)(context.TrialPeriod > 0 ? " | <strong>" + context.TrialPeriod + " " + @SharedLocalizer["Trial"] + "</strong>" : ""))
|
|
||||||
</td>
|
|
||||||
<td style="width: 1px; vertical-align: middle;">
|
|
||||||
@if (context.Price != null && !string.IsNullOrEmpty(context.PackageUrl))
|
|
||||||
{
|
|
||||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await GetPackage(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button>
|
|
||||||
}
|
|
||||||
</td>
|
|
||||||
<td style="width: 1px; vertical-align: middle;">
|
|
||||||
@if (context.Price != null && !string.IsNullOrEmpty(context.PaymentUrl))
|
|
||||||
{
|
|
||||||
<a class="btn btn-primary" style="text-decoration: none !important" href="@context.PaymentUrl" target="_new">@context.Price.Value.ToString("$#,##0.00")</a>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await GetPackage(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button>
|
|
||||||
}
|
|
||||||
</td>
|
|
||||||
</Row>
|
|
||||||
</Pager>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<br />
|
|
||||||
<div class="mx-auto text-center">
|
|
||||||
@Localizer["Search.NoResults"]
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<button type="button" class="btn btn-success" @onclick="InstallLanguages">@SharedLocalizer["Install"]</button>
|
|
||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
|
||||||
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<ModuleMessage Type="MessageType.Info" Message="@SharedLocalizer["Oqtane.Marketplace"]" />
|
|
||||||
}
|
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel Name="Upload" ResourceKey="Upload" Security="SecurityAccessLevel.Host">
|
<TabPanel Name="Upload" ResourceKey="Upload" Security="SecurityAccessLevel.Host">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" HelpText="Upload one or more translations. Once they are uploaded click Install to complete the installation." ResourceKey="LanguageUpload">Translation: </Label>
|
<Label Class="col-sm-3" HelpText="Upload one or more translations. Once they are uploaded click Install." ResourceKey="LanguageUpload">Translation: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<FileManager Folder="@Constants.PackagesFolder" UploadMultiple="true" />
|
<FileManager Folder="@Constants.PackagesFolder" UploadMultiple="true" OnUpload="OnUpload" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success" @onclick="InstallLanguages">@SharedLocalizer["Install"]</button>
|
|
||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
</TabStrip>
|
</TabStrip>
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (_productname != "")
|
|
||||||
{
|
|
||||||
<div class="app-actiondialog">
|
|
||||||
<div class="modal" tabindex="-1" role="dialog">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">@SharedLocalizer["Review License Terms"]</h5>
|
|
||||||
<button type="button" class="btn-close" aria-label="Close" @onclick="HideModal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<p style="height: 200px; overflow-y: scroll;">
|
|
||||||
<h3>@_productname</h3>
|
|
||||||
@if (!string.IsNullOrEmpty(_license))
|
|
||||||
{
|
|
||||||
@((MarkupString)_license)
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
@SharedLocalizer["License Not Specified"]
|
|
||||||
}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-success" @onclick="DownloadPackage">@SharedLocalizer["Accept"]</button>
|
|
||||||
<button type="button" class="btn btn-secondary" @onclick="HideModal">@SharedLocalizer["Cancel"]</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private ElementReference form;
|
private ElementReference form;
|
||||||
private bool validated = false;
|
private bool validated = false;
|
||||||
|
|
||||||
private string _code = string.Empty;
|
private string _code = "-";
|
||||||
private string _isDefault = "False";
|
private string _default = "False";
|
||||||
private string _message;
|
private List<string> _languages;
|
||||||
private IEnumerable<Culture> _supportedCultures;
|
private IEnumerable<Culture> _cultures;
|
||||||
private IEnumerable<Culture> _availableCultures;
|
|
||||||
private List<Package> _packages;
|
|
||||||
private string _price = "free";
|
|
||||||
private string _search = "";
|
|
||||||
private string _productname = "";
|
|
||||||
private string _license = "";
|
|
||||||
private string _packageid = "";
|
|
||||||
private string _version = "";
|
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
var languages = await LanguageService.GetLanguagesAsync(PageState.Site.SiteId);
|
var languages = await LanguageService.GetLanguagesAsync(PageState.Site.SiteId);
|
||||||
var languagesCodes = languages.Select(l => l.Code).ToList();
|
_languages = languages.Select(l => l.Code).ToList();
|
||||||
|
|
||||||
_supportedCultures = await LocalizationService.GetCulturesAsync();
|
await LoadCultures();
|
||||||
_availableCultures = _supportedCultures.Where(c => !c.Name.Equals(Constants.DefaultCulture) && !languagesCodes.Contains(c.Name));
|
}
|
||||||
await LoadTranslations();
|
|
||||||
|
|
||||||
if (_supportedCultures.Count() == 1)
|
private async Task LoadCultures()
|
||||||
{
|
{
|
||||||
_message = Localizer["OnlyEnglish"];
|
_cultures = await LocalizationService.GetCulturesAsync(false);
|
||||||
}
|
_cultures = _cultures.Where(c => !c.Name.Equals(Constants.DefaultCulture) && !_languages.Contains(c.Name));
|
||||||
else if (_availableCultures.Count() == 0)
|
_code = "-";
|
||||||
{
|
}
|
||||||
_message = Localizer["AllLanguages"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task LoadTranslations()
|
private async Task SaveLanguage()
|
||||||
{
|
{
|
||||||
_packages = await PackageService.GetPackagesAsync("translation", _search, _price, "");
|
validated = true;
|
||||||
}
|
var interop = new Interop(JSRuntime);
|
||||||
|
if (await interop.FormValid(form) && _code != "-")
|
||||||
|
{
|
||||||
|
var language = new Language
|
||||||
|
{
|
||||||
|
SiteId = PageState.Page.SiteId,
|
||||||
|
Name = CultureInfo.GetCultureInfo(_code).DisplayName,
|
||||||
|
Code = _code,
|
||||||
|
IsDefault = (_default == null ? false : Boolean.Parse(_default))
|
||||||
|
};
|
||||||
|
|
||||||
private async void PriceChanged(ChangeEventArgs e)
|
try
|
||||||
{
|
{
|
||||||
try
|
language = await LanguageService.AddLanguageAsync(language);
|
||||||
{
|
|
||||||
_price = (string)e.Value;
|
|
||||||
_search = "";
|
|
||||||
await LoadTranslations();
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error On PriceChanged");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task Search()
|
if (language.IsDefault)
|
||||||
{
|
{
|
||||||
try
|
await SetCultureAsync(language.Code);
|
||||||
{
|
}
|
||||||
await LoadTranslations();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error On Search");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task Reset()
|
await logger.LogInformation("Language Added {Language}", language);
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_search = "";
|
|
||||||
await LoadTranslations();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error On Reset");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SaveLanguage()
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
{
|
}
|
||||||
validated = true;
|
catch (Exception ex)
|
||||||
var interop = new Interop(JSRuntime);
|
{
|
||||||
if (await interop.FormValid(form))
|
await logger.LogError(ex, "Error Adding Language {Language} {Error}", language, ex.Message);
|
||||||
{
|
AddModuleMessage(Localizer["Error.Language.Add"], MessageType.Error);
|
||||||
var language = new Language
|
}
|
||||||
{
|
}
|
||||||
SiteId = PageState.Page.SiteId,
|
else
|
||||||
Name = CultureInfo.GetCultureInfo(_code).DisplayName,
|
{
|
||||||
Code = _code,
|
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||||
IsDefault = (_isDefault == null ? false : Boolean.Parse(_isDefault))
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
language = await LanguageService.AddLanguageAsync(language);
|
|
||||||
|
|
||||||
if (language.IsDefault)
|
|
||||||
{
|
|
||||||
await SetCultureAsync(language.Code);
|
|
||||||
}
|
|
||||||
|
|
||||||
await logger.LogInformation("Language Added {Language}", language);
|
|
||||||
|
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Adding Language {Language} {Error}", language, ex.Message);
|
|
||||||
AddModuleMessage(Localizer["Error.Language.Add"], MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void HideModal()
|
|
||||||
{
|
|
||||||
_productname = "";
|
|
||||||
_license = "";
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task GetPackage(string packageid, string version)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var package = await PackageService.GetPackageAsync(packageid, version);
|
|
||||||
if (package != null)
|
|
||||||
{
|
|
||||||
_productname = package.Name;
|
|
||||||
if (!string.IsNullOrEmpty(package.License))
|
|
||||||
{
|
|
||||||
_license = package.License.Replace("\n", "<br />");
|
|
||||||
}
|
|
||||||
_packageid = package.PackageId;
|
|
||||||
_version = package.Version;
|
|
||||||
}
|
|
||||||
StateHasChanged();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Getting Package {PackageId} {Version}", packageid, version);
|
|
||||||
AddModuleMessage(Localizer["Error.Module.Download"], MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task DownloadPackage()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Downloading Translation {Name} {Version}", _packageid, _version);
|
|
||||||
AddModuleMessage(Localizer["Error.Language.Download"], MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task InstallLanguages()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await PackageService.InstallPackagesAsync();
|
|
||||||
AddModuleMessage(string.Format(Localizer["Success.Language.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Installing Translations");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SetCultureAsync(string culture)
|
private async Task SetCultureAsync(string culture)
|
||||||
{
|
{
|
||||||
@ -358,4 +135,9 @@ else
|
|||||||
NavigationManager.NavigateTo(NavigationManager.Uri, true);
|
NavigationManager.NavigateTo(NavigationManager.Uri, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnUpload()
|
||||||
|
{
|
||||||
|
AddModuleMessage(string.Format(Localizer["Success.Language.Download"], NavigateUrl("admin/system")), MessageType.Success);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,94 +19,163 @@ else
|
|||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th>@SharedLocalizer["Name"]</th>
|
<th>@SharedLocalizer["Name"]</th>
|
||||||
<th>@Localizer["Code"]</th>
|
<th>@Localizer["Code"]</th>
|
||||||
<th>@Localizer["Translation"]</th>
|
|
||||||
<th>@Localizer["Default"]</th>
|
<th>@Localizer["Default"]</th>
|
||||||
<th style="width: 1px;"> </th>
|
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
|
{
|
||||||
|
<th style="width: 1px;">@Localizer["Translation"]</th>
|
||||||
|
<th style="width: 1px;"> </th>
|
||||||
|
}
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><ActionDialog Header="Delete Language" Message="@string.Format(Localizer["Confirm.Language.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteLanguage(context))" Disabled="@((context.IsDefault && _languages.Count > 2) || context.Code == Constants.DefaultCulture)" ResourceKey="DeleteLanguage" /></td>
|
<td><ActionDialog Header="Delete Language" Message="@string.Format(Localizer["Confirm.Language.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteLanguage(context))" Disabled="@((context.IsDefault && _languages.Count > 2) || context.Code == Constants.DefaultCulture)" ResourceKey="DeleteLanguage" /></td>
|
||||||
<td>@context.Name</td>
|
<td>@context.Name</td>
|
||||||
<td>@context.Code</td>
|
<td>@context.Code</td>
|
||||||
<td>@context.Version</td>
|
|
||||||
<td><TriStateCheckBox Value="@(context.IsDefault)" Disabled="true"></TriStateCheckBox></td>
|
<td><TriStateCheckBox Value="@(context.IsDefault)" Disabled="true"></TriStateCheckBox></td>
|
||||||
<td>
|
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
@if (UpgradeAvailable(context.Code, context.Version))
|
{
|
||||||
{
|
<td>@((string.IsNullOrEmpty(context.Version)) ? "---" : context.Version)</td>
|
||||||
<button type="button" class="btn btn-success" @onclick=@(async () => await DownloadLanguage(context.Code))>@SharedLocalizer["Upgrade"]</button>
|
<td>
|
||||||
}
|
@{
|
||||||
</td>
|
var translation = TranslationAvailable(context.Code, context.Version);
|
||||||
|
}
|
||||||
|
@if (translation != null)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(context.Version))
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-success" @onclick=@(async () => await GetPackage(context.Code, translation.Version))>@SharedLocalizer["Download"]</button>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Version.Parse(translation.Version).CompareTo(Version.Parse(context.Version)) > 0)
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-success" @onclick=@(async () => await GetPackage(context.Code, translation.Version))>@SharedLocalizer["Upgrade"]</button>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
}
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@if (_package != null)
|
||||||
|
{
|
||||||
|
<div class="app-actiondialog">
|
||||||
|
<div class="modal" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">@SharedLocalizer["Review License Terms"]</h5>
|
||||||
|
<button type="button" class="btn-close" aria-label="Close" @onclick="HideModal"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p style="height: 200px; overflow-y: scroll;">
|
||||||
|
<h4 style="display: inline;"><a href="@_package.ProductUrl" target="_new">@_package.Name</a></h4><br />
|
||||||
|
@SharedLocalizer["Search.By"]: <strong><a href="@_package.OwnerUrl" target="new">@_package.Owner</a></strong><br />
|
||||||
|
@(_package.Description.Length > 400 ? (_package.Description.Substring(0, 400) + "...") : _package.Description)<br />
|
||||||
|
<strong>@(String.Format("{0:n0}", _package.Downloads))</strong> @SharedLocalizer["Search.Downloads"] |
|
||||||
|
@SharedLocalizer["Search.Released"]: <strong>@_package.ReleaseDate.ToString("MMM dd, yyyy")</strong> |
|
||||||
|
@SharedLocalizer["Search.Version"]: <strong>@_package.Version</strong>
|
||||||
|
@((MarkupString)(!string.IsNullOrEmpty(_package.PackageUrl) ? " | " + SharedLocalizer["Search.Source"] + ": <strong>" + new Uri(_package.PackageUrl).Host + "</strong>" : ""))
|
||||||
|
<br /><br />
|
||||||
|
@if (!string.IsNullOrEmpty(_package.License))
|
||||||
|
{
|
||||||
|
@((MarkupString)_package.License.Replace("\n", "<br />"))
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@SharedLocalizer["License Not Specified"]
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-success" @onclick="DownloadPackage">@SharedLocalizer["Accept"]</button>
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="HideModal">@SharedLocalizer["Cancel"]</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<Language> _languages;
|
private List<Language> _languages;
|
||||||
private List<Package> _packages;
|
private List<Package> _packages;
|
||||||
|
private Package _package;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
|
{
|
||||||
|
await GetLanguages();
|
||||||
|
|
||||||
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
|
{
|
||||||
|
_packages = await PackageService.GetPackagesAsync("translation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GetLanguages()
|
||||||
{
|
{
|
||||||
_languages = await LanguageService.GetLanguagesAsync(PageState.Site.SiteId, Constants.ClientId);
|
_languages = await LanguageService.GetLanguagesAsync(PageState.Site.SiteId, Constants.ClientId);
|
||||||
|
}
|
||||||
|
|
||||||
var cultures = await LocalizationService.GetCulturesAsync();
|
private async Task DeleteLanguage(Language language)
|
||||||
var culture = cultures.First(c => c.Name.Equals(Constants.DefaultCulture));
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await LanguageService.DeleteLanguageAsync(language.LanguageId);
|
||||||
|
await logger.LogInformation("Language Deleted {Language}", language);
|
||||||
|
await GetLanguages();
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Deleting Language {Language} {Error}", language, ex.Message);
|
||||||
|
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
AddModuleMessage(Localizer["Error.Language.Delete"], MessageType.Error);
|
||||||
{
|
}
|
||||||
_packages = await PackageService.GetPackagesAsync("translation");
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task DeleteLanguage(Language language)
|
private Package TranslationAvailable(string code, string version)
|
||||||
{
|
{
|
||||||
try
|
return _packages?.FirstOrDefault(item => item.PackageId == (Constants.PackageId + "." + code));
|
||||||
{
|
}
|
||||||
await LanguageService.DeleteLanguageAsync(language.LanguageId);
|
|
||||||
await logger.LogInformation("Language Deleted {Language}", language);
|
|
||||||
|
|
||||||
StateHasChanged();
|
private async Task GetPackage(string code, string version)
|
||||||
}
|
{
|
||||||
catch (Exception ex)
|
try
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Deleting Language {Language} {Error}", language, ex.Message);
|
_package = await PackageService.GetPackageAsync(Constants.PackageId + "." + code, version);
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Getting Package {PackageId} {Version}", Constants.PackageId + "." + code, Constants.Version);
|
||||||
|
AddModuleMessage(Localizer["Error.Translation.Download"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AddModuleMessage(Localizer["Error.Language.Delete"], MessageType.Error);
|
private async Task DownloadPackage()
|
||||||
}
|
{
|
||||||
}
|
try
|
||||||
|
{
|
||||||
|
await PackageService.DownloadPackageAsync(_package.PackageId, _package.Version, Constants.PackagesFolder);
|
||||||
|
await logger.LogInformation("Language Package {Name} {Version} Downloaded Successfully", _package.PackageId, _package.Version);
|
||||||
|
AddModuleMessage(string.Format(Localizer["Success.Language.Download"], NavigateUrl("admin/system")), MessageType.Success);
|
||||||
|
_package = null;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Downloading Translation {Name} {Version}", _package.PackageId, _package.Version);
|
||||||
|
AddModuleMessage(Localizer["Error.Language.Download"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private bool UpgradeAvailable(string code, string version)
|
private void HideModal()
|
||||||
{
|
{
|
||||||
var upgradeavailable = false;
|
_package = null;
|
||||||
if (_packages != null && version != null)
|
StateHasChanged();
|
||||||
{
|
}
|
||||||
var package = _packages.Where(item => item.PackageId == (Constants.PackageId + "." + code)).FirstOrDefault();
|
|
||||||
if (package != null)
|
|
||||||
{
|
|
||||||
upgradeavailable = (Version.Parse(package.Version).CompareTo(Version.Parse(Constants.Version)) == 0) &&
|
|
||||||
(Version.Parse(package.Version).CompareTo(Version.Parse(version)) > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return upgradeavailable;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task DownloadLanguage(string code)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
|
||||||
{
|
|
||||||
await PackageService.DownloadPackageAsync(Constants.PackageId + "." + 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Downloading Translation {Code} {Version} {Error}", code, Constants.Version, ex.Message);
|
|
||||||
AddModuleMessage(Localizer["Error.Language.Download"], MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
@using System.Net
|
||||||
@namespace Oqtane.Modules.Admin.Login
|
@namespace Oqtane.Modules.Admin.Login
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@ -33,7 +34,7 @@
|
|||||||
<Label Class="control-label" For="password" HelpText="Please enter your Password" ResourceKey="Password">Password:</Label>
|
<Label Class="control-label" For="password" HelpText="Please enter your Password" ResourceKey="Password">Password:</Label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="password" type="@_passwordtype" name="Password" class="form-control" placeholder="@Localizer["Password.Placeholder"]" @bind="@_password" required />
|
<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>
|
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group mt-2">
|
<div class="form-group mt-2">
|
||||||
@ -205,7 +206,7 @@
|
|||||||
var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider
|
var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider
|
||||||
.GetService(typeof(IdentityAuthenticationStateProvider));
|
.GetService(typeof(IdentityAuthenticationStateProvider));
|
||||||
authstateprovider.NotifyAuthenticationChanged();
|
authstateprovider.NotifyAuthenticationChanged();
|
||||||
NavigationManager.NavigateTo(NavigateUrl(_returnUrl, true));
|
NavigationManager.NavigateTo(NavigateUrl(WebUtility.UrlDecode(_returnUrl), true));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -106,12 +106,6 @@ else
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// external link to log item will display Details component
|
|
||||||
if (PageState.QueryString.ContainsKey("id") && int.TryParse(PageState.QueryString["id"], out int id))
|
|
||||||
{
|
|
||||||
NavigationManager.NavigateTo(EditUrl(PageState.Page.Path, ModuleState.ModuleId, "Detail", $"/{id}"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UrlParameters.ContainsKey("level"))
|
if (UrlParameters.ContainsKey("level"))
|
||||||
{
|
{
|
||||||
_level = UrlParameters["level"];
|
_level = UrlParameters["level"];
|
||||||
@ -241,4 +235,15 @@ else
|
|||||||
_page = page;
|
_page = page;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnAfterRender(bool firstRender)
|
||||||
|
{
|
||||||
|
if (firstRender)
|
||||||
|
{
|
||||||
|
// external link to log item will display Details component
|
||||||
|
if (PageState.QueryString.ContainsKey("id") && int.TryParse(PageState.QueryString["id"], out int id))
|
||||||
|
{
|
||||||
|
NavigationManager.NavigateTo(EditUrl(PageState.Page.Path, ModuleState.ModuleId, "Detail", $"/{id}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,7 +131,7 @@ else
|
|||||||
moduleDefinition = await ModuleDefinitionService.CreateModuleDefinitionAsync(moduleDefinition);
|
moduleDefinition = await ModuleDefinitionService.CreateModuleDefinitionAsync(moduleDefinition);
|
||||||
|
|
||||||
var settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId);
|
var settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId);
|
||||||
SettingService.SetSetting(settings, "ModuleDefinitionName", moduleDefinition.ModuleDefinitionName);
|
settings = SettingService.SetSetting(settings, "ModuleDefinitionName", moduleDefinition.ModuleDefinitionName);
|
||||||
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
|
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
|
||||||
|
|
||||||
GetLocation();
|
GetLocation();
|
||||||
@ -174,7 +174,7 @@ else
|
|||||||
private bool IsValid(string name)
|
private bool IsValid(string name)
|
||||||
{
|
{
|
||||||
// must contain letters, underscores and digits and first character must be letter or underscore
|
// must contain letters, underscores and digits and first character must be letter or underscore
|
||||||
return !string.IsNullOrEmpty(name) && name.ToLower() != "module" && Regex.IsMatch(name, "^[A-Za-z_][A-Za-z0-9_]*$");
|
return !string.IsNullOrEmpty(name) && name.ToLower() != "module" && !name.ToLower().Contains("oqtane") && Regex.IsMatch(name, "^[A-Za-z_][A-Za-z0-9_]*$");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TemplateChanged(ChangeEventArgs e)
|
private void TemplateChanged(ChangeEventArgs e)
|
||||||
|
@ -65,13 +65,15 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
<br />
|
||||||
|
<ModuleMessage Type="MessageType.Info" Message="@SharedLocalizer["Oqtane.Marketplace"]" />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel Name="Upload" ResourceKey="Upload">
|
<TabPanel Name="Upload" ResourceKey="Upload">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" HelpText="Upload one or more module packages. Once they are uploaded click Install to complete the installation." ResourceKey="Module">Module: </Label>
|
<Label Class="col-sm-3" HelpText="Upload one or more module packages. Once they are uploaded click Install to complete the installation." ResourceKey="Module">Module: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<FileManager Folder="@Constants.PackagesFolder" UploadMultiple="true" />
|
<FileManager Folder="@Constants.PackagesFolder" UploadMultiple="true" OnUpload="OnUpload" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -111,153 +113,140 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
<button type="button" class="btn btn-success" @onclick="InstallModules">@SharedLocalizer["Install"]</button>
|
|
||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<ModuleMessage Type="MessageType.Info" Message="@SharedLocalizer["Oqtane.Marketplace"]" />
|
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<Package> _packages;
|
private List<Package> _packages;
|
||||||
private string _price = "free";
|
private string _price = "free";
|
||||||
private string _search = "";
|
private string _search = "";
|
||||||
private string _productname = "";
|
private string _productname = "";
|
||||||
private string _packageid = "";
|
private string _packageid = "";
|
||||||
private string _packagelicense = "";
|
private string _packagelicense = "";
|
||||||
private string _packageversion = "";
|
private string _packageversion = "";
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await LoadModuleDefinitions();
|
await LoadModuleDefinitions();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Loading Packages {Error}", ex.Message);
|
await logger.LogError(ex, "Error Loading Packages {Error}", ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.Package.Load"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Package.Load"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task LoadModuleDefinitions()
|
private async Task LoadModuleDefinitions()
|
||||||
{
|
{
|
||||||
var moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
|
var moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
|
||||||
_packages = await PackageService.GetPackagesAsync("module", _search, _price, "");
|
_packages = await PackageService.GetPackagesAsync("module", _search, _price, "");
|
||||||
|
|
||||||
if (_packages != null)
|
if (_packages != null)
|
||||||
{
|
{
|
||||||
foreach (Package package in _packages.ToArray())
|
foreach (Package package in _packages.ToArray())
|
||||||
{
|
{
|
||||||
if (moduledefinitions.Exists(item => item.PackageName == package.PackageId))
|
if (moduledefinitions.Exists(item => item.PackageName == package.PackageId))
|
||||||
{
|
{
|
||||||
_packages.Remove(package);
|
_packages.Remove(package);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void PriceChanged(ChangeEventArgs e)
|
private async void PriceChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_price = (string)e.Value;
|
_price = (string)e.Value;
|
||||||
_search = "";
|
_search = "";
|
||||||
await LoadModuleDefinitions();
|
await LoadModuleDefinitions();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error On PriceChanged");
|
await logger.LogError(ex, "Error On PriceChanged");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Search()
|
private async Task Search()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await LoadModuleDefinitions();
|
await LoadModuleDefinitions();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error On Search");
|
await logger.LogError(ex, "Error On Search");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Reset()
|
private async Task Reset()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_search = "";
|
_search = "";
|
||||||
await LoadModuleDefinitions();
|
await LoadModuleDefinitions();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error On Reset");
|
await logger.LogError(ex, "Error On Reset");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HideModal()
|
private void HideModal()
|
||||||
{
|
{
|
||||||
_productname = "";
|
_productname = "";
|
||||||
_packagelicense = "";
|
_packagelicense = "";
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task GetPackage(string packageid, string version)
|
private async Task GetPackage(string packageid, string version)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var package = await PackageService.GetPackageAsync(packageid, version);
|
var package = await PackageService.GetPackageAsync(packageid, version);
|
||||||
if (package != null)
|
if (package != null)
|
||||||
{
|
{
|
||||||
_productname = package.Name;
|
_productname = package.Name;
|
||||||
_packageid = package.PackageId;
|
_packageid = package.PackageId;
|
||||||
if (!string.IsNullOrEmpty(package.License))
|
if (!string.IsNullOrEmpty(package.License))
|
||||||
{
|
{
|
||||||
_packagelicense = package.License.Replace("\n", "<br />");
|
_packagelicense = package.License.Replace("\n", "<br />");
|
||||||
}
|
}
|
||||||
_packageversion = package.Version;
|
_packageversion = package.Version;
|
||||||
}
|
}
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Getting Package {PackageId} {Version}", packageid, version);
|
await logger.LogError(ex, "Error Getting Package {PackageId} {Version}", packageid, version);
|
||||||
AddModuleMessage(Localizer["Error.Module.Download"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Module.Download"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DownloadPackage()
|
private async Task DownloadPackage()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await PackageService.DownloadPackageAsync(_packageid, _packageversion, Constants.PackagesFolder);
|
await PackageService.DownloadPackageAsync(_packageid, _packageversion, Constants.PackagesFolder);
|
||||||
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _packageid, _packageversion);
|
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _packageid, _packageversion);
|
||||||
AddModuleMessage(Localizer["Success.Module.Download"], MessageType.Success);
|
AddModuleMessage(string.Format(Localizer["Success.Module.Download"], NavigateUrl("admin/system")), MessageType.Success);
|
||||||
_productname = "";
|
_productname = "";
|
||||||
_packagelicense = "";
|
_packagelicense = "";
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Downloading Package {PackageId} {Version}", _packageid, _packageversion);
|
await logger.LogError(ex, "Error Downloading Package {PackageId} {Version}", _packageid, _packageversion);
|
||||||
AddModuleMessage(Localizer["Error.Module.Download"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Module.Download"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task InstallModules()
|
private void OnUpload()
|
||||||
{
|
{
|
||||||
try
|
AddModuleMessage(string.Format(Localizer["Success.Module.Download"], NavigateUrl("admin/system")), MessageType.Success);
|
||||||
{
|
}
|
||||||
await ModuleDefinitionService.InstallModuleDefinitionsAsync();
|
|
||||||
AddModuleMessage(string.Format(Localizer["Success.Module.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Installing Modules");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,7 @@
|
|||||||
private bool IsValid(string name)
|
private bool IsValid(string name)
|
||||||
{
|
{
|
||||||
// must contain letters, underscores and digits and first character must be letter or underscore
|
// must contain letters, underscores and digits and first character must be letter or underscore
|
||||||
return !string.IsNullOrEmpty(name) && name.ToLower() != "module" && Regex.IsMatch(name, "^[A-Za-z_][A-Za-z0-9_]*$");
|
return !string.IsNullOrEmpty(name) && name.ToLower() != "module" && !name.ToLower().Contains("oqtane") && Regex.IsMatch(name, "^[A-Za-z_][A-Za-z0-9_]*$");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TemplateChanged(ChangeEventArgs e)
|
private void TemplateChanged(ChangeEventArgs e)
|
||||||
|
@ -9,280 +9,304 @@
|
|||||||
@inject IStringLocalizer<Edit> Localizer
|
@inject IStringLocalizer<Edit> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
<TabStrip>
|
@if (_initialized)
|
||||||
<TabPanel Name="Definition" ResourceKey="Definition">
|
{
|
||||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
<TabStrip>
|
||||||
<div class="container">
|
<TabPanel Name="Definition" ResourceKey="Definition">
|
||||||
<div class="row mb-1 align-items-center">
|
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||||
<Label Class="col-sm-3" For="name" HelpText="The name of the module" ResourceKey="Name">Name: </Label>
|
<div class="container">
|
||||||
<div class="col-sm-9">
|
<div class="row mb-1 align-items-center">
|
||||||
<input id="name" class="form-control" @bind="@_name" maxlength="200" required />
|
<Label Class="col-sm-3" For="name" HelpText="The name of the module" ResourceKey="Name">Name: </Label>
|
||||||
</div>
|
<div class="col-sm-9">
|
||||||
</div>
|
<input id="name" class="form-control" @bind="@_name" maxlength="200" required />
|
||||||
<div class="row mb-1 align-items-center">
|
</div>
|
||||||
<Label Class="col-sm-3" For="description" HelpText="The description of the module" ResourceKey="Description">Description: </Label>
|
</div>
|
||||||
<div class="col-sm-9">
|
<div class="row mb-1 align-items-center">
|
||||||
<textarea id="description" class="form-control" @bind="@_description" rows="2" maxlength="2000" required></textarea>
|
<Label Class="col-sm-3" For="description" HelpText="The description of the module" ResourceKey="Description">Description: </Label>
|
||||||
</div>
|
<div class="col-sm-9">
|
||||||
</div>
|
<textarea id="description" class="form-control" @bind="@_description" rows="2" maxlength="2000" required></textarea>
|
||||||
<div class="row mb-1 align-items-center">
|
</div>
|
||||||
<Label Class="col-sm-3" For="categories" HelpText="Comma delimited list of module categories" ResourceKey="Categories">Categories: </Label>
|
</div>
|
||||||
<div class="col-sm-9">
|
<div class="row mb-1 align-items-center">
|
||||||
<input id="categories" class="form-control" @bind="@_categories" maxlength="200" required />
|
<Label Class="col-sm-3" For="categories" HelpText="Comma delimited list of module categories" ResourceKey="Categories">Categories: </Label>
|
||||||
</div>
|
<div class="col-sm-9">
|
||||||
</div>
|
<input id="categories" class="form-control" @bind="@_categories" maxlength="200" required />
|
||||||
</div>
|
</div>
|
||||||
</form>
|
|
||||||
<Section Name="Information" ResourceKey="Information">
|
|
||||||
<div class="container">
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="moduledefinitionname" HelpText="The internal name of the module" ResourceKey="InternalName">Internal Name: </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input id="moduledefinitionname" class="form-control" @bind="@_moduledefinitionname" disabled />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="version" HelpText="The version of the module" ResourceKey="Version">Version: </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input id="version" class="form-control" @bind="@_version" disabled />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="packagename" HelpText="The unique name of the package from which this module was installed" ResourceKey="PackageName">Package Name: </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
</form>
|
||||||
<Label Class="col-sm-3" For="owner" HelpText="The owner or creator of the module" ResourceKey="Owner">Owner: </Label>
|
<Section Name="Information" ResourceKey="Information">
|
||||||
<div class="col-sm-9">
|
<div class="container">
|
||||||
<input id="owner" class="form-control" @bind="@_owner" disabled />
|
<div class="row mb-1 align-items-center">
|
||||||
</div>
|
<Label Class="col-sm-3" For="moduledefinitionname" HelpText="The internal name of the module" ResourceKey="InternalName">Internal Name: </Label>
|
||||||
</div>
|
<div class="col-sm-9">
|
||||||
<div class="row mb-1 align-items-center">
|
<input id="moduledefinitionname" class="form-control" @bind="@_moduledefinitionname" disabled />
|
||||||
<Label Class="col-sm-3" For="url" HelpText="The reference url of the module" ResourceKey="ReferenceUrl">Reference Url: </Label>
|
</div>
|
||||||
<div class="col-sm-9">
|
</div>
|
||||||
<input id="url" class="form-control" @bind="@_url" disabled />
|
<div class="row mb-1 align-items-center">
|
||||||
</div>
|
<Label Class="col-sm-3" For="version" HelpText="The version of the module" ResourceKey="Version">Version: </Label>
|
||||||
</div>
|
<div class="col-sm-9">
|
||||||
<div class="row mb-1 align-items-center">
|
<input id="version" class="form-control" @bind="@_version" disabled />
|
||||||
<Label Class="col-sm-3" For="contact" HelpText="The contact for the module" ResourceKey="Contact">Contact: </Label>
|
</div>
|
||||||
<div class="col-sm-9">
|
</div>
|
||||||
<input id="contact" class="form-control" @bind="@_contact" disabled />
|
<div class="row mb-1 align-items-center">
|
||||||
</div>
|
<Label Class="col-sm-3" For="packagename" HelpText="The unique name of the package from which this module was installed" ResourceKey="PackageName">Package Name: </Label>
|
||||||
</div>
|
<div class="col-sm-9">
|
||||||
<div class="row mb-1 align-items-center">
|
<input id="packagename" class="form-control" @bind="@_packagename" disabled />
|
||||||
<Label Class="col-sm-3" For="license" HelpText="The module license terms" ResourceKey="License">License: </Label>
|
</div>
|
||||||
<div class="col-sm-9">
|
</div>
|
||||||
<textarea id="license" class="form-control" @bind="@_license" rows="5" disabled></textarea>
|
<div class="row mb-1 align-items-center">
|
||||||
</div>
|
<Label Class="col-sm-3" For="owner" HelpText="The owner or creator of the module" ResourceKey="Owner">Owner: </Label>
|
||||||
</div>
|
<div class="col-sm-9">
|
||||||
<div class="row mb-1 align-items-center">
|
<input id="owner" class="form-control" @bind="@_owner" disabled />
|
||||||
<Label Class="col-sm-3" For="runtimes" HelpText="The Blazor runtimes which this module supports" ResourceKey="Runtimes">Runtimes: </Label>
|
</div>
|
||||||
<div class="col-sm-9">
|
</div>
|
||||||
<input id="runtimes" class="form-control" @bind="@_runtimes" disabled />
|
<div class="row mb-1 align-items-center">
|
||||||
</div>
|
<Label Class="col-sm-3" For="url" HelpText="The reference url of the module" ResourceKey="ReferenceUrl">Reference Url: </Label>
|
||||||
</div>
|
<div class="col-sm-9">
|
||||||
</div>
|
<input id="url" class="form-control" @bind="@_url" disabled />
|
||||||
</Section>
|
</div>
|
||||||
<br />
|
</div>
|
||||||
<button type="button" class="btn btn-success" @onclick="SaveModuleDefinition">@SharedLocalizer["Save"]</button>
|
<div class="row mb-1 align-items-center">
|
||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
<Label Class="col-sm-3" For="contact" HelpText="The contact for the module" ResourceKey="Contact">Contact: </Label>
|
||||||
<br />
|
<div class="col-sm-9">
|
||||||
<br />
|
<input id="contact" class="form-control" @bind="@_contact" disabled />
|
||||||
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon"></AuditInfo>
|
</div>
|
||||||
</TabPanel>
|
</div>
|
||||||
<TabPanel Name="Permissions" ResourceKey="Permissions">
|
<div class="row mb-1 align-items-center">
|
||||||
<div class="container">
|
<Label Class="col-sm-3" For="license" HelpText="The module license terms" ResourceKey="License">License: </Label>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="col-sm-9">
|
||||||
<PermissionGrid EntityName="@EntityNames.ModuleDefinition" PermissionNames="@PermissionNames.Utilize" Permissions="@_permissions" @ref="_permissionGrid" />
|
<textarea id="license" class="form-control" @bind="@_license" rows="5" disabled></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-success" @onclick="SaveModuleDefinition">@SharedLocalizer["Save"]</button>
|
<div class="row mb-1 align-items-center">
|
||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
<Label Class="col-sm-3" For="runtimes" HelpText="The Blazor runtimes which this module supports" ResourceKey="Runtimes">Runtimes: </Label>
|
||||||
</TabPanel>
|
<div class="col-sm-9">
|
||||||
<TabPanel Name="Translations" ResourceKey="Translations">
|
<input id="runtimes" class="form-control" @bind="@_runtimes" disabled />
|
||||||
@if (_languages != null && _languages.Count > 0)
|
</div>
|
||||||
{
|
</div>
|
||||||
<Pager Items="@_languages">
|
</div>
|
||||||
<Header>
|
</Section>
|
||||||
<th>@SharedLocalizer["Name"]</th>
|
|
||||||
<th>@Localizer["Code"]</th>
|
|
||||||
<th>@Localizer["Version"]</th>
|
|
||||||
<th style="width: 1px;"> </th>
|
|
||||||
</Header>
|
|
||||||
<Row>
|
|
||||||
<td>@context.Name</td>
|
|
||||||
<td>@context.Code</td>
|
|
||||||
<td>@context.Version</td>
|
|
||||||
<td>
|
|
||||||
@if (context.IsDefault)
|
|
||||||
{
|
|
||||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await GetPackage(_packagename + "." + context.Code))>@SharedLocalizer["Download"]</button>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (UpgradeAvailable(_packagename + "." + context.Code, context.Version))
|
|
||||||
{
|
|
||||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await DownloadPackage(_packagename + "." + context.Code))>@SharedLocalizer["Upgrade"]</button>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</td>
|
|
||||||
</Row>
|
|
||||||
</Pager>
|
|
||||||
<button type="button" class="btn btn-success" @onclick="InstallTranslations">@SharedLocalizer["Install"]</button>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<br />
|
<br />
|
||||||
<div class="mx-auto text-center">
|
<button type="button" class="btn btn-success" @onclick="SaveModuleDefinition">@SharedLocalizer["Save"]</button>
|
||||||
@Localizer["Search.NoResults"]
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon"></AuditInfo>
|
||||||
|
</TabPanel>
|
||||||
|
<TabPanel Name="Permissions" ResourceKey="Permissions">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<PermissionGrid EntityName="@EntityNames.ModuleDefinition" PermissionNames="@PermissionNames.Utilize" PermissionList="@_permissions" @ref="_permissionGrid" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
}
|
<button type="button" class="btn btn-success" @onclick="SaveModuleDefinition">@SharedLocalizer["Save"]</button>
|
||||||
</TabPanel>
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
</TabStrip>
|
</TabPanel>
|
||||||
|
<TabPanel Name="Translations" ResourceKey="Translations">
|
||||||
|
@if (_languages != null && _languages.Count > 0)
|
||||||
|
{
|
||||||
|
<Pager Items="@_languages">
|
||||||
|
<Header>
|
||||||
|
<th>@SharedLocalizer["Name"]</th>
|
||||||
|
<th>@Localizer["Code"]</th>
|
||||||
|
<th style="width: 1px;">@Localizer["Version"]</th>
|
||||||
|
<th style="width: 1px;"> </th>
|
||||||
|
</Header>
|
||||||
|
<Row>
|
||||||
|
<td>@context.Name</td>
|
||||||
|
<td>@context.Code</td>
|
||||||
|
<td>@((string.IsNullOrEmpty(context.Version)) ? "---" : context.Version)</td>
|
||||||
|
<td>
|
||||||
|
@switch (TranslationAvailable(_packagename + "." + context.Code, context.Version))
|
||||||
|
{
|
||||||
|
case "install":
|
||||||
|
<button type="button" class="btn btn-success" @onclick=@(async () => await GetPackage(_packagename + "." + context.Code))>@SharedLocalizer["Download"]</button>
|
||||||
|
break;
|
||||||
|
case "upgrade":
|
||||||
|
<button type="button" class="btn btn-success" @onclick=@(async () => await GetPackage(_packagename + "." + context.Code))>@SharedLocalizer["Upgrade"]</button>
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
</Row>
|
||||||
|
</Pager>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<br />
|
||||||
|
<div class="mx-auto text-center">
|
||||||
|
@if (string.IsNullOrEmpty(_packagename))
|
||||||
|
{
|
||||||
|
@Localizer["Search.PackageNameMissing"]
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@Localizer["Search.NoResults"]
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
}
|
||||||
|
</TabPanel>
|
||||||
|
</TabStrip>
|
||||||
|
|
||||||
@if (_productname != "")
|
@if (_package != null)
|
||||||
{
|
{
|
||||||
<div class="app-actiondialog">
|
<div class="app-actiondialog">
|
||||||
<div class="modal" tabindex="-1" role="dialog">
|
<div class="modal" tabindex="-1" role="dialog">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title">@SharedLocalizer["Review License Terms"]</h5>
|
<h5 class="modal-title">@SharedLocalizer["Review License Terms"]</h5>
|
||||||
<button type="button" class="btn-close" aria-label="Close" @onclick="HideModal"></button>
|
<button type="button" class="btn-close" aria-label="Close" @onclick="HideModal"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p style="height: 200px; overflow-y: scroll;">
|
<p style="height: 200px; overflow-y: scroll;">
|
||||||
<h3>@_productname</h3>
|
<h4 style="display: inline;"><a href="@_package.ProductUrl" target="_new">@_package.Name</a></h4><br />
|
||||||
@if (!string.IsNullOrEmpty(_packagelicense))
|
@SharedLocalizer["Search.By"]: <strong><a href="@_package.OwnerUrl" target="new">@_package.Owner</a></strong><br />
|
||||||
{
|
@(_package.Description.Length > 400 ? (_package.Description.Substring(0, 400) + "...") : _package.Description)<br />
|
||||||
@((MarkupString)_packagelicense)
|
<strong>@(String.Format("{0:n0}", _package.Downloads))</strong> @SharedLocalizer["Search.Downloads"] |
|
||||||
}
|
@SharedLocalizer["Search.Released"]: <strong>@_package.ReleaseDate.ToString("MMM dd, yyyy")</strong> |
|
||||||
else
|
@SharedLocalizer["Search.Version"]: <strong>@_package.Version</strong>
|
||||||
{
|
@((MarkupString)(!string.IsNullOrEmpty(_package.PackageUrl) ? " | " + SharedLocalizer["Search.Source"] + ": <strong>" + new Uri(_package.PackageUrl).Host + "</strong>" : ""))
|
||||||
@SharedLocalizer["License Not Specified"]
|
<br /><br />
|
||||||
}
|
@if (!string.IsNullOrEmpty(_package.License))
|
||||||
</p>
|
{
|
||||||
</div>
|
@((MarkupString)_package.License.Replace("\n", "<br />"))
|
||||||
<div class="modal-footer">
|
}
|
||||||
<button type="button" class="btn btn-success" @onclick=@(async () => await DownloadPackage(_packageid))>@SharedLocalizer["Accept"]</button>
|
else
|
||||||
<button type="button" class="btn btn-secondary" @onclick="HideModal">@SharedLocalizer["Cancel"]</button>
|
{
|
||||||
|
@SharedLocalizer["License Not Specified"]
|
||||||
|
}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-success" @onclick="DownloadPackage">@SharedLocalizer["Accept"]</button>
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="HideModal">@SharedLocalizer["Cancel"]</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private ElementReference form;
|
private bool _initialized = false;
|
||||||
private bool validated = false;
|
private ElementReference form;
|
||||||
private int _moduleDefinitionId;
|
private bool validated = false;
|
||||||
private string _name;
|
private int _moduleDefinitionId;
|
||||||
private string _description = "";
|
private string _name;
|
||||||
private string _categories;
|
private string _description = "";
|
||||||
private string _moduledefinitionname = "";
|
private string _categories;
|
||||||
private string _version;
|
private string _moduledefinitionname = "";
|
||||||
private string _packagename = "";
|
private string _version;
|
||||||
private string _owner = "";
|
private string _packagename = "";
|
||||||
private string _url = "";
|
private string _owner = "";
|
||||||
private string _contact = "";
|
private string _url = "";
|
||||||
private string _license = "";
|
private string _contact = "";
|
||||||
private string _runtimes = "";
|
private string _license = "";
|
||||||
private string _permissions;
|
private string _runtimes = "";
|
||||||
private string _createdby;
|
private List<Permission> _permissions = null;
|
||||||
private DateTime _createdon;
|
private string _createdby;
|
||||||
private string _modifiedby;
|
private DateTime _createdon;
|
||||||
private DateTime _modifiedon;
|
private string _modifiedby;
|
||||||
|
private DateTime _modifiedon;
|
||||||
|
|
||||||
#pragma warning disable 649
|
#pragma warning disable 649
|
||||||
private PermissionGrid _permissionGrid;
|
private PermissionGrid _permissionGrid;
|
||||||
#pragma warning restore 649
|
#pragma warning restore 649
|
||||||
|
|
||||||
private List<Package> _packages;
|
private List<Package> _packages;
|
||||||
private List<Language> _languages;
|
private List<Language> _languages;
|
||||||
private string _productname = "";
|
private Package _package;
|
||||||
private string _packagelicense = "";
|
|
||||||
private string _packageid = "";
|
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_moduleDefinitionId = Int32.Parse(PageState.QueryString["id"]);
|
_moduleDefinitionId = Int32.Parse(PageState.QueryString["id"]);
|
||||||
var moduleDefinition = await ModuleDefinitionService.GetModuleDefinitionAsync(_moduleDefinitionId, ModuleState.SiteId);
|
var moduleDefinition = await ModuleDefinitionService.GetModuleDefinitionAsync(_moduleDefinitionId, ModuleState.SiteId);
|
||||||
if (moduleDefinition != null)
|
if (moduleDefinition != null)
|
||||||
{
|
{
|
||||||
_name = moduleDefinition.Name;
|
_name = moduleDefinition.Name;
|
||||||
_description = moduleDefinition.Description;
|
_description = moduleDefinition.Description;
|
||||||
_categories = moduleDefinition.Categories;
|
_categories = moduleDefinition.Categories;
|
||||||
_moduledefinitionname = moduleDefinition.ModuleDefinitionName;
|
_moduledefinitionname = moduleDefinition.ModuleDefinitionName;
|
||||||
_version = moduleDefinition.Version;
|
_version = moduleDefinition.Version;
|
||||||
_packagename = moduleDefinition.PackageName;
|
_packagename = moduleDefinition.PackageName;
|
||||||
_owner = moduleDefinition.Owner;
|
_owner = moduleDefinition.Owner;
|
||||||
_url = moduleDefinition.Url;
|
_url = moduleDefinition.Url;
|
||||||
_contact = moduleDefinition.Contact;
|
_contact = moduleDefinition.Contact;
|
||||||
_license = moduleDefinition.License;
|
_license = moduleDefinition.License;
|
||||||
_runtimes = moduleDefinition.Runtimes;
|
_runtimes = moduleDefinition.Runtimes;
|
||||||
_permissions = moduleDefinition.Permissions;
|
_permissions = moduleDefinition.PermissionList;
|
||||||
_createdby = moduleDefinition.CreatedBy;
|
_createdby = moduleDefinition.CreatedBy;
|
||||||
_createdon = moduleDefinition.CreatedOn;
|
_createdon = moduleDefinition.CreatedOn;
|
||||||
_modifiedby = moduleDefinition.ModifiedBy;
|
_modifiedby = moduleDefinition.ModifiedBy;
|
||||||
_modifiedon = moduleDefinition.ModifiedOn;
|
_modifiedon = moduleDefinition.ModifiedOn;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(_packagename))
|
if (!string.IsNullOrEmpty(_packagename))
|
||||||
{
|
{
|
||||||
_packages = await PackageService.GetPackagesAsync("translation", "", "", _packagename);
|
_packages = await PackageService.GetPackagesAsync("translation", "", "", _packagename);
|
||||||
_languages = await LanguageService.GetLanguagesAsync(-1, _packagename);
|
_languages = await LanguageService.GetLanguagesAsync(-1, _packagename);
|
||||||
foreach (var package in _packages)
|
foreach (var package in _packages)
|
||||||
{
|
{
|
||||||
var code = package.PackageId.Split('.').Last();
|
var code = package.PackageId.Split('.').Last();
|
||||||
if (!_languages.Any(item => item.Code == code))
|
if (!_languages.Any(item => item.Code == code))
|
||||||
{
|
{
|
||||||
_languages.Add(new Language { Code = code, Name = CultureInfo.GetCultureInfo(code).DisplayName, Version = package.Version, IsDefault = true });
|
_languages.Add(new Language { Code = code, Name = CultureInfo.GetCultureInfo(code).DisplayName, Version = package.Version, IsDefault = true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_languages = _languages.OrderBy(item => item.Name).ToList();
|
_languages = _languages.OrderBy(item => item.Name).ToList();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Loading ModuleDefinition {ModuleDefinitionId} {Error}", _moduleDefinitionId, ex.Message);
|
|
||||||
AddModuleMessage(Localizer["Error.Module.Load"], MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SaveModuleDefinition()
|
_initialized = true;
|
||||||
{
|
}
|
||||||
validated = true;
|
}
|
||||||
var interop = new Interop(JSRuntime);
|
catch (Exception ex)
|
||||||
if (await interop.FormValid(form))
|
{
|
||||||
{
|
await logger.LogError(ex, "Error Loading ModuleDefinition {ModuleDefinitionId} {Error}", _moduleDefinitionId, ex.Message);
|
||||||
try
|
AddModuleMessage(Localizer["Error.Module.Load"], MessageType.Error);
|
||||||
{
|
}
|
||||||
var moduledefinition = await ModuleDefinitionService.GetModuleDefinitionAsync(_moduleDefinitionId, ModuleState.SiteId);
|
}
|
||||||
if (moduledefinition.Name != _name)
|
|
||||||
{
|
private async Task SaveModuleDefinition()
|
||||||
moduledefinition.Name = _name;
|
{
|
||||||
}
|
validated = true;
|
||||||
if (moduledefinition.Description != _description)
|
var interop = new Interop(JSRuntime);
|
||||||
{
|
if (await interop.FormValid(form))
|
||||||
moduledefinition.Description = _description;
|
{
|
||||||
}
|
try
|
||||||
if (moduledefinition.Categories != _categories)
|
{
|
||||||
{
|
var moduleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
|
||||||
moduledefinition.Categories = _categories;
|
if (!moduleDefinitions.Any(item => item.Name.ToLower() == _name.ToLower() && item.ModuleDefinitionId != _moduleDefinitionId))
|
||||||
}
|
{
|
||||||
moduledefinition.Permissions = _permissionGrid.GetPermissions();
|
var moduledefinition = await ModuleDefinitionService.GetModuleDefinitionAsync(_moduleDefinitionId, ModuleState.SiteId);
|
||||||
await ModuleDefinitionService.UpdateModuleDefinitionAsync(moduledefinition);
|
if (moduledefinition.Name != _name)
|
||||||
await logger.LogInformation("ModuleDefinition Saved {ModuleDefinition}", moduledefinition);
|
{
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
moduledefinition.Name = _name;
|
||||||
}
|
}
|
||||||
|
if (moduledefinition.Description != _description)
|
||||||
|
{
|
||||||
|
moduledefinition.Description = _description;
|
||||||
|
}
|
||||||
|
if (moduledefinition.Categories != _categories)
|
||||||
|
{
|
||||||
|
moduledefinition.Categories = _categories;
|
||||||
|
}
|
||||||
|
moduledefinition.PermissionList = _permissionGrid.GetPermissionList();
|
||||||
|
await ModuleDefinitionService.UpdateModuleDefinitionAsync(moduledefinition);
|
||||||
|
await logger.LogInformation("ModuleDefinition Saved {ModuleDefinition}", moduledefinition);
|
||||||
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.DuplicateName"], MessageType.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Saving ModuleDefinition {ModuleDefinitionId} {Error}", _moduleDefinitionId, ex.Message);
|
await logger.LogError(ex, "Error Saving ModuleDefinition {ModuleDefinitionId} {Error}", _moduleDefinitionId, ex.Message);
|
||||||
@ -297,24 +321,31 @@
|
|||||||
|
|
||||||
private void HideModal()
|
private void HideModal()
|
||||||
{
|
{
|
||||||
_productname = "";
|
_package = null;
|
||||||
_packagelicense = "";
|
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool UpgradeAvailable(string packagename, string version)
|
private string TranslationAvailable(string packagename, string version)
|
||||||
{
|
{
|
||||||
var upgradeavailable = false;
|
|
||||||
if (_packages != null)
|
if (_packages != null)
|
||||||
{
|
{
|
||||||
var package = _packages.Where(item => item.PackageId == packagename).FirstOrDefault();
|
var package = _packages.Where(item => item.PackageId == packagename).FirstOrDefault();
|
||||||
if (package != null)
|
if (package != null)
|
||||||
{
|
{
|
||||||
upgradeavailable = (Version.Parse(package.Version).CompareTo(Version.Parse(version)) > 0);
|
if (string.IsNullOrEmpty(version))
|
||||||
|
{
|
||||||
|
return "install";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Version.Parse(package.Version).CompareTo(Version.Parse(version)) > 0)
|
||||||
|
{
|
||||||
|
return "upgrade";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return upgradeavailable;
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task GetPackage(string packagename)
|
private async Task GetPackage(string packagename)
|
||||||
@ -322,16 +353,7 @@
|
|||||||
var version = _packages.Where(item => item.PackageId == packagename).FirstOrDefault().Version;
|
var version = _packages.Where(item => item.PackageId == packagename).FirstOrDefault().Version;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var package = await PackageService.GetPackageAsync(packagename, version);
|
_package = await PackageService.GetPackageAsync(packagename, version);
|
||||||
if (package != null)
|
|
||||||
{
|
|
||||||
_productname = package.Name;
|
|
||||||
if (!string.IsNullOrEmpty(package.License))
|
|
||||||
{
|
|
||||||
_packagelicense = package.License.Replace("\n", "<br />");
|
|
||||||
}
|
|
||||||
_packageid = package.PackageId;
|
|
||||||
}
|
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -341,16 +363,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DownloadPackage(string packagename)
|
private async Task DownloadPackage()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var version = _packages.Where(item => item.PackageId == packagename).FirstOrDefault().Version;
|
await PackageService.DownloadPackageAsync(_package.PackageId, _package.Version, Constants.PackagesFolder);
|
||||||
await PackageService.DownloadPackageAsync(packagename, version, Constants.PackagesFolder);
|
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _package.PackageId, _package.Version);
|
||||||
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", packagename, version);
|
AddModuleMessage(string.Format(Localizer["Success.Translation.Download"], NavigateUrl("admin/system")), MessageType.Success);
|
||||||
AddModuleMessage(Localizer["Success.Translation.Download"], MessageType.Success);
|
_package = null;
|
||||||
_productname = "";
|
|
||||||
_packagelicense = "";
|
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -359,17 +379,4 @@
|
|||||||
AddModuleMessage(Localizer["Error.Translation.Download"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Translation.Download"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task InstallTranslations()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await PackageService.InstallPackagesAsync();
|
|
||||||
AddModuleMessage(string.Format(Localizer["Success.Translation.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Installing Translations");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,6 @@ else
|
|||||||
{
|
{
|
||||||
await PackageService.DownloadPackageAsync(packagename, version, Constants.PackagesFolder);
|
await PackageService.DownloadPackageAsync(packagename, version, Constants.PackagesFolder);
|
||||||
await logger.LogInformation("Module Downloaded {ModuleDefinitionName} {Version}", packagename, version);
|
await logger.LogInformation("Module Downloaded {ModuleDefinitionName} {Version}", packagename, version);
|
||||||
await ModuleDefinitionService.InstallModuleDefinitionsAsync();
|
|
||||||
AddModuleMessage(string.Format(Localizer["Success.Module.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
AddModuleMessage(string.Format(Localizer["Success.Module.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
<select id="page" class="form-select" @bind="@_pageId" required>
|
<select id="page" class="form-select" @bind="@_pageId" required>
|
||||||
@foreach (Page p in PageState.Pages)
|
@foreach (Page p in PageState.Pages)
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||||
{
|
{
|
||||||
<option value="@p.PageId">@(new string('-', p.Level * 2))@(p.Name)</option>
|
<option value="@p.PageId">@(new string('-', p.Level * 2))@(p.Name)</option>
|
||||||
}
|
}
|
||||||
@ -62,7 +62,7 @@
|
|||||||
{
|
{
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<PermissionGrid EntityName="@EntityNames.Module" PermissionNames="@_permissionNames" Permissions="@_permissions" @ref="_permissionGrid" />
|
<PermissionGrid EntityName="@EntityNames.Module" PermissionNames="@_permissionNames" PermissionList="@_permissions" @ref="_permissionGrid" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -101,7 +101,7 @@
|
|||||||
private string _containerType;
|
private string _containerType;
|
||||||
private string _allPages = "false";
|
private string _allPages = "false";
|
||||||
private string _permissionNames = "";
|
private string _permissionNames = "";
|
||||||
private string _permissions = null;
|
private List<Permission> _permissions = null;
|
||||||
private string _pageId;
|
private string _pageId;
|
||||||
private PermissionGrid _permissionGrid;
|
private PermissionGrid _permissionGrid;
|
||||||
private Type _moduleSettingsType;
|
private Type _moduleSettingsType;
|
||||||
@ -123,7 +123,7 @@
|
|||||||
_containers = ThemeService.GetContainerControls(_themes, PageState.Page.ThemeType);
|
_containers = ThemeService.GetContainerControls(_themes, PageState.Page.ThemeType);
|
||||||
_containerType = ModuleState.ContainerType;
|
_containerType = ModuleState.ContainerType;
|
||||||
_allPages = ModuleState.AllPages.ToString();
|
_allPages = ModuleState.AllPages.ToString();
|
||||||
_permissions = ModuleState.Permissions;
|
_permissions = ModuleState.PermissionList;
|
||||||
_pageId = ModuleState.PageId.ToString();
|
_pageId = ModuleState.PageId.ToString();
|
||||||
createdby = ModuleState.CreatedBy;
|
createdby = ModuleState.CreatedBy;
|
||||||
createdon = ModuleState.CreatedOn;
|
createdon = ModuleState.CreatedOn;
|
||||||
@ -207,7 +207,7 @@
|
|||||||
var module = ModuleState;
|
var module = ModuleState;
|
||||||
module.AllPages = bool.Parse(_allPages);
|
module.AllPages = bool.Parse(_allPages);
|
||||||
module.PageModuleId = ModuleState.PageModuleId;
|
module.PageModuleId = ModuleState.PageModuleId;
|
||||||
module.Permissions = _permissionGrid.GetPermissions();
|
module.PermissionList = _permissionGrid.GetPermissionList();
|
||||||
await ModuleService.UpdateModuleAsync(module);
|
await ModuleService.UpdateModuleAsync(module);
|
||||||
|
|
||||||
if (_moduleSettingsType != null)
|
if (_moduleSettingsType != null)
|
||||||
|
@ -157,7 +157,8 @@
|
|||||||
</TabPanel>
|
</TabPanel>
|
||||||
}
|
}
|
||||||
</TabStrip>
|
</TabStrip>
|
||||||
<button type="button" class="btn btn-success" @onclick="SavePage">@SharedLocalizer["Save"]</button>
|
<br />
|
||||||
|
<button type="button" class="btn btn-success" @onclick="SavePage">@SharedLocalizer["Save"]</button>
|
||||||
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
@ -182,7 +183,7 @@
|
|||||||
private string _themetype = string.Empty;
|
private string _themetype = string.Empty;
|
||||||
private string _containertype = string.Empty;
|
private string _containertype = string.Empty;
|
||||||
private string _icon = string.Empty;
|
private string _icon = string.Empty;
|
||||||
private string _permissions = string.Empty;
|
private string _permissions = null;
|
||||||
private PermissionGrid _permissionGrid;
|
private PermissionGrid _permissionGrid;
|
||||||
private Type _themeSettingsType;
|
private Type _themeSettingsType;
|
||||||
private object _themeSettings;
|
private object _themeSettings;
|
||||||
@ -201,7 +202,6 @@
|
|||||||
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
|
||||||
_containertype = PageState.Site.DefaultContainerType;
|
_containertype = PageState.Site.DefaultContainerType;
|
||||||
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
|
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
|
||||||
_permissions = string.Empty;
|
|
||||||
ThemeSettings();
|
ThemeSettings();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -221,7 +221,7 @@
|
|||||||
{
|
{
|
||||||
foreach (Page p in PageState.Pages.Where(item => item.ParentId == null))
|
foreach (Page p in PageState.Pages.Where(item => item.ParentId == null))
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||||
{
|
{
|
||||||
_children.Add(p);
|
_children.Add(p);
|
||||||
}
|
}
|
||||||
@ -231,7 +231,7 @@
|
|||||||
{
|
{
|
||||||
foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)))
|
foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)))
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||||
{
|
{
|
||||||
_children.Add(p);
|
_children.Add(p);
|
||||||
}
|
}
|
||||||
@ -377,7 +377,7 @@
|
|||||||
page.DefaultContainerType = string.Empty;
|
page.DefaultContainerType = string.Empty;
|
||||||
}
|
}
|
||||||
page.Icon = (_icon == null ? string.Empty : _icon);
|
page.Icon = (_icon == null ? string.Empty : _icon);
|
||||||
page.Permissions = _permissionGrid.GetPermissions();
|
page.PermissionList = _permissionGrid.GetPermissionList();
|
||||||
page.IsPersonalizable = (_ispersonalizable == null ? false : Boolean.Parse(_ispersonalizable));
|
page.IsPersonalizable = (_ispersonalizable == null ? false : Boolean.Parse(_ispersonalizable));
|
||||||
page.UserId = null;
|
page.UserId = null;
|
||||||
page.Meta = _meta;
|
page.Meta = _meta;
|
||||||
|
@ -148,7 +148,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
<br /><br />
|
<br />
|
||||||
|
<br />
|
||||||
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon" DeletedBy="@_deletedby" DeletedOn="@_deletedon"></AuditInfo>
|
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon" DeletedBy="@_deletedby" DeletedOn="@_deletedon"></AuditInfo>
|
||||||
}
|
}
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
@ -157,7 +158,7 @@
|
|||||||
{
|
{
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<PermissionGrid EntityName="@EntityNames.Page" Permissions="@_permissions" @ref="_permissionGrid" />
|
<PermissionGrid EntityName="@EntityNames.Page" PermissionList="@_permissions" @ref="_permissionGrid" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@ -173,8 +174,8 @@
|
|||||||
<th>@Localizer["ModuleDefinition"]</th>
|
<th>@Localizer["ModuleDefinition"]</th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><ActionLink Action="Settings" Text="Edit" ModuleId="@context.ModuleId" Security="SecurityAccessLevel.Edit" Permissions="@context.Permissions" ResourceKey="ModuleSettings" /></td>
|
<td><ActionLink Action="Settings" Text="Edit" ModuleId="@context.ModuleId" Security="SecurityAccessLevel.Edit" PermissionList="@context.PermissionList" ResourceKey="ModuleSettings" /></td>
|
||||||
<td><ActionDialog Header="Delete Module" Message="Are You Sure You Wish To Delete This Module?" Action="Delete" Security="SecurityAccessLevel.Edit" Permissions="@context.Permissions" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" ResourceKey="DeleteModule" /></td>
|
<td><ActionDialog Header="Delete Module" Message="Are You Sure You Wish To Delete This Module?" Action="Delete" Security="SecurityAccessLevel.Edit" PermissionList="@context.PermissionList" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" ResourceKey="DeleteModule" /></td>
|
||||||
<td>@context.Title</td>
|
<td>@context.Title</td>
|
||||||
<td>@context.ModuleDefinition?.Name</td>
|
<td>@context.ModuleDefinition?.Name</td>
|
||||||
</Row>
|
</Row>
|
||||||
@ -189,7 +190,8 @@
|
|||||||
<br />
|
<br />
|
||||||
}
|
}
|
||||||
</TabStrip>
|
</TabStrip>
|
||||||
<button type="button" class="btn btn-success" @onclick="SavePage">@SharedLocalizer["Save"]</button>
|
<br />
|
||||||
|
<button type="button" class="btn btn-success" @onclick="SavePage">@SharedLocalizer["Save"]</button>
|
||||||
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
@ -219,7 +221,7 @@
|
|||||||
private string _themetype;
|
private string _themetype;
|
||||||
private string _containertype = "-";
|
private string _containertype = "-";
|
||||||
private string _icon;
|
private string _icon;
|
||||||
private string _permissions = null;
|
private List<Permission> _permissions = null;
|
||||||
private string _createdby;
|
private string _createdby;
|
||||||
private DateTime _createdon;
|
private DateTime _createdon;
|
||||||
private string _modifiedby;
|
private string _modifiedby;
|
||||||
@ -290,7 +292,7 @@
|
|||||||
_containertype = PageState.Site.DefaultContainerType;
|
_containertype = PageState.Site.DefaultContainerType;
|
||||||
}
|
}
|
||||||
_icon = page.Icon;
|
_icon = page.Icon;
|
||||||
_permissions = page.Permissions;
|
_permissions = page.PermissionList;
|
||||||
_createdby = page.CreatedBy;
|
_createdby = page.CreatedBy;
|
||||||
_createdon = page.CreatedOn;
|
_createdon = page.CreatedOn;
|
||||||
_modifiedby = page.ModifiedBy;
|
_modifiedby = page.ModifiedBy;
|
||||||
@ -337,7 +339,7 @@
|
|||||||
{
|
{
|
||||||
foreach (Page p in PageState.Pages.Where(item => item.ParentId == null))
|
foreach (Page p in PageState.Pages.Where(item => item.ParentId == null))
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||||
{
|
{
|
||||||
_children.Add(p);
|
_children.Add(p);
|
||||||
}
|
}
|
||||||
@ -347,7 +349,7 @@
|
|||||||
{
|
{
|
||||||
foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)))
|
foreach (Page p in PageState.Pages.Where(item => item.ParentId == int.Parse(_parentid)))
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||||
{
|
{
|
||||||
_children.Add(p);
|
_children.Add(p);
|
||||||
}
|
}
|
||||||
@ -507,7 +509,7 @@
|
|||||||
page.DefaultContainerType = string.Empty;
|
page.DefaultContainerType = string.Empty;
|
||||||
}
|
}
|
||||||
page.Icon = _icon ?? string.Empty;
|
page.Icon = _icon ?? string.Empty;
|
||||||
page.Permissions = _permissionGrid.GetPermissions();
|
page.PermissionList = _permissionGrid.GetPermissionList();
|
||||||
page.IsPersonalizable = (_ispersonalizable != null && Boolean.Parse(_ispersonalizable));
|
page.IsPersonalizable = (_ispersonalizable != null && Boolean.Parse(_ispersonalizable));
|
||||||
page.UserId = null;
|
page.UserId = null;
|
||||||
page.Meta = _meta;
|
page.Meta = _meta;
|
||||||
|
@ -104,7 +104,7 @@
|
|||||||
private string modifiedby;
|
private string modifiedby;
|
||||||
private DateTime modifiedon;
|
private DateTime modifiedon;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||||
|
|
||||||
public override string Actions => "Add,Edit";
|
public override string Actions => "Add,Edit";
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<ActionLink Action="Add" Security="SecurityAccessLevel.Admin" Text="Add Profile" ResourceKey="AddProfile" />
|
<ActionLink Action="Add" Text="Add Profile" Security="SecurityAccessLevel.Edit" ResourceKey="AddProfile" />
|
||||||
|
|
||||||
<Pager Items="@_profiles">
|
<Pager Items="@_profiles">
|
||||||
<Header>
|
<Header>
|
||||||
@ -19,8 +19,8 @@ else
|
|||||||
<th>@SharedLocalizer["Name"]</th>
|
<th>@SharedLocalizer["Name"]</th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ProfileId.ToString())" ResourceKey="EditProfile" /></td>
|
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ProfileId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="EditProfile" /></td>
|
||||||
<td><ActionDialog Header="Delete Profile" Message="@string.Format(Localizer["Confirm.Profile.Delete"], context.Name)" Action="Delete" Class="btn btn-danger" OnClick="@(async () => await DeleteProfile(context.ProfileId))" ResourceKey="DeleteProfile" /></td>
|
<td><ActionDialog Header="Delete Profile" Message="@string.Format(Localizer["Confirm.Profile.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteProfile(context.ProfileId))" ResourceKey="DeleteProfile" /></td>
|
||||||
<td>@context.Name</td>
|
<td>@context.Name</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
@ -29,7 +29,7 @@ else
|
|||||||
@code {
|
@code {
|
||||||
private List<Profile> _profiles;
|
private List<Profile> _profiles;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
|
20
Oqtane.Client/Modules/Admin/Profiles/ModuleInfo.cs
Normal file
20
Oqtane.Client/Modules/Admin/Profiles/ModuleInfo.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using Oqtane.Documentation;
|
||||||
|
using Oqtane.Models;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
|
namespace Oqtane.Modules.Admin.Profiles
|
||||||
|
{
|
||||||
|
[PrivateApi("Mark this as private, since it's not very useful in the public docs")]
|
||||||
|
public class ModuleInfo : IModule
|
||||||
|
{
|
||||||
|
public ModuleDefinition ModuleDefinition => new ModuleDefinition
|
||||||
|
{
|
||||||
|
Name = "Profiles",
|
||||||
|
Description = "Manage Profiles",
|
||||||
|
Categories = "Admin",
|
||||||
|
Version = Constants.Version,
|
||||||
|
PermissionNames = $"{PermissionNames.View},{PermissionNames.Edit}," +
|
||||||
|
$"{EntityNames.Profile}:{PermissionNames.Write}:{RoleNames.Admin}"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -22,7 +22,7 @@ else
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<Pager Items="@_pages.Where(item => item.IsDeleted)">
|
<Pager Items="@_pages.Where(item => item.IsDeleted)" CurrentPage="@_pagePage.ToString()" OnPageChange="OnPageChangePage">
|
||||||
<Header>
|
<Header>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
@ -50,7 +50,7 @@ else
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<Pager Items="@_modules.Where(item => item.IsDeleted)">
|
<Pager Items="@_modules.Where(item => item.IsDeleted)" CurrentPage="@_pageModule.ToString()" OnPageChange="OnPageChangeModule">
|
||||||
<Header>
|
<Header>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
<th style="width: 1px;"> </th>
|
<th style="width: 1px;"> </th>
|
||||||
@ -76,9 +76,10 @@ else
|
|||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<Page> _pages;
|
private List<Page> _pages;
|
||||||
private List<Module> _modules;
|
private List<Module> _modules;
|
||||||
|
private int _pagePage = 1;
|
||||||
|
private int _pageModule = 1;
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
@ -140,7 +141,7 @@ else
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
ModuleInstance.ShowProgressIndicator();
|
ModuleInstance.ShowProgressIndicator();
|
||||||
foreach (Page page in _pages.Where(item => item.IsDeleted))
|
foreach (Page page in _pages.Where(item => item.IsDeleted))
|
||||||
{
|
{
|
||||||
await PageService.DeletePageAsync(page.PageId);
|
await PageService.DeletePageAsync(page.PageId);
|
||||||
await logger.LogInformation("Page Permanently Deleted {Page}", page);
|
await logger.LogInformation("Page Permanently Deleted {Page}", page);
|
||||||
@ -185,7 +186,7 @@ else
|
|||||||
await PageModuleService.DeletePageModuleAsync(module.PageModuleId);
|
await PageModuleService.DeletePageModuleAsync(module.PageModuleId);
|
||||||
|
|
||||||
// check if there are any remaining module instances in the site
|
// check if there are any remaining module instances in the site
|
||||||
if (!_modules.Exists(item => item.ModuleId == module.ModuleId))
|
if (!_modules.Exists (item => item.ModuleId == module.ModuleId && item.PageModuleId != module.PageModuleId))
|
||||||
{
|
{
|
||||||
await ModuleService.DeleteModuleAsync(module.ModuleId);
|
await ModuleService.DeleteModuleAsync(module.ModuleId);
|
||||||
}
|
}
|
||||||
@ -206,12 +207,14 @@ else
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
ModuleInstance.ShowProgressIndicator();
|
ModuleInstance.ShowProgressIndicator();
|
||||||
foreach (Module module in _modules.Where(item => item.IsDeleted))
|
foreach (Module module in _modules.Where(item => item.IsDeleted).ToList())
|
||||||
{
|
{
|
||||||
await PageModuleService.DeletePageModuleAsync(module.PageModuleId);
|
await PageModuleService.DeletePageModuleAsync(module.PageModuleId);
|
||||||
|
|
||||||
|
// DeletePageModuleAsync does not update _modules so remove it.
|
||||||
|
_modules.Remove(module);
|
||||||
// check if there are any remaining module instances in the site
|
// check if there are any remaining module instances in the site
|
||||||
if (!_modules.Exists(item => item.ModuleId == module.ModuleId))
|
if (!_modules.Exists(item => item.ModuleId == module.ModuleId && item.PageModuleId != module.PageModuleId))
|
||||||
{
|
{
|
||||||
await ModuleService.DeleteModuleAsync(module.ModuleId);
|
await ModuleService.DeleteModuleAsync(module.ModuleId);
|
||||||
}
|
}
|
||||||
@ -229,4 +232,12 @@ else
|
|||||||
ModuleInstance.HideProgressIndicator();
|
ModuleInstance.HideProgressIndicator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private void OnPageChangePage(int page)
|
||||||
|
{
|
||||||
|
_pagePage = page;
|
||||||
|
}
|
||||||
|
private void OnPageChangeModule(int page)
|
||||||
|
{
|
||||||
|
_pageModule = page;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
@inject IUserService UserService
|
@inject IUserService UserService
|
||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
@inject ISettingService SettingService
|
||||||
|
|
||||||
@if (PageState.Site.AllowRegistration)
|
@if (PageState.Site.AllowRegistration)
|
||||||
{
|
{
|
||||||
@ -15,7 +16,7 @@
|
|||||||
<ModuleMessage Message="@Localizer["Info.Registration.Exists"]" Type="MessageType.Info" />
|
<ModuleMessage Message="@Localizer["Info.Registration.Exists"]" Type="MessageType.Info" />
|
||||||
</Authorized>
|
</Authorized>
|
||||||
<NotAuthorized>
|
<NotAuthorized>
|
||||||
<ModuleMessage Message="@Localizer["Info.Registration.InvalidEmail"]" Type="MessageType.Info" />
|
<ModuleMessage Message="@_passwordconstruction" Type="MessageType.Info" />
|
||||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -29,7 +30,7 @@
|
|||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" required />
|
<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>
|
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -38,7 +39,7 @@
|
|||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@_confirm" autocomplete="new-password" required />
|
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@_confirm" autocomplete="new-password" required />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglepassword</button>
|
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -68,21 +69,54 @@ else
|
|||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private string _username = string.Empty;
|
private string _username = string.Empty;
|
||||||
private ElementReference form;
|
private ElementReference form;
|
||||||
private bool validated = false;
|
private bool validated = false;
|
||||||
private string _password = string.Empty;
|
private string _password = string.Empty;
|
||||||
private string _passwordtype = "password";
|
private string _passwordtype = "password";
|
||||||
private string _togglepassword = string.Empty;
|
private string _togglepassword = string.Empty;
|
||||||
private string _confirm = string.Empty;
|
private string _confirm = string.Empty;
|
||||||
private string _email = string.Empty;
|
private string _email = string.Empty;
|
||||||
private string _displayname = string.Empty;
|
private string _displayname = string.Empty;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
//Password construction
|
||||||
|
private string _minimumlength;
|
||||||
|
private string _uniquecharacters;
|
||||||
|
private bool _requiredigit;
|
||||||
|
private bool _requireupper;
|
||||||
|
private bool _requirelower;
|
||||||
|
private bool _requirepunctuation;
|
||||||
|
private string _passwordconstruction;
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||||
|
|
||||||
|
_minimumlength = SettingService.GetSetting(settings, "IdentityOptions:Password:RequiredLength", "6");
|
||||||
|
_uniquecharacters = SettingService.GetSetting(settings, "IdentityOptions:Password:RequiredUniqueChars", "1");
|
||||||
|
_requiredigit = bool.Parse(SettingService.GetSetting(settings, "IdentityOptions:Password:RequireDigit", "true"));
|
||||||
|
_requireupper = bool.Parse(SettingService.GetSetting(settings, "IdentityOptions:Password:RequireUppercase", "true"));
|
||||||
|
_requirelower = bool.Parse(SettingService.GetSetting(settings, "IdentityOptions:Password:RequireLowercase", "true"));
|
||||||
|
_requirepunctuation = bool.Parse(SettingService.GetSetting(settings, "IdentityOptions:Password:RequireNonAlphanumeric", "true"));
|
||||||
|
|
||||||
|
// Replace the placeholders with the actual values of the variables
|
||||||
|
string digitRequirement = _requiredigit ? Localizer["Password.DigitRequirement"] + ", " : "";
|
||||||
|
string uppercaseRequirement = _requireupper ? Localizer["Password.UppercaseRequirement"] + ", " : "";
|
||||||
|
string lowercaseRequirement = _requirelower ? Localizer["Password.LowercaseRequirement"] + ", " : "";
|
||||||
|
string punctuationRequirement = _requirepunctuation ? Localizer["Password.PunctuationRequirement"] + ", " : "";
|
||||||
|
|
||||||
|
// Replace the placeholders with the actual values of the variables
|
||||||
|
string passwordValidationCriteriaTemplate = Localizer["Password.ValidationCriteria"];
|
||||||
|
_passwordconstruction = Localizer["Info.Registration.InvalidEmail"] + ". " + string.Format(passwordValidationCriteriaTemplate,
|
||||||
|
_minimumlength, _uniquecharacters, digitRequirement, uppercaseRequirement, lowercaseRequirement, punctuationRequirement);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Register()
|
private async Task Register()
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" required />
|
<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>
|
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -27,7 +27,7 @@
|
|||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@_confirm" autocomplete="new-password" required />
|
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@_confirm" autocomplete="new-password" required />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglepassword</button>
|
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
private string _description = string.Empty;
|
private string _description = string.Empty;
|
||||||
private string _isautoassigned = "False";
|
private string _isautoassigned = "False";
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||||
|
|
||||||
private async Task SaveRole()
|
private async Task SaveRole()
|
||||||
{
|
{
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
private string _modifiedby;
|
private string _modifiedby;
|
||||||
private DateTime _modifiedon;
|
private DateTime _modifiedon;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<ActionLink Action="Add" Text="Add Role" ResourceKey="AddRole" />
|
<ActionLink Action="Add" Text="Add Role" Security="SecurityAccessLevel.Edit" ResourceKey="AddRole" />
|
||||||
|
|
||||||
<Pager Items="@_roles">
|
<Pager Items="@_roles">
|
||||||
<Header>
|
<Header>
|
||||||
@ -20,9 +20,9 @@ else
|
|||||||
<th>@SharedLocalizer["Name"]</th>
|
<th>@SharedLocalizer["Name"]</th>
|
||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.RoleId.ToString())" Disabled="@(context.IsSystem)" ResourceKey="Edit" /></td>
|
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.RoleId.ToString())" Security="SecurityAccessLevel.Edit" Disabled="@(context.IsSystem)" ResourceKey="Edit" /></td>
|
||||||
<td><ActionDialog Header="Delete Role" Message="@string.Format(Localizer["Confirm.DeleteUser"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteRole(context))" Disabled="@(context.IsSystem)" ResourceKey="DeleteRole" /></td>
|
<td><ActionDialog Header="Delete Role" Message="@string.Format(Localizer["Confirm.DeleteUser"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteRole(context))" Disabled="@(context.IsSystem)" ResourceKey="DeleteRole" /></td>
|
||||||
<td><ActionLink Action="Users" Parameters="@($"id=" + context.RoleId.ToString())" ResourceKey="Users" /></td>
|
<td><ActionLink Action="Users" Parameters="@($"id=" + context.RoleId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="Users" /></td>
|
||||||
<td>@context.Name</td>
|
<td>@context.Name</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
@ -31,7 +31,7 @@ else
|
|||||||
@code {
|
@code {
|
||||||
private List<Role> _roles;
|
private List<Role> _roles;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
|
21
Oqtane.Client/Modules/Admin/Roles/ModuleInfo.cs
Normal file
21
Oqtane.Client/Modules/Admin/Roles/ModuleInfo.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using Oqtane.Documentation;
|
||||||
|
using Oqtane.Models;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
|
namespace Oqtane.Modules.Admin.Roles
|
||||||
|
{
|
||||||
|
[PrivateApi("Mark this as private, since it's not very useful in the public docs")]
|
||||||
|
public class ModuleInfo : IModule
|
||||||
|
{
|
||||||
|
public ModuleDefinition ModuleDefinition => new ModuleDefinition
|
||||||
|
{
|
||||||
|
Name = "Roles",
|
||||||
|
Description = "Manage Roles",
|
||||||
|
Categories = "Admin",
|
||||||
|
Version = Constants.Version,
|
||||||
|
PermissionNames = $"{PermissionNames.View},{PermissionNames.Edit}," +
|
||||||
|
$"{EntityNames.Role}:{PermissionNames.Write}:{RoleNames.Admin}," +
|
||||||
|
$"{EntityNames.UserRole}:{PermissionNames.Write}:{RoleNames.Admin}"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -23,13 +23,7 @@ else
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="user" HelpText="Select a user" ResourceKey="User">User: </Label>
|
<Label Class="col-sm-3" For="user" HelpText="Select a user" ResourceKey="User">User: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="user" class="form-select" @bind="@userid" required>
|
<AutoComplete OnSearch="GetUsers" Placeholder="@Localizer["User.Select"]" @ref="user" />
|
||||||
<option value="-1"><@Localizer["User.Select"]></option>
|
|
||||||
@foreach (UserRole userrole in users)
|
|
||||||
{
|
|
||||||
<option value="@(userrole.UserId)">@userrole.User.DisplayName</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -64,7 +58,7 @@ else
|
|||||||
<td>@context.EffectiveDate</td>
|
<td>@context.EffectiveDate</td>
|
||||||
<td>@context.ExpiryDate</td>
|
<td>@context.ExpiryDate</td>
|
||||||
<td>
|
<td>
|
||||||
<ActionDialog Header="Remove User" Message="@string.Format(Localizer["Confirm.User.DeleteRole"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteUserRole(context.UserRoleId))" Disabled="@(context.Role.IsAutoAssigned || PageState.User.Username == UserNames.Host)" ResourceKey="DeleteUserRole" />
|
<ActionDialog Header="Remove User" Message="@string.Format(Localizer["Confirm.User.DeleteRole"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteUserRole(context.UserRoleId))" Disabled="@(context.Role.IsAutoAssigned || context.User.Username == UserNames.Host || context.User.UserId == PageState.User.UserId)" ResourceKey="DeleteUserRole" />
|
||||||
</td>
|
</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
@ -75,81 +69,96 @@ else
|
|||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private ElementReference form;
|
private ElementReference form;
|
||||||
private bool validated = false;
|
private bool validated = false;
|
||||||
|
|
||||||
private int roleid;
|
private int roleid;
|
||||||
private string name = string.Empty;
|
private string name = string.Empty;
|
||||||
private List<UserRole> users;
|
private AutoComplete user;
|
||||||
private int userid = -1;
|
private DateTime? effectivedate = null;
|
||||||
private DateTime? effectivedate = null;
|
private DateTime? expirydate = null;
|
||||||
private DateTime? expirydate = null;
|
private List<UserRole> userroles;
|
||||||
private List<UserRole> userroles;
|
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
roleid = Int32.Parse(PageState.QueryString["id"]);
|
roleid = Int32.Parse(PageState.QueryString["id"]);
|
||||||
Role role = await RoleService.GetRoleAsync(roleid);
|
Role role = await RoleService.GetRoleAsync(roleid);
|
||||||
name = role.Name;
|
name = role.Name;
|
||||||
users = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Registered);
|
await GetUserRoles();
|
||||||
await GetUserRoles();
|
}
|
||||||
}
|
catch (Exception ex)
|
||||||
catch (Exception ex)
|
{
|
||||||
{
|
await logger.LogError(ex, "Error Loading Users {Error}", ex.Message);
|
||||||
await logger.LogError(ex, "Error Loading Users {Error}", ex.Message);
|
AddModuleMessage(Localizer["Error.User.Load"], MessageType.Error);
|
||||||
AddModuleMessage(Localizer["Error.User.Load"], MessageType.Error);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private async Task GetUserRoles()
|
private async Task<Dictionary<string, string>> GetUsers(string filter)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
userroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, name);
|
var users = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Registered);
|
||||||
}
|
return users.Where(item => item.User.DisplayName.Contains(filter, StringComparison.OrdinalIgnoreCase))
|
||||||
catch (Exception ex)
|
.ToDictionary(item => item.UserId.ToString(), item => item.User.DisplayName);
|
||||||
{
|
}
|
||||||
await logger.LogError(ex, "Error Loading User Roles {RoleId} {Error}", roleid, ex.Message);
|
catch (Exception ex)
|
||||||
AddModuleMessage(Localizer["Error.User.LoadRole"], MessageType.Error);
|
{
|
||||||
}
|
await logger.LogError(ex, "Error Loading Users {filter} {Error}", filter, ex.Message);
|
||||||
}
|
AddModuleMessage(Localizer["Error.User.Load"], MessageType.Error);
|
||||||
|
}
|
||||||
|
return new Dictionary<string, string>();
|
||||||
|
}
|
||||||
|
|
||||||
private async Task SaveUserRole()
|
private async Task GetUserRoles()
|
||||||
{
|
{
|
||||||
validated = true;
|
try
|
||||||
var interop = new Interop(JSRuntime);
|
{
|
||||||
if (await interop.FormValid(form))
|
userroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, name);
|
||||||
{
|
}
|
||||||
try
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
if (userid != -1)
|
await logger.LogError(ex, "Error Loading User Roles {RoleId} {Error}", roleid, ex.Message);
|
||||||
{
|
AddModuleMessage(Localizer["Error.User.LoadRole"], MessageType.Error);
|
||||||
var userrole = userroles.Where(item => item.UserId == userid && item.RoleId == roleid).FirstOrDefault();
|
}
|
||||||
if (userrole != null)
|
}
|
||||||
{
|
|
||||||
userrole.EffectiveDate = effectivedate;
|
|
||||||
userrole.ExpiryDate = expirydate;
|
|
||||||
await UserRoleService.UpdateUserRoleAsync(userrole);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
userrole = new UserRole();
|
|
||||||
userrole.UserId = userid;
|
|
||||||
userrole.RoleId = roleid;
|
|
||||||
userrole.EffectiveDate = effectivedate;
|
|
||||||
userrole.ExpiryDate = expirydate;
|
|
||||||
|
|
||||||
await UserRoleService.AddUserRoleAsync(userrole);
|
private async Task SaveUserRole()
|
||||||
}
|
{
|
||||||
|
validated = true;
|
||||||
|
var interop = new Interop(JSRuntime);
|
||||||
|
if (await interop.FormValid(form))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(user.Key) && int.TryParse(user.Key, out int userid))
|
||||||
|
{
|
||||||
|
var userrole = userroles.Where(item => item.UserId == userid && item.RoleId == roleid).FirstOrDefault();
|
||||||
|
if (userrole != null)
|
||||||
|
{
|
||||||
|
userrole.EffectiveDate = effectivedate;
|
||||||
|
userrole.ExpiryDate = expirydate;
|
||||||
|
await UserRoleService.UpdateUserRoleAsync(userrole);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
userrole = new UserRole();
|
||||||
|
userrole.UserId = userid;
|
||||||
|
userrole.RoleId = roleid;
|
||||||
|
userrole.EffectiveDate = effectivedate;
|
||||||
|
userrole.ExpiryDate = expirydate;
|
||||||
|
|
||||||
await logger.LogInformation("User Assigned To Role {UserRole}", userrole);
|
await UserRoleService.AddUserRoleAsync(userrole);
|
||||||
AddModuleMessage(Localizer["Success.User.AssignedRole"], MessageType.Success);
|
}
|
||||||
await GetUserRoles();
|
|
||||||
StateHasChanged();
|
await logger.LogInformation("User Assigned To Role {UserRole}", userrole);
|
||||||
|
AddModuleMessage(Localizer["Success.User.AssignedRole"], MessageType.Success);
|
||||||
|
await GetUserRoles();
|
||||||
|
user.Clear();
|
||||||
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -78,7 +78,7 @@
|
|||||||
<option value="-"><@Localizer["Not Specified"]></option>
|
<option value="-"><@Localizer["Not Specified"]></option>
|
||||||
@foreach (Page page in PageState.Pages)
|
@foreach (Page page in PageState.Pages)
|
||||||
{
|
{
|
||||||
if (UserSecurity.ContainsRole(page.Permissions, PermissionNames.View, RoleNames.Everyone))
|
if (UserSecurity.ContainsRole(page.PermissionList, PermissionNames.View, RoleNames.Everyone))
|
||||||
{
|
{
|
||||||
<option value="@(page.PageId)">@(new string('-', page.Level * 2))@(page.Name)</option>
|
<option value="@(page.PageId)">@(new string('-', page.Level * 2))@(page.Name)</option>
|
||||||
}
|
}
|
||||||
@ -95,6 +95,12 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="sitemap" HelpText="The site map url for this site which can be submitted to search engines for indexing" ResourceKey="SiteMap">Site Map: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="sitemap" class="form-control" @bind="@_sitemap" required disabled />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Section Name="SMTP" Heading="SMTP Settings" ResourceKey="SMTPSettings">
|
<Section Name="SMTP" Heading="SMTP Settings" ResourceKey="SMTPSettings">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@ -127,7 +133,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="username" HelpText="Enter the username for your SMTP account" ResourceKey="SmptUsername">Username: </Label>
|
<Label Class="col-sm-3" For="username" HelpText="Enter the username for your SMTP account" ResourceKey="SmtpUsername">Username: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="username" class="form-control" @bind="@_smtpusername" />
|
<input id="username" class="form-control" @bind="@_smtpusername" />
|
||||||
</div>
|
</div>
|
||||||
@ -137,17 +143,26 @@
|
|||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="password" type="@_smtppasswordtype" class="form-control" @bind="@_smtppassword" />
|
<input id="password" type="@_smtppasswordtype" class="form-control" @bind="@_smtppassword" />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@ToggleSMTPPassword">@_togglesmtppassword</button>
|
<button type="button" class="btn btn-secondary" @onclick="@ToggleSMTPPassword" tabindex="-1">@_togglesmtppassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="sender" HelpText="Enter the email which emails will be sent from. Please note that this email address may need to be authorized with the SMTP server." ResourceKey="SmptSender">Email Sender: </Label>
|
<Label Class="col-sm-3" For="sender" HelpText="Enter the email which emails will be sent from. Please note that this email address may need to be authorized with the SMTP server." ResourceKey="SmtpSender">Email Sender: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="sender" class="form-control" @bind="@_smtpsender" />
|
<input id="sender" class="form-control" @bind="@_smtpsender" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="relay" HelpText="Only specify this option if you have properly configured an SMTP Relay Service to route your outgoing mail. This option will send notifications from the user's email rather than from the Email Sender specified above." ResourceKey="SmtpRelay">Relay Configured? </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="relay" class="form-select" @bind="@_smtprelay" 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="retention" HelpText="Number of days of notifications to retain" ResourceKey="Retention">Retention (Days): </Label>
|
<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">
|
<div class="col-sm-9">
|
||||||
<input id="retention" class="form-control" @bind="@_retention" />
|
<input id="retention" class="form-control" @bind="@_retention" />
|
||||||
@ -258,16 +273,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
<Section Name="TenantInformation" Heading="Tenant Information" ResourceKey="TenantInformation">
|
<Section Name="TenantInformation" Heading="Database" ResourceKey="TenantInformation">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="tenant" HelpText="The tenant for the site" ResourceKey="Tenant">Tenant: </Label>
|
<Label Class="col-sm-3" For="tenant" HelpText="The name of the database used for the site" ResourceKey="Tenant">Database: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="tenant" class="form-control" @bind="@_tenant" readonly />
|
<input id="tenant" class="form-control" @bind="@_tenant" readonly />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="database" HelpText="The database for the tenant" ResourceKey="Database">Database: </Label>
|
<Label Class="col-sm-3" For="database" HelpText="The type of database" ResourceKey="Database">Type: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="database" class="form-control" @bind="@_database" readonly />
|
<input id="database" class="form-control" @bind="@_database" readonly />
|
||||||
</div>
|
</div>
|
||||||
@ -275,7 +290,7 @@
|
|||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="connectionstring" HelpText="The connection information for the database" ResourceKey="ConnectionString">Connection: </Label>
|
<Label Class="col-sm-3" For="connectionstring" HelpText="The connection information for the database" ResourceKey="ConnectionString">Connection: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<textarea id="connectionstring" class="form-control" @bind="@_connectionstring" rows="2" readonly></textarea>
|
<input id="connectionstring" class="form-control" @bind="@_connectionstring" readonly />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -312,6 +327,7 @@
|
|||||||
private string _containertype = "-";
|
private string _containertype = "-";
|
||||||
private string _admincontainertype = "-";
|
private string _admincontainertype = "-";
|
||||||
private string _homepageid = "-";
|
private string _homepageid = "-";
|
||||||
|
private string _sitemap = "";
|
||||||
private string _smtphost = string.Empty;
|
private string _smtphost = string.Empty;
|
||||||
private string _smtpport = string.Empty;
|
private string _smtpport = string.Empty;
|
||||||
private string _smtpssl = "False";
|
private string _smtpssl = "False";
|
||||||
@ -320,6 +336,7 @@
|
|||||||
private string _smtppasswordtype = "password";
|
private string _smtppasswordtype = "password";
|
||||||
private string _togglesmtppassword = string.Empty;
|
private string _togglesmtppassword = string.Empty;
|
||||||
private string _smtpsender = string.Empty;
|
private string _smtpsender = string.Empty;
|
||||||
|
private string _smtprelay = "False";
|
||||||
private string _retention = string.Empty;
|
private string _retention = string.Empty;
|
||||||
private string _pwaisenabled;
|
private string _pwaisenabled;
|
||||||
private int _pwaappiconfileid = -1;
|
private int _pwaappiconfileid = -1;
|
||||||
@ -351,6 +368,7 @@
|
|||||||
_runtime = site.Runtime;
|
_runtime = site.Runtime;
|
||||||
_prerender = site.RenderMode.Replace(_runtime, "");
|
_prerender = site.RenderMode.Replace(_runtime, "");
|
||||||
_isdeleted = site.IsDeleted.ToString();
|
_isdeleted = site.IsDeleted.ToString();
|
||||||
|
_sitemap = PageState.Alias.Protocol + PageState.Alias.Name + "/pages/sitemap.xml";
|
||||||
|
|
||||||
await GetAliases();
|
await GetAliases();
|
||||||
|
|
||||||
@ -393,6 +411,7 @@
|
|||||||
_smtppassword = SettingService.GetSetting(settings, "SMTPPassword", string.Empty);
|
_smtppassword = SettingService.GetSetting(settings, "SMTPPassword", string.Empty);
|
||||||
_togglesmtppassword = SharedLocalizer["ShowPassword"];
|
_togglesmtppassword = SharedLocalizer["ShowPassword"];
|
||||||
_smtpsender = SettingService.GetSetting(settings, "SMTPSender", string.Empty);
|
_smtpsender = SettingService.GetSetting(settings, "SMTPSender", string.Empty);
|
||||||
|
_smtprelay = SettingService.GetSetting(settings, "SMTPRelay", "False");
|
||||||
_retention = SettingService.GetSetting(settings, "NotificationRetention", "30");
|
_retention = SettingService.GetSetting(settings, "NotificationRetention", "30");
|
||||||
|
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
@ -444,7 +463,7 @@
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", _themetype, ex.Message);
|
await logger.LogError(ex, "Error Loading Containers For Theme {ThemeType} {Error}", _themetype, ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.Theme.LoadPane"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Theme.LoadPane"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -532,6 +551,7 @@
|
|||||||
settings = SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
settings = SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
settings = SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
settings = SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "SMTPRelay", _smtprelay, true);
|
||||||
settings = SettingService.SetSetting(settings, "NotificationRetention", _retention, true);
|
settings = SettingService.SetSetting(settings, "NotificationRetention", _retention, true);
|
||||||
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
|
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
|
||||||
|
|
||||||
@ -602,12 +622,12 @@
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||||
SettingService.SetSetting(settings, "SMTPHost", _smtphost, true);
|
settings = SettingService.SetSetting(settings, "SMTPHost", _smtphost, true);
|
||||||
SettingService.SetSetting(settings, "SMTPPort", _smtpport, true);
|
settings = SettingService.SetSetting(settings, "SMTPPort", _smtpport, true);
|
||||||
SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, true);
|
settings = SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, true);
|
||||||
SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
settings = SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
||||||
SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
settings = SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
||||||
SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
settings = SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
||||||
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
||||||
await logger.LogInformation("Site SMTP Settings Saved");
|
await logger.LogInformation("Site SMTP Settings Saved");
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ else
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="tenant" HelpText="Select the tenant for the site" ResourceKey="Tenant">Tenant: </Label>
|
<Label Class="col-sm-3" For="tenant" HelpText="Select the database for the site" ResourceKey="Tenant">Database: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="tenant" class="form-select" @onchange="(e => TenantChanged(e))" required>
|
<select id="tenant" class="form-select" @onchange="(e => TenantChanged(e))" required>
|
||||||
<option value="-"><@Localizer["Tenant.Select"]></option>
|
<option value="-"><@Localizer["Tenant.Select"]></option>
|
||||||
@ -121,13 +121,13 @@ else
|
|||||||
<hr class="app-rule" />
|
<hr class="app-rule" />
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="name" HelpText="Enter the name for the tenant" ResourceKey="TenantName">Tenant Name: </Label>
|
<Label Class="col-sm-3" For="name" HelpText="Enter the name for the database" ResourceKey="TenantName">Name: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="name" class="form-control" @bind="@_tenantName" maxlength="100" required />
|
<input id="name" class="form-control" @bind="@_tenantName" maxlength="100" required />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="databaseType" HelpText="Select the database type for the tenant" ResourceKey="DatabaseType">Database Type: </Label>
|
<Label Class="col-sm-3" For="databaseType" HelpText="Select the database type" ResourceKey="DatabaseType">Type: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@if (_databases != null)
|
@if (_databases != null)
|
||||||
{
|
{
|
||||||
@ -160,7 +160,7 @@ else
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="connectionstring" HelpText="Enter a complete connection string including all parameters and delimiters" ResourceKey="ConnectionString">String:</Label>
|
<Label Class="col-sm-3" For="connectionstring" HelpText="Enter a complete connection string including all parameters and delimiters" ResourceKey="ConnectionString">Settings:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<textarea id="connectionstring" class="form-control" @bind="@_connectionString" rows="3"></textarea>
|
<textarea id="connectionstring" class="form-control" @bind="@_connectionString" rows="3"></textarea>
|
||||||
</div>
|
</div>
|
||||||
@ -315,7 +315,7 @@ else
|
|||||||
_urls = Regex.Replace(_urls, @"\r\n?|\n", ",");
|
_urls = Regex.Replace(_urls, @"\r\n?|\n", ",");
|
||||||
var duplicates = new List<string>();
|
var duplicates = new List<string>();
|
||||||
var aliases = await AliasService.GetAliasesAsync();
|
var aliases = await AliasService.GetAliasesAsync();
|
||||||
foreach (string name in _urls.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
foreach (string name in _urls.Split(',', StringSplitOptions.RemoveEmptyEntries))
|
||||||
{
|
{
|
||||||
if (aliases.Exists(item => item.Name == name))
|
if (aliases.Exists(item => item.Name == name))
|
||||||
{
|
{
|
||||||
@ -329,7 +329,7 @@ else
|
|||||||
|
|
||||||
if (_tenantid == "+")
|
if (_tenantid == "+")
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(_tenantName) && _tenants.FirstOrDefault(item => item.Name == _tenantName) == null)
|
if (!string.IsNullOrEmpty(_tenantName) && !_tenants.Exists(item => item.Name == _tenantName))
|
||||||
{
|
{
|
||||||
// validate host credentials
|
// validate host credentials
|
||||||
var user = new User();
|
var user = new User();
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
@namespace Oqtane.Modules.Admin.Sql
|
@namespace Oqtane.Modules.Admin.Sql
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
|
@inject ISystemService SystemService
|
||||||
@inject ITenantService TenantService
|
@inject ITenantService TenantService
|
||||||
@inject IDatabaseService DatabaseService
|
@inject IDatabaseService DatabaseService
|
||||||
@inject ISqlService SqlService
|
@inject ISqlService SqlService
|
||||||
@ -14,125 +15,307 @@
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="connection" HelpText="Select a database connection (from appsettings.json)" ResourceKey="Connection">Connection: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="tenant" class="form-select" value="@_connection" @onchange="(e => ConnectionChanged(e))">
|
||||||
|
<option value="-"><@Localizer["Connection.Select"]></option>
|
||||||
|
<option value="+"><@Localizer["Connection.Add"]></option>
|
||||||
|
@foreach (var connection in _connections)
|
||||||
|
{
|
||||||
|
<option value="@connection.Key">@connection.Key</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if (_connection == "+")
|
||||||
|
{
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="name" HelpText="Enter the name of the connection" ResourceKey="Name">Name: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="name" class="form-control" @bind="@_name" maxlength="100" required />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="databasetype" HelpText="Select the database type" ResourceKey="DatabaseType">Type: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
@if (_databases != null)
|
||||||
|
{
|
||||||
|
<div class="input-group">
|
||||||
|
<select id="databasetype" class="form-select" value="@_databasetype" @onchange="(e => DatabaseTypeChanged(e))" required>
|
||||||
|
@foreach (var database in _databases)
|
||||||
|
{
|
||||||
|
<option value="@database.Name">@Localizer[@database.Name]</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
@if (!_showConnectionString)
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="ShowConnectionString">@Localizer["EnterConnectionString"]</button>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="ShowConnectionString">@Localizer["EnterConnectionParameters"]</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if (!_showConnectionString)
|
||||||
|
{
|
||||||
|
if (_databaseConfigType != null)
|
||||||
|
{
|
||||||
|
@DatabaseConfigComponent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="connectionstring" HelpText="Enter a complete connection string including all parameters and delimiters" ResourceKey="ConnectionString">Settings:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<textarea id="connectionstring" class="form-control" @bind="@_connectionstring" rows="3"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<br />
|
||||||
|
<button type="button" class="btn btn-success" @onclick="Add">@Localizer["Add"]</button>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@if (_connection != "-")
|
||||||
|
{
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="databasetype" HelpText="The database type" ResourceKey="DatabaseType">Type: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
@if (_databases != null)
|
||||||
|
{
|
||||||
|
<select id="databasetype" class="form-select" @bind="@_databasetype" required>
|
||||||
|
<option value="-"><@Localizer["Type.Select"]></option>
|
||||||
|
@foreach (var database in _databases)
|
||||||
|
{
|
||||||
|
<option value="@database.Name">@Localizer[@database.Name]</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if (!string.IsNullOrEmpty(_tenant))
|
||||||
|
{
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="tenant" HelpText="The database using this connection" ResourceKey="Tenant">Database: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="tenant" class="form-control" @bind="@_tenant" readonly />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="connectionstring" HelpText="The connection string" ResourceKey="ConnectionString">Settings: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<div class="input-group">
|
||||||
|
<input id="connectionstring" type="@_connectionstringtype" class="form-control" @bind="@_connectionstring" readonly />
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="@ToggleConnectionString">@_connectionstringtoggle</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="sqlQuery" HelpText="Enter a valid SQL query for the database" ResourceKey="SqlQuery">SQL Query: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<textarea id="sqlQuery" class="form-control" @bind="@_sql" rows="3"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<button type="button" class="btn btn-success" @onclick="Execute">@Localizer["Execute"]</button>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
@if (_results != null)
|
||||||
|
{
|
||||||
|
@if (_results.Count > 0)
|
||||||
|
{
|
||||||
|
<Pager Class="table table-bordered" Items="@_results">
|
||||||
|
<Header>
|
||||||
|
@foreach (KeyValuePair<string, string> kvp in _results.First())
|
||||||
|
{
|
||||||
|
<th>@kvp.Key</th>
|
||||||
|
}
|
||||||
|
</Header>
|
||||||
|
<Row>
|
||||||
|
@foreach (KeyValuePair<string, string> kvp in context)
|
||||||
|
{
|
||||||
|
<td>@kvp.Value</td>
|
||||||
|
}
|
||||||
|
</Row>
|
||||||
|
</Pager>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@Localizer["Return.NoResult"]
|
||||||
|
}
|
||||||
|
<br />
|
||||||
|
|
||||||
<div class="row mb-1 align-items-center">
|
<br />
|
||||||
<Label Class="col-sm-3" For="tenant" HelpText="Select the tenant for the SQL server" ResourceKey="Tenant">Tenant: </Label>
|
}
|
||||||
<div class="col-sm-9">
|
}
|
||||||
<select id="tenant" class="form-select" value="@_tenantid" @onchange="(e => TenantChanged(e))">
|
}
|
||||||
<option value="-1"><@Localizer["Tenant.Select"]></option>
|
</div>
|
||||||
@foreach (Tenant tenant in _tenants)
|
|
||||||
{
|
|
||||||
<option value="@tenant.TenantId">@tenant.Name</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@if (_tenantid != "-1")
|
|
||||||
{
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="database" HelpText="The database for the tenant" ResourceKey="Database">Database: </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input id="database" class="form-control" @bind="@_database" readonly />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="connectionstring" HelpText="The connection information for the database" ResourceKey="ConnectionString">Connection: </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<textarea id="connectionstring" class="form-control" @bind="@_connectionstring" rows="2" readonly></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="sqlQeury" HelpText="Enter the query for the SQL server" ResourceKey="SqlQuery">SQL Query: </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<textarea id="sqlQeury" class="form-control" @bind="@_sql" rows="3"></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<br />
|
|
||||||
<button type="button" class="btn btn-success" @onclick="Execute">@Localizer["Execute"]</button>
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
@if (_results != null)
|
|
||||||
{
|
|
||||||
@if (_results.Count > 0)
|
|
||||||
{
|
|
||||||
<Pager Class="table table-bordered" Items="@_results">
|
|
||||||
<Header>
|
|
||||||
@foreach (KeyValuePair<string, string> kvp in _results.First())
|
|
||||||
{
|
|
||||||
<th>@kvp.Key</th>
|
|
||||||
}
|
|
||||||
</Header>
|
|
||||||
<Row>
|
|
||||||
@foreach (KeyValuePair<string, string> kvp in context)
|
|
||||||
{
|
|
||||||
<td>@kvp.Value</td>
|
|
||||||
}
|
|
||||||
</Row>
|
|
||||||
</Pager>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
@Localizer["Return.NoResult"]
|
|
||||||
}
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<Tenant> _tenants;
|
private string _connection = "-";
|
||||||
private string _tenantid = "-1";
|
private Dictionary<string, object> _connections;
|
||||||
private string _database = string.Empty;
|
private List<Tenant> _tenants;
|
||||||
private string _connectionstring = string.Empty;
|
private List<Database> _databases;
|
||||||
private string _sql = string.Empty;
|
|
||||||
private List<Dictionary<string, string>> _results;
|
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
private string _name = string.Empty;
|
||||||
|
private string _databasetype = string.Empty;
|
||||||
|
private Type _databaseConfigType;
|
||||||
|
private object _databaseConfig;
|
||||||
|
private RenderFragment DatabaseConfigComponent { get; set; }
|
||||||
|
private bool _showConnectionString = false;
|
||||||
|
private string _tenant = string.Empty;
|
||||||
|
private string _connectionstring = string.Empty;
|
||||||
|
private string _connectionstringtype = "password";
|
||||||
|
private string _connectionstringtoggle = string.Empty;
|
||||||
|
private string _sql = string.Empty;
|
||||||
|
private List<Dictionary<string, string>> _results;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_tenants = await TenantService.GetTenantsAsync();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Loading Tenants {Error}", ex.Message);
|
|
||||||
AddModuleMessage(ex.Message, MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void TenantChanged(ChangeEventArgs e)
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_tenantid = (string)e.Value;
|
_connections = await SystemService.GetSystemInfoAsync("connectionstrings");
|
||||||
var tenants = await TenantService.GetTenantsAsync();
|
_tenants = await TenantService.GetTenantsAsync();
|
||||||
var _databases = await DatabaseService.GetDatabasesAsync();
|
_databases = await DatabaseService.GetDatabasesAsync();
|
||||||
var tenant = tenants.Find(item => item.TenantId == int.Parse(_tenantid));
|
_connectionstringtoggle = SharedLocalizer["ShowPassword"];
|
||||||
if (tenant != null)
|
}
|
||||||
{
|
catch (Exception ex)
|
||||||
_database = _databases.Find(item => item.DBType == tenant.DBType)?.Name;
|
{
|
||||||
_connectionstring = tenant.DBConnectionString;
|
await logger.LogError(ex, "Error Loading Tenants {Error}", ex.Message);
|
||||||
}
|
AddModuleMessage(ex.Message, MessageType.Error);
|
||||||
StateHasChanged();
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Loading Tenant {TenantId} {Error}", _tenantid, ex.Message);
|
|
||||||
AddModuleMessage(ex.Message, MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task Execute()
|
private async void ConnectionChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_tenantid != "-1" && !string.IsNullOrEmpty(_sql))
|
_connection = (string)e.Value;
|
||||||
{
|
if (_connection != "-" && _connection != "+")
|
||||||
var sqlquery = new SqlQuery { TenantId = int.Parse(_tenantid), Query = _sql };
|
{
|
||||||
|
_connectionstring = _connections[_connection].ToString();
|
||||||
|
_tenant = "";
|
||||||
|
_databasetype = "-";
|
||||||
|
var tenant = _tenants.FirstOrDefault(item => item.DBConnectionString == _connection);
|
||||||
|
if (tenant != null)
|
||||||
|
{
|
||||||
|
_tenant = tenant.Name;
|
||||||
|
_databasetype = _databases.FirstOrDefault(item => item.DBType == tenant.DBType).Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_databases.Exists(item => item.IsDefault))
|
||||||
|
{
|
||||||
|
_databasetype = _databases.Find(item => item.IsDefault).Name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_databasetype = "LocalDB";
|
||||||
|
}
|
||||||
|
_showConnectionString = false;
|
||||||
|
LoadDatabaseConfigComponent();
|
||||||
|
}
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Loading Connection {Connection} {Error}", _connection, ex.Message);
|
||||||
|
AddModuleMessage(ex.Message, MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DatabaseTypeChanged(ChangeEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_databasetype = (string)eventArgs.Value;
|
||||||
|
_showConnectionString = false;
|
||||||
|
LoadDatabaseConfigComponent();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Error.Database.LoadConfig"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadDatabaseConfigComponent()
|
||||||
|
{
|
||||||
|
var database = _databases.SingleOrDefault(d => d.Name == _databasetype);
|
||||||
|
if (database != null)
|
||||||
|
{
|
||||||
|
_databaseConfigType = Type.GetType(database.ControlType);
|
||||||
|
DatabaseConfigComponent = builder =>
|
||||||
|
{
|
||||||
|
builder.OpenComponent(0, _databaseConfigType);
|
||||||
|
builder.AddComponentReferenceCapture(1, inst => { _databaseConfig = Convert.ChangeType(inst, _databaseConfigType); });
|
||||||
|
builder.CloseComponent();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowConnectionString()
|
||||||
|
{
|
||||||
|
if (_databaseConfig is IDatabaseConfigControl databaseConfigControl)
|
||||||
|
{
|
||||||
|
_connectionstring = databaseConfigControl.GetConnectionString();
|
||||||
|
}
|
||||||
|
_showConnectionString = !_showConnectionString;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Add()
|
||||||
|
{
|
||||||
|
var connectionstring = _connectionstring;
|
||||||
|
if (!_showConnectionString && _databaseConfig is IDatabaseConfigControl databaseConfigControl)
|
||||||
|
{
|
||||||
|
connectionstring = databaseConfigControl.GetConnectionString();
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(_name) && !string.IsNullOrEmpty(connectionstring))
|
||||||
|
{
|
||||||
|
var settings = new Dictionary<string, object>();
|
||||||
|
settings.Add($"{SettingKeys.ConnectionStringsSection}:{_name}", connectionstring);
|
||||||
|
await SystemService.UpdateSystemInfoAsync(settings);
|
||||||
|
_connections = await SystemService.GetSystemInfoAsync("connectionstrings");
|
||||||
|
_connection = "-";
|
||||||
|
AddModuleMessage(Localizer["Message.Connection.Added"], MessageType.Success);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.Required.Connection"], MessageType.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ToggleConnectionString()
|
||||||
|
{
|
||||||
|
if (_connectionstringtype == "password")
|
||||||
|
{
|
||||||
|
_connectionstringtype = "text";
|
||||||
|
_connectionstringtoggle = SharedLocalizer["HidePassword"];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_connectionstringtype = "password";
|
||||||
|
_connectionstringtoggle = SharedLocalizer["ShowPassword"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Execute()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_databasetype != "-" && !string.IsNullOrEmpty(_sql))
|
||||||
|
{
|
||||||
|
var dbtype = _databases.FirstOrDefault(item => item.Name == _databasetype).DBType;
|
||||||
|
var sqlquery = new SqlQuery { DBConnectionString = _connection, DBType = dbtype, Query = _sql };
|
||||||
sqlquery = await SqlService.ExecuteQueryAsync(sqlquery);
|
sqlquery = await SqlService.ExecuteQueryAsync(sqlquery);
|
||||||
_results = sqlquery.Results;
|
_results = sqlquery.Results;
|
||||||
AddModuleMessage(Localizer["Success.QueryExecuted"], MessageType.Success);
|
AddModuleMessage(Localizer["Success.QueryExecuted"], MessageType.Success);
|
||||||
|
@ -147,6 +147,18 @@
|
|||||||
<a class="btn btn-primary" href="swagger/index.html" target="_new">@Localizer["Access.ApiFramework"]</a>
|
<a class="btn btn-primary" href="swagger/index.html" target="_new">@Localizer["Access.ApiFramework"]</a>
|
||||||
<ActionDialog Header="Restart Application" Message="Are You Sure You Wish To Restart The Application?" Action="Restart Application" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await RestartApplication())" ResourceKey="RestartApplication" />
|
<ActionDialog Header="Restart Application" Message="Are You Sure You Wish To Restart The Application?" Action="Restart Application" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await RestartApplication())" ResourceKey="RestartApplication" />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
<TabPanel Name="Log" Heading="Log" ResourceKey="Log">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="log" HelpText="System log information for current day" ResourceKey="Log">Log: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<textarea id="log" class="form-control" rows="10" @bind="@_log" readonly />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br /><br />
|
||||||
|
<button type="button" class="btn btn-danger" @onclick="ClearLog">@Localizer["Clear"]</button>
|
||||||
|
</TabPanel>
|
||||||
</TabStrip>
|
</TabStrip>
|
||||||
<br /><br />
|
<br /><br />
|
||||||
|
|
||||||
@ -172,11 +184,13 @@
|
|||||||
private string _swagger = string.Empty;
|
private string _swagger = string.Empty;
|
||||||
private string _packageservice = string.Empty;
|
private string _packageservice = string.Empty;
|
||||||
|
|
||||||
|
private string _log = string.Empty;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
_version = Constants.Version;
|
_version = Constants.Version;
|
||||||
|
|
||||||
Dictionary<string, object> systeminfo = await SystemService.GetSystemInfoAsync("environment");
|
var systeminfo = await SystemService.GetSystemInfoAsync("environment");
|
||||||
if (systeminfo != null)
|
if (systeminfo != null)
|
||||||
{
|
{
|
||||||
_clrversion = systeminfo["CLRVersion"].ToString();
|
_clrversion = systeminfo["CLRVersion"].ToString();
|
||||||
@ -191,37 +205,60 @@
|
|||||||
_workingset = (Convert.ToInt64(systeminfo["WorkingSet"].ToString()) / 1000000).ToString() + " MB";
|
_workingset = (Convert.ToInt64(systeminfo["WorkingSet"].ToString()) / 1000000).ToString() + " MB";
|
||||||
}
|
}
|
||||||
|
|
||||||
systeminfo = await SystemService.GetSystemInfoAsync();
|
systeminfo = await SystemService.GetSystemInfoAsync("configuration");
|
||||||
if (systeminfo != null)
|
if (systeminfo != null)
|
||||||
{
|
{
|
||||||
_installationid = systeminfo["InstallationId"].ToString();
|
_installationid = systeminfo["InstallationId"].ToString();
|
||||||
_detailederrors = systeminfo["DetailedErrors"].ToString();
|
_detailederrors = systeminfo["DetailedErrors"].ToString();
|
||||||
_logginglevel = systeminfo["Logging:LogLevel:Default"].ToString();
|
_logginglevel = systeminfo["Logging:LogLevel:Default"].ToString();
|
||||||
_notificationlevel = systeminfo["Logging:LogLevel:Notify"].ToString();
|
_notificationlevel = systeminfo["Logging:LogLevel:Notify"].ToString();
|
||||||
_swagger = systeminfo["UseSwagger"].ToString();
|
_swagger = systeminfo["UseSwagger"].ToString();
|
||||||
_packageservice = systeminfo["PackageService"].ToString();
|
_packageservice = systeminfo["PackageService"].ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
systeminfo = await SystemService.GetSystemInfoAsync("log");
|
||||||
|
if (systeminfo != null)
|
||||||
|
{
|
||||||
|
_log = systeminfo["Log"].ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SaveConfig()
|
private async Task SaveConfig()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var settings = new Dictionary<string, object>();
|
var settings = new Dictionary<string, object>();
|
||||||
settings.Add("DetailedErrors", _detailederrors);
|
settings.Add("DetailedErrors", _detailederrors);
|
||||||
settings.Add("Logging:LogLevel:Default", _logginglevel);
|
settings.Add("Logging:LogLevel:Default", _logginglevel);
|
||||||
settings.Add("Logging:LogLevel:Notify", _notificationlevel);
|
settings.Add("Logging:LogLevel:Notify", _notificationlevel);
|
||||||
settings.Add("UseSwagger", _swagger);
|
settings.Add("UseSwagger", _swagger);
|
||||||
settings.Add("PackageService", _packageservice);
|
settings.Add("PackageService", _packageservice);
|
||||||
await SystemService.UpdateSystemInfoAsync(settings);
|
await SystemService.UpdateSystemInfoAsync(settings);
|
||||||
AddModuleMessage(Localizer["Success.UpdateConfig.Restart"], MessageType.Success);
|
AddModuleMessage(Localizer["Success.UpdateConfig.Restart"], MessageType.Success);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Saving Configuration");
|
await logger.LogError(ex, "Error Saving Configuration");
|
||||||
AddModuleMessage(Localizer["Error.UpdateConfig"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.UpdateConfig"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task ClearLog()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var settings = new Dictionary<string, object>();
|
||||||
|
settings.Add("clearlog", "true");
|
||||||
|
await SystemService.UpdateSystemInfoAsync(settings);
|
||||||
|
_log = string.Empty;
|
||||||
|
AddModuleMessage(Localizer["Success.ClearLog"], MessageType.Success);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Clearing Log");
|
||||||
|
AddModuleMessage(Localizer["Error.ClearLog"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task RestartApplication()
|
private async Task RestartApplication()
|
||||||
{
|
{
|
||||||
|
@ -65,13 +65,15 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
<br />
|
||||||
|
<ModuleMessage Type="MessageType.Info" Message="@SharedLocalizer["Oqtane.Marketplace"]" />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel Name="Upload" ResourceKey="Upload">
|
<TabPanel Name="Upload" ResourceKey="Upload">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" HelpText="Upload one or more theme packages. Once they are uploaded click Install to complete the installation." ResourceKey="Theme">Theme: </Label>
|
<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">
|
<div class="col-sm-9">
|
||||||
<FileManager Folder="@Constants.PackagesFolder" UploadMultiple="true" />
|
<FileManager Folder="@Constants.PackagesFolder" UploadMultiple="true" OnUpload="OnUpload" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -111,13 +113,8 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
<button type="button" class="btn btn-success" @onclick="InstallThemes">@SharedLocalizer["Install"]</button>
|
|
||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<ModuleMessage Type="MessageType.Info" Message="@SharedLocalizer["Oqtane.Marketplace"]" />
|
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<Package> _packages;
|
private List<Package> _packages;
|
||||||
private string _price = "free";
|
private string _price = "free";
|
||||||
@ -236,7 +233,7 @@
|
|||||||
{
|
{
|
||||||
await PackageService.DownloadPackageAsync(_packageid, _version, Constants.PackagesFolder);
|
await PackageService.DownloadPackageAsync(_packageid, _version, Constants.PackagesFolder);
|
||||||
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _packageid, _version);
|
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _packageid, _version);
|
||||||
AddModuleMessage(Localizer["Success.Theme.Download"], MessageType.Success);
|
AddModuleMessage(string.Format(Localizer["Success.Theme.Download"], NavigateUrl("admin/system")), MessageType.Success);
|
||||||
_productname = "";
|
_productname = "";
|
||||||
_license = "";
|
_license = "";
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
@ -248,16 +245,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task InstallThemes()
|
private void OnUpload()
|
||||||
{
|
{
|
||||||
try
|
AddModuleMessage(string.Format(Localizer["Success.Theme.Download"], NavigateUrl("admin/system")), MessageType.Success);
|
||||||
{
|
|
||||||
await ThemeService.InstallThemesAsync();
|
|
||||||
AddModuleMessage(string.Format(Localizer["Success.Theme.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Installing Theme");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@
|
|||||||
private bool IsValid(string name)
|
private bool IsValid(string name)
|
||||||
{
|
{
|
||||||
// must contain letters, underscores and digits and first character must be letter or underscore
|
// must contain letters, underscores and digits and first character must be letter or underscore
|
||||||
return !string.IsNullOrEmpty(name) && name.ToLower() != "theme" && Regex.IsMatch(name, "^[A-Za-z_][A-Za-z0-9_]*$");
|
return !string.IsNullOrEmpty(name) && name.ToLower() != "theme" && !name.ToLower().Contains("oqtane") && Regex.IsMatch(name, "^[A-Za-z_][A-Za-z0-9_]*$");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TemplateChanged(ChangeEventArgs e)
|
private void TemplateChanged(ChangeEventArgs e)
|
||||||
|
@ -116,7 +116,6 @@ else
|
|||||||
{
|
{
|
||||||
await PackageService.DownloadPackageAsync(packagename, version, Constants.PackagesFolder);
|
await PackageService.DownloadPackageAsync(packagename, version, Constants.PackagesFolder);
|
||||||
await logger.LogInformation("Theme Downloaded {ThemeName} {Version}", packagename, version);
|
await logger.LogInformation("Theme Downloaded {ThemeName} {Version}", packagename, version);
|
||||||
await ThemeService.InstallThemesAsync();
|
|
||||||
AddModuleMessage(string.Format(Localizer["Success.Theme.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
AddModuleMessage(string.Format(Localizer["Success.Theme.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -34,7 +34,7 @@ else
|
|||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" />
|
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglepassword</button>
|
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -43,7 +43,7 @@ else
|
|||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@confirm" autocomplete="new-password" />
|
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@confirm" autocomplete="new-password" />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglepassword</button>
|
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -211,8 +211,11 @@ else
|
|||||||
</Detail>
|
</Detail>
|
||||||
</Pager>
|
</Pager>
|
||||||
}
|
}
|
||||||
<br />
|
@if (notifications.Any())
|
||||||
<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 />
|
||||||
|
<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 />
|
<br /><hr />
|
||||||
<select class="form-select" @onchange="(e => FilterChanged(e))">
|
<select class="form-select" @onchange="(e => FilterChanged(e))">
|
||||||
<option value="to">@Localizer["Inbox"]</option>
|
<option value="to">@Localizer["Inbox"]</option>
|
||||||
@ -224,126 +227,140 @@ else
|
|||||||
<br /><br />
|
<br /><br />
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private string username = string.Empty;
|
private string username = string.Empty;
|
||||||
private string _password = string.Empty;
|
private string _password = string.Empty;
|
||||||
private string _passwordtype = "password";
|
private string _passwordtype = "password";
|
||||||
private string _togglepassword = string.Empty;
|
private string _togglepassword = string.Empty;
|
||||||
private string confirm = string.Empty;
|
private string confirm = string.Empty;
|
||||||
private bool allowtwofactor = false;
|
private bool allowtwofactor = false;
|
||||||
private string twofactor = "False";
|
private string twofactor = "False";
|
||||||
private string email = string.Empty;
|
private string email = string.Empty;
|
||||||
private string displayname = string.Empty;
|
private string displayname = string.Empty;
|
||||||
private FileManager filemanager;
|
private FileManager filemanager;
|
||||||
private int folderid = -1;
|
private int folderid = -1;
|
||||||
private int photofileid = -1;
|
private int photofileid = -1;
|
||||||
private File photo = null;
|
private File photo = null;
|
||||||
private List<Profile> profiles;
|
private List<Profile> profiles;
|
||||||
private Dictionary<string, string> settings;
|
private Dictionary<string, string> settings;
|
||||||
private string category = string.Empty;
|
private string category = string.Empty;
|
||||||
private string filter = "to";
|
private string filter = "to";
|
||||||
private List<Notification> notifications;
|
private List<Notification> notifications;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_togglepassword = SharedLocalizer["ShowPassword"];
|
_togglepassword = SharedLocalizer["ShowPassword"];
|
||||||
|
|
||||||
if (PageState.Site.Settings.ContainsKey("LoginOptions:TwoFactor") && !string.IsNullOrEmpty(PageState.Site.Settings["LoginOptions:TwoFactor"]))
|
if (PageState.Site.Settings.ContainsKey("LoginOptions:TwoFactor") && !string.IsNullOrEmpty(PageState.Site.Settings["LoginOptions:TwoFactor"]))
|
||||||
{
|
{
|
||||||
allowtwofactor = (PageState.Site.Settings["LoginOptions:TwoFactor"] == "true");
|
allowtwofactor = (PageState.Site.Settings["LoginOptions:TwoFactor"] == "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PageState.User != null)
|
if (PageState.User != null)
|
||||||
{
|
{
|
||||||
username = PageState.User.Username;
|
username = PageState.User.Username;
|
||||||
twofactor = PageState.User.TwoFactorRequired.ToString();
|
twofactor = PageState.User.TwoFactorRequired.ToString();
|
||||||
email = PageState.User.Email;
|
email = PageState.User.Email;
|
||||||
displayname = PageState.User.DisplayName;
|
displayname = PageState.User.DisplayName;
|
||||||
|
|
||||||
// get user folder
|
// get user folder
|
||||||
var folder = await FolderService.GetFolderAsync(ModuleState.SiteId, PageState.User.FolderPath);
|
var folder = await FolderService.GetFolderAsync(ModuleState.SiteId, PageState.User.FolderPath);
|
||||||
if (folder != null)
|
if (folder != null)
|
||||||
{
|
{
|
||||||
folderid = folder.FolderId;
|
folderid = folder.FolderId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PageState.User.PhotoFileId != null)
|
if (PageState.User.PhotoFileId != null)
|
||||||
{
|
{
|
||||||
photofileid = PageState.User.PhotoFileId.Value;
|
photofileid = PageState.User.PhotoFileId.Value;
|
||||||
photo = await FileService.GetFileAsync(photofileid);
|
photo = await FileService.GetFileAsync(photofileid);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
photofileid = -1;
|
photofileid = -1;
|
||||||
photo = null;
|
photo = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
||||||
settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
|
settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
|
||||||
|
|
||||||
await LoadNotificationsAsync();
|
await LoadNotificationsAsync();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddModuleMessage(Localizer["Message.User.NoLogIn"], MessageType.Warning);
|
AddModuleMessage(Localizer["Message.User.NoLogIn"], MessageType.Warning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Loading User Profile {Error}", ex.Message);
|
await logger.LogError(ex, "Error Loading User Profile {Error}", ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.Profile.Load"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Profile.Load"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task LoadNotificationsAsync()
|
private async Task LoadNotificationsAsync()
|
||||||
{
|
{
|
||||||
notifications = await NotificationService.GetNotificationsAsync(PageState.Site.SiteId, filter, PageState.User.UserId);
|
notifications = await NotificationService.GetNotificationsAsync(PageState.Site.SiteId, filter, PageState.User.UserId);
|
||||||
notifications = notifications.Where(item => item.DeletedBy != PageState.User.Username).ToList();
|
notifications = notifications.Where(item => item.DeletedBy != PageState.User.Username).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetProfileValue(string SettingName, string DefaultValue)
|
private string GetProfileValue(string SettingName, string DefaultValue)
|
||||||
=> SettingService.GetSetting(settings, SettingName, DefaultValue);
|
{
|
||||||
|
string value = SettingService.GetSetting(settings, SettingName, DefaultValue);
|
||||||
|
if (value.Contains("]"))
|
||||||
|
{
|
||||||
|
value = value.Substring(value.IndexOf("]") + 1);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task Save()
|
private async Task Save()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (username != string.Empty && email != string.Empty && ValidateProfiles())
|
if (username != string.Empty && email != string.Empty && ValidateProfiles())
|
||||||
{
|
{
|
||||||
if (_password == confirm)
|
if (_password == confirm)
|
||||||
{
|
{
|
||||||
var user = PageState.User;
|
var user = PageState.User;
|
||||||
user.Username = username;
|
user.Username = username;
|
||||||
user.Password = _password;
|
user.Password = _password;
|
||||||
user.TwoFactorRequired = bool.Parse(twofactor);
|
user.TwoFactorRequired = bool.Parse(twofactor);
|
||||||
user.Email = email;
|
user.Email = email;
|
||||||
user.DisplayName = (displayname == string.Empty ? username : displayname);
|
user.DisplayName = (displayname == string.Empty ? username : displayname);
|
||||||
user.PhotoFileId = filemanager.GetFileId();
|
user.PhotoFileId = filemanager.GetFileId();
|
||||||
if (user.PhotoFileId == -1)
|
if (user.PhotoFileId == -1)
|
||||||
{
|
{
|
||||||
user.PhotoFileId = null;
|
user.PhotoFileId = null;
|
||||||
}
|
}
|
||||||
if (user.PhotoFileId != null)
|
if (user.PhotoFileId != null)
|
||||||
{
|
{
|
||||||
photofileid = user.PhotoFileId.Value;
|
photofileid = user.PhotoFileId.Value;
|
||||||
photo = await FileService.GetFileAsync(photofileid);
|
photo = await FileService.GetFileAsync(photofileid);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
photofileid = -1;
|
photofileid = -1;
|
||||||
photo = null;
|
photo = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
await UserService.UpdateUserAsync(user);
|
user = await UserService.UpdateUserAsync(user);
|
||||||
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
|
if (user != null)
|
||||||
await logger.LogInformation("User Profile Saved");
|
{
|
||||||
|
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
|
||||||
|
await logger.LogInformation("User Profile Saved");
|
||||||
|
|
||||||
AddModuleMessage(Localizer["Success.Profile.Update"], MessageType.Success);
|
AddModuleMessage(Localizer["Success.Profile.Update"], MessageType.Success);
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddModuleMessage(Localizer["Message.Password.Invalid"], MessageType.Warning);
|
AddModuleMessage(Localizer["Message.Password.Invalid"], MessageType.Warning);
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" required />
|
<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>
|
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -32,7 +32,7 @@
|
|||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@confirm" autocomplete="new-password" required />
|
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@confirm" autocomplete="new-password" required />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglepassword</button>
|
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -104,7 +104,7 @@
|
|||||||
private Dictionary<string, string> settings;
|
private Dictionary<string, string> settings;
|
||||||
private string category = string.Empty;
|
private string category = string.Empty;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
@ -121,8 +121,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetProfileValue(string SettingName, string DefaultValue)
|
private string GetProfileValue(string SettingName, string DefaultValue)
|
||||||
=> SettingService.GetSetting(settings, SettingName, DefaultValue);
|
{
|
||||||
|
string value = SettingService.GetSetting(settings, SettingName, DefaultValue);
|
||||||
|
if (value.Contains("]"))
|
||||||
|
{
|
||||||
|
value = value.Substring(value.IndexOf("]") + 1);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task SaveUser()
|
private async Task SaveUser()
|
||||||
{
|
{
|
||||||
|
@ -32,7 +32,7 @@ else
|
|||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" />
|
<input id="password" type="@_passwordtype" class="form-control" @bind="@_password" autocomplete="new-password" />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglepassword</button>
|
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -41,7 +41,7 @@ else
|
|||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@confirm" autocomplete="new-password" />
|
<input id="confirm" type="@_passwordtype" class="form-control" @bind="@confirm" autocomplete="new-password" />
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword">@_togglepassword</button>
|
<button type="button" class="btn btn-secondary" @onclick="@TogglePassword" tabindex="-1">@_togglepassword</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -174,7 +174,7 @@ else
|
|||||||
private string deletedby;
|
private string deletedby;
|
||||||
private DateTime? deletedon;
|
private DateTime? deletedon;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
@ -201,58 +201,71 @@ else
|
|||||||
photofileid = -1;
|
photofileid = -1;
|
||||||
photo = null;
|
photo = null;
|
||||||
}
|
}
|
||||||
isdeleted = user.IsDeleted.ToString();
|
isdeleted = user.IsDeleted.ToString();
|
||||||
lastlogin = string.Format("{0:MMM dd yyyy HH:mm:ss}", user.LastLoginOn);
|
lastlogin = string.Format("{0:MMM dd yyyy HH:mm:ss}", user.LastLoginOn);
|
||||||
lastipaddress = user.LastIPAddress;
|
lastipaddress = user.LastIPAddress;
|
||||||
|
|
||||||
settings = await SettingService.GetUserSettingsAsync(user.UserId);
|
settings = await SettingService.GetUserSettingsAsync(user.UserId);
|
||||||
createdby = user.CreatedBy;
|
createdby = user.CreatedBy;
|
||||||
createdon = user.CreatedOn;
|
createdon = user.CreatedOn;
|
||||||
modifiedby = user.ModifiedBy;
|
modifiedby = user.ModifiedBy;
|
||||||
modifiedon = user.ModifiedOn;
|
modifiedon = user.ModifiedOn;
|
||||||
deletedby = user.DeletedBy;
|
deletedby = user.DeletedBy;
|
||||||
deletedon = user.DeletedOn;
|
deletedon = user.DeletedOn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Loading User {UserId} {Error}", userid, ex.Message);
|
await logger.LogError(ex, "Error Loading User {UserId} {Error}", userid, ex.Message);
|
||||||
AddModuleMessage(Localizer["Error.User.Load"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.User.Load"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetProfileValue(string SettingName, string DefaultValue)
|
private string GetProfileValue(string SettingName, string DefaultValue)
|
||||||
=> SettingService.GetSetting(settings, SettingName, DefaultValue);
|
{
|
||||||
|
string value = SettingService.GetSetting(settings, SettingName, DefaultValue);
|
||||||
|
if (value.Contains("]"))
|
||||||
|
{
|
||||||
|
value = value.Substring(value.IndexOf("]") + 1);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task SaveUser()
|
private async Task SaveUser()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (username != string.Empty && email != string.Empty && ValidateProfiles())
|
if (username != string.Empty && email != string.Empty && ValidateProfiles())
|
||||||
{
|
{
|
||||||
if (_password == confirm)
|
if (_password == confirm)
|
||||||
{
|
{
|
||||||
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
|
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
|
||||||
user.SiteId = PageState.Site.SiteId;
|
user.SiteId = PageState.Site.SiteId;
|
||||||
user.Username = username;
|
user.Username = username;
|
||||||
user.Password = _password;
|
user.Password = _password;
|
||||||
user.Email = email;
|
user.Email = email;
|
||||||
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
|
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
|
||||||
user.PhotoFileId = null;
|
user.PhotoFileId = null;
|
||||||
user.PhotoFileId = filemanager.GetFileId();
|
user.PhotoFileId = filemanager.GetFileId();
|
||||||
if (user.PhotoFileId == -1)
|
if (user.PhotoFileId == -1)
|
||||||
{
|
{
|
||||||
user.PhotoFileId = null;
|
user.PhotoFileId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
|
user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
|
||||||
|
|
||||||
user = await UserService.UpdateUserAsync(user);
|
user = await UserService.UpdateUserAsync(user);
|
||||||
await SettingService.UpdateUserSettingsAsync(settings, user.UserId);
|
if (user != null)
|
||||||
await logger.LogInformation("User Saved {User}", user);
|
{
|
||||||
|
await SettingService.UpdateUserSettingsAsync(settings, user.UserId);
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
await logger.LogInformation("User Saved {User}", user);
|
||||||
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.Password.Complexity"], MessageType.Error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -20,7 +20,7 @@ else
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<ActionLink Action="Add" Text="Add User" ResourceKey="AddUser" />
|
<ActionLink Action="Add" Text="Add User" Security="SecurityAccessLevel.Edit" ResourceKey="AddUser" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<input class="form-control" @bind="@_search" />
|
<input class="form-control" @bind="@_search" />
|
||||||
@ -41,21 +41,21 @@ else
|
|||||||
</Header>
|
</Header>
|
||||||
<Row>
|
<Row>
|
||||||
<td>
|
<td>
|
||||||
<ActionLink Action="Edit" Parameters="@($"id=" + context.UserId.ToString())" ResourceKey="EditUser" />
|
<ActionLink Action="Edit" Parameters="@($"id=" + context.UserId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="EditUser" />
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<ActionDialog Header="Delete User" Message="@string.Format(Localizer["Confirm.User.Delete"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteUser(context))" Disabled="@(context.UserId == PageState.User.UserId)" ResourceKey="DeleteUser" />
|
<ActionDialog Header="Delete User" Message="@string.Format(Localizer["Confirm.User.Delete"], context.User.DisplayName)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteUser(context))" Disabled="@(context.UserId == PageState.User.UserId)" ResourceKey="DeleteUser" />
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<ActionLink Action="Roles" Parameters="@($"id=" + context.UserId.ToString())" ResourceKey="Roles" />
|
<ActionLink Action="Roles" Parameters="@($"id=" + context.UserId.ToString())" Security="SecurityAccessLevel.Edit" ResourceKey="Roles" />
|
||||||
</td>
|
</td>
|
||||||
<td>@context.User.Username</td>
|
<td>@context.User.Username</td>
|
||||||
<td>@((MarkupString)string.Format("<a href=\"mailto:{0}\">{1}</a>", @context.User.Email, @context.User.DisplayName))</td>
|
<td>@((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>
|
<td>@((context.User.LastLoginOn != DateTime.MinValue) ? string.Format("{0:dd-MMM-yyyy HH:mm:ss}", context.User.LastLoginOn) : "")</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings">
|
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings" Security="SecurityAccessLevel.Admin">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<Section Name="User" Heading="User Settings" ResourceKey="UserSettings">
|
<Section Name="User" Heading="User Settings" ResourceKey="UserSettings">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
@ -294,6 +294,12 @@ else
|
|||||||
<input id="roleclaimtype" class="form-control" @bind="@_roleclaimtype" />
|
<input id="roleclaimtype" class="form-control" @bind="@_roleclaimtype" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="profileclaimtypes" HelpText="A comma delimited list of user profile claims provided by the provider, as well as mappings to your user profile definition. For example if the provider includes a 'given_name' claim and you have a 'FirstName' user profile definition you should specify 'given_name:FirstName'." ResourceKey="ProfileClaimTypes">User Profile Claims:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="profileclaimtypes" class="form-control" @bind="@_profileclaimtypes" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
<div class="row mb-1 align-items-center">
|
<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>
|
<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>
|
||||||
@ -395,6 +401,7 @@ else
|
|||||||
private string _identifierclaimtype;
|
private string _identifierclaimtype;
|
||||||
private string _emailclaimtype;
|
private string _emailclaimtype;
|
||||||
private string _roleclaimtype;
|
private string _roleclaimtype;
|
||||||
|
private string _profileclaimtypes;
|
||||||
private string _domainfilter;
|
private string _domainfilter;
|
||||||
private string _createusers;
|
private string _createusers;
|
||||||
|
|
||||||
@ -406,7 +413,7 @@ else
|
|||||||
private string _lifetime;
|
private string _lifetime;
|
||||||
private string _token;
|
private string _token;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
@ -449,6 +456,7 @@ else
|
|||||||
_identifierclaimtype = SettingService.GetSetting(settings, "ExternalLogin:IdentifierClaimType", "sub");
|
_identifierclaimtype = SettingService.GetSetting(settings, "ExternalLogin:IdentifierClaimType", "sub");
|
||||||
_emailclaimtype = SettingService.GetSetting(settings, "ExternalLogin:EmailClaimType", "email");
|
_emailclaimtype = SettingService.GetSetting(settings, "ExternalLogin:EmailClaimType", "email");
|
||||||
_roleclaimtype = SettingService.GetSetting(settings, "ExternalLogin:RoleClaimType", "");
|
_roleclaimtype = SettingService.GetSetting(settings, "ExternalLogin:RoleClaimType", "");
|
||||||
|
_profileclaimtypes = SettingService.GetSetting(settings, "ExternalLogin:ProfileClaimTypes", "");
|
||||||
_domainfilter = SettingService.GetSetting(settings, "ExternalLogin:DomainFilter", "");
|
_domainfilter = SettingService.GetSetting(settings, "ExternalLogin:DomainFilter", "");
|
||||||
_createusers = SettingService.GetSetting(settings, "ExternalLogin:CreateUsers", "true");
|
_createusers = SettingService.GetSetting(settings, "ExternalLogin:CreateUsers", "true");
|
||||||
|
|
||||||
@ -456,7 +464,8 @@ else
|
|||||||
_togglesecret = SharedLocalizer["ShowPassword"];
|
_togglesecret = SharedLocalizer["ShowPassword"];
|
||||||
_issuer = SettingService.GetSetting(settings, "JwtOptions:Issuer", PageState.Uri.Scheme + "://" + PageState.Alias.Name);
|
_issuer = SettingService.GetSetting(settings, "JwtOptions:Issuer", PageState.Uri.Scheme + "://" + PageState.Alias.Name);
|
||||||
_audience = SettingService.GetSetting(settings, "JwtOptions:Audience", "");
|
_audience = SettingService.GetSetting(settings, "JwtOptions:Audience", "");
|
||||||
_lifetime = SettingService.GetSetting(settings, "JwtOptions:Lifetime", "20"); }
|
_lifetime = SettingService.GetSetting(settings, "JwtOptions:Lifetime", "20");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task LoadUsersAsync(bool load)
|
private async Task LoadUsersAsync(bool load)
|
||||||
@ -522,7 +531,7 @@ else
|
|||||||
private async Task UpdateUserSettingsAsync()
|
private async Task UpdateUserSettingsAsync()
|
||||||
{
|
{
|
||||||
Dictionary<string, string> settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
|
Dictionary<string, string> settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
|
||||||
SettingService.SetSetting(settings, settingSearch, _search);
|
settings = SettingService.SetSetting(settings, settingSearch, _search);
|
||||||
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
|
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -567,6 +576,7 @@ else
|
|||||||
settings = SettingService.SetSetting(settings, "ExternalLogin:IdentifierClaimType", _identifierclaimtype, true);
|
settings = SettingService.SetSetting(settings, "ExternalLogin:IdentifierClaimType", _identifierclaimtype, true);
|
||||||
settings = SettingService.SetSetting(settings, "ExternalLogin:EmailClaimType", _emailclaimtype, true);
|
settings = SettingService.SetSetting(settings, "ExternalLogin:EmailClaimType", _emailclaimtype, true);
|
||||||
settings = SettingService.SetSetting(settings, "ExternalLogin:RoleClaimType", _roleclaimtype, true);
|
settings = SettingService.SetSetting(settings, "ExternalLogin:RoleClaimType", _roleclaimtype, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "ExternalLogin:ProfileClaimTypes", _profileclaimtypes, true);
|
||||||
settings = SettingService.SetSetting(settings, "ExternalLogin:DomainFilter", _domainfilter, true);
|
settings = SettingService.SetSetting(settings, "ExternalLogin:DomainFilter", _domainfilter, true);
|
||||||
settings = SettingService.SetSetting(settings, "ExternalLogin:CreateUsers", _createusers, true);
|
settings = SettingService.SetSetting(settings, "ExternalLogin:CreateUsers", _createusers, true);
|
||||||
|
|
||||||
|
21
Oqtane.Client/Modules/Admin/Users/ModuleInfo.cs
Normal file
21
Oqtane.Client/Modules/Admin/Users/ModuleInfo.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using Oqtane.Documentation;
|
||||||
|
using Oqtane.Models;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
|
namespace Oqtane.Modules.Admin.Users
|
||||||
|
{
|
||||||
|
[PrivateApi("Mark this as private, since it's not very useful in the public docs")]
|
||||||
|
public class ModuleInfo : IModule
|
||||||
|
{
|
||||||
|
public ModuleDefinition ModuleDefinition => new ModuleDefinition
|
||||||
|
{
|
||||||
|
Name = "Users",
|
||||||
|
Description = "Manage Users",
|
||||||
|
Categories = "Admin",
|
||||||
|
Version = Constants.Version,
|
||||||
|
PermissionNames = $"{PermissionNames.View},{PermissionNames.Edit}," +
|
||||||
|
$"{EntityNames.User}:{PermissionNames.Write}:{RoleNames.Admin}," +
|
||||||
|
$"{EntityNames.UserRole}:{PermissionNames.Write}:{RoleNames.Admin}"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -63,7 +63,7 @@ else
|
|||||||
<td>@context.EffectiveDate</td>
|
<td>@context.EffectiveDate</td>
|
||||||
<td>@context.ExpiryDate</td>
|
<td>@context.ExpiryDate</td>
|
||||||
<td>
|
<td>
|
||||||
<ActionDialog Header="Remove Role" Message="@string.Format(Localizer["Confirm.User.RemoveRole"], context.Role.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteUserRole(context.UserRoleId))" Disabled="@(context.Role.IsAutoAssigned || (context.Role.Name == RoleNames.Host && userid == PageState.User.UserId))" ResourceKey="DeleteUserRole" />
|
<ActionDialog Header="Remove Role" Message="@string.Format(Localizer["Confirm.User.RemoveRole"], context.Role.Name)" Action="Delete" Security="SecurityAccessLevel.Edit" Class="btn btn-danger" OnClick="@(async () => await DeleteUserRole(context.UserRoleId))" Disabled="@(context.Role.IsAutoAssigned || (context.Role.Name == RoleNames.Host && userid == PageState.User.UserId))" ResourceKey="DeleteUserRole" />
|
||||||
</td>
|
</td>
|
||||||
</Row>
|
</Row>
|
||||||
</Pager>
|
</Pager>
|
||||||
@ -79,7 +79,7 @@ else
|
|||||||
private string expirydate = string.Empty;
|
private string expirydate = string.Empty;
|
||||||
private List<UserRole> userroles;
|
private List<UserRole> userroles;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
@namespace Oqtane.Modules.Controls
|
@namespace Oqtane.Modules.Controls
|
||||||
|
@using System.Text.Json
|
||||||
@inherits LocalizableComponent
|
@inherits LocalizableComponent
|
||||||
|
|
||||||
@if (_visible)
|
@if (_visible)
|
||||||
@ -40,7 +41,7 @@
|
|||||||
|
|
||||||
@code {
|
@code {
|
||||||
private bool _visible = false;
|
private bool _visible = false;
|
||||||
private string _permissions = string.Empty;
|
private List<Permission> _permissions;
|
||||||
private bool _editmode = false;
|
private bool _editmode = false;
|
||||||
private bool _authorized = false;
|
private bool _authorized = false;
|
||||||
private string _iconSpan = string.Empty;
|
private string _iconSpan = string.Empty;
|
||||||
@ -61,7 +62,10 @@
|
|||||||
public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel
|
public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Permissions { get; set; } // optional - can be used to specify a permission string
|
public string Permissions { get; set; } // deprecated - use PermissionList instead
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public List<Permission> PermissionList { get; set; } // optional - can be used to specify permissions
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Class { get; set; } // optional
|
public string Class { get; set; } // optional
|
||||||
@ -78,7 +82,15 @@
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public string IconName { get; set; } // optional - specifies an icon for the link - default is no icon
|
public string IconName { get; set; } // optional - specifies an icon for the link - default is no icon
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override void OnInitialized()
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(Permissions))
|
||||||
|
{
|
||||||
|
PermissionList = JsonSerializer.Deserialize<List<Permission>>(Permissions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
base.OnParametersSet();
|
base.OnParametersSet();
|
||||||
|
|
||||||
@ -109,7 +121,7 @@
|
|||||||
Header = Localize(nameof(Header), Header);
|
Header = Localize(nameof(Header), Header);
|
||||||
Message = Localize(nameof(Message), Message);
|
Message = Localize(nameof(Message), Message);
|
||||||
|
|
||||||
_permissions = (string.IsNullOrEmpty(Permissions)) ? ModuleState.Permissions : Permissions;
|
_permissions = (PermissionList == null) ? ModuleState.PermissionList : PermissionList;
|
||||||
_authorized = IsAuthorized();
|
_authorized = IsAuthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
@namespace Oqtane.Modules.Controls
|
@namespace Oqtane.Modules.Controls
|
||||||
@using System.Net
|
@using System.Net
|
||||||
|
@using System.Text.Json
|
||||||
@inherits LocalizableComponent
|
@inherits LocalizableComponent
|
||||||
@inject IUserService UserService
|
@inject IUserService UserService
|
||||||
|
|
||||||
@ -26,7 +27,7 @@
|
|||||||
private string _text = string.Empty;
|
private string _text = string.Empty;
|
||||||
private string _parameters = string.Empty;
|
private string _parameters = string.Empty;
|
||||||
private string _url = string.Empty;
|
private string _url = string.Empty;
|
||||||
private string _permissions = string.Empty;
|
private List<Permission> _permissions;
|
||||||
private bool _editmode = false;
|
private bool _editmode = false;
|
||||||
private bool _authorized = false;
|
private bool _authorized = false;
|
||||||
private string _classname = "btn btn-primary";
|
private string _classname = "btn btn-primary";
|
||||||
@ -52,7 +53,10 @@
|
|||||||
public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel
|
public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Permissions { get; set; } // optional - can be used to specify a permission string
|
public string Permissions { get; set; } // deprecated - use PermissionList instead
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public List<Permission> PermissionList { get; set; } // optional - can be used to specify permissions
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool Disabled { get; set; } // optional
|
public bool Disabled { get; set; } // optional
|
||||||
@ -75,6 +79,14 @@
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public string ReturnUrl { get; set; } // optional - used to set a url to redirect to
|
public string ReturnUrl { get; set; } // optional - used to set a url to redirect to
|
||||||
|
|
||||||
|
protected override void OnInitialized()
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(Permissions))
|
||||||
|
{
|
||||||
|
PermissionList = JsonSerializer.Deserialize<List<Permission>>(Permissions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
base.OnParametersSet();
|
base.OnParametersSet();
|
||||||
@ -119,7 +131,7 @@
|
|||||||
_iconSpan = $"<span class=\"{IconName}\"></span>{(IconOnly ? "" : " ")}";
|
_iconSpan = $"<span class=\"{IconName}\"></span>{(IconOnly ? "" : " ")}";
|
||||||
}
|
}
|
||||||
|
|
||||||
_permissions = (string.IsNullOrEmpty(Permissions)) ? ModuleState.Permissions : Permissions;
|
_permissions = (PermissionList == null) ? ModuleState.PermissionList : PermissionList;
|
||||||
_text = Localize(nameof(Text), _text);
|
_text = Localize(nameof(Text), _text);
|
||||||
_url = (ModuleId == -1) ? EditUrl(Action, _parameters) : EditUrl(ModuleId, Action, _parameters);
|
_url = (ModuleId == -1) ? EditUrl(Action, _parameters) : EditUrl(ModuleId, Action, _parameters);
|
||||||
if (!string.IsNullOrEmpty(ReturnUrl))
|
if (!string.IsNullOrEmpty(ReturnUrl))
|
||||||
|
153
Oqtane.Client/Modules/Controls/AutoComplete.razor
Normal file
153
Oqtane.Client/Modules/Controls/AutoComplete.razor
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
@namespace Oqtane.Modules.Controls
|
||||||
|
@inherits LocalizableComponent
|
||||||
|
|
||||||
|
<div class="app-autocomplete">
|
||||||
|
<input class="form-control" value="@Value" @oninput="OnInput" @onkeyup="OnKeyUp" placeholder="@Placeholder" autocomplete="off" />
|
||||||
|
@if (_results != null)
|
||||||
|
{
|
||||||
|
<select class="form-select" style="position: relative;" value="@Value" size="@Rows" @onkeyup="OnKeyUp" @onchange="(e => OnChange(e))">
|
||||||
|
@if (_results.Any())
|
||||||
|
{
|
||||||
|
@foreach (var result in _results)
|
||||||
|
{
|
||||||
|
if (result.Value == Value)
|
||||||
|
{
|
||||||
|
<option selected>@result.Value</option>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<option>@result.Value</option>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<option disabled>No Results</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
Dictionary<string, string> _results;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public Func<string, Task<Dictionary<string, string>>> OnSearch { get; set; } // required - an async delegate method which accepts a filter string parameter and returns a dictionary
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public int Characters { get; set; } = 3; // optional - number of characters before search is initiated
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public int Rows { get; set; } = 3; // optional - number of result rows to display
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string Placeholder { get; set; } // optional - placeholder input text
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string Value { get; set; } // value of item selected
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string Key { get; set; } // key of item selected
|
||||||
|
|
||||||
|
private async Task OnInput(ChangeEventArgs e)
|
||||||
|
{
|
||||||
|
Value = e.Value?.ToString();
|
||||||
|
if (Value?.Length >= Characters)
|
||||||
|
{
|
||||||
|
_results = await OnSearch?.Invoke(Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_results = null;
|
||||||
|
}
|
||||||
|
SetKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OnKeyUp(KeyboardEventArgs e)
|
||||||
|
{
|
||||||
|
var index = -1;
|
||||||
|
switch (e.Key)
|
||||||
|
{
|
||||||
|
case "ArrowDown":
|
||||||
|
if (_results == null)
|
||||||
|
{
|
||||||
|
if (Value?.Length >= Characters)
|
||||||
|
{
|
||||||
|
_results = await OnSearch?.Invoke(Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
index = GetIndex();
|
||||||
|
if (index < _results.Count - 1)
|
||||||
|
{
|
||||||
|
Value = _results.ElementAt(index + 1).Value;
|
||||||
|
Key = _results.ElementAt(index + 1).Key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "ArrowUp":
|
||||||
|
index = GetIndex();
|
||||||
|
if (index > 0)
|
||||||
|
{
|
||||||
|
Value = _results.ElementAt(index - 1).Value;
|
||||||
|
Key = _results.ElementAt(index - 1).Key;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "ArrowRight":
|
||||||
|
case "Tab":
|
||||||
|
_results = null;
|
||||||
|
break;
|
||||||
|
case "Enter": // note within a form the enter key submits the entire form
|
||||||
|
case "NumpadEnter":
|
||||||
|
_results = null;
|
||||||
|
break;
|
||||||
|
case "Escape":
|
||||||
|
Value = "";
|
||||||
|
_results = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnChange(ChangeEventArgs e)
|
||||||
|
{
|
||||||
|
Value = (string)e.Value;
|
||||||
|
SetKey();
|
||||||
|
_results = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetIndex()
|
||||||
|
{
|
||||||
|
if (_results != null)
|
||||||
|
{
|
||||||
|
for (int index = 0; index < _results.Count; index++)
|
||||||
|
{
|
||||||
|
if (_results.ElementAt(index).Value == Value)
|
||||||
|
{
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetKey()
|
||||||
|
{
|
||||||
|
var index = GetIndex();
|
||||||
|
if (index != -1)
|
||||||
|
{
|
||||||
|
Key = _results.ElementAt(index).Key;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Key = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
Value = "";
|
||||||
|
Key = "";
|
||||||
|
_results = null;
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,12 @@
|
|||||||
@namespace Oqtane.Modules.Controls
|
@namespace Oqtane.Modules.Controls
|
||||||
|
@using System.Threading
|
||||||
@inherits ModuleControlBase
|
@inherits ModuleControlBase
|
||||||
@inject IFolderService FolderService
|
@inject IFolderService FolderService
|
||||||
@inject IFileService FileService
|
@inject IFileService FileService
|
||||||
@inject IStringLocalizer<FileManager> Localizer
|
@inject IStringLocalizer<FileManager> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
@if (_folders != null)
|
@if (_initialized)
|
||||||
{
|
{
|
||||||
<div id="@Id" class="container-fluid px-0">
|
<div id="@Id" class="container-fluid px-0">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -53,7 +54,7 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="col mt-2 text-end">
|
<div class="col mt-2 text-end">
|
||||||
<button type="button" class="btn btn-success" @onclick="UploadFile">@SharedLocalizer["Upload"]</button>
|
<button type="button" class="btn btn-success" @onclick="UploadFiles">@SharedLocalizer["Upload"]</button>
|
||||||
@if (ShowFiles && GetFileId() != -1)
|
@if (ShowFiles && GetFileId() != -1)
|
||||||
{
|
{
|
||||||
<button type="button" class="btn btn-danger mx-1" @onclick="DeleteFile">@SharedLocalizer["Delete"]</button>
|
<button type="button" class="btn btn-danger mx-1" @onclick="DeleteFile">@SharedLocalizer["Delete"]</button>
|
||||||
@ -86,286 +87,310 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private string _id;
|
private bool _initialized = false;
|
||||||
private List<Folder> _folders;
|
private List<Folder> _folders;
|
||||||
private List<File> _files = new List<File>();
|
private List<File> _files = new List<File>();
|
||||||
private string _fileinputid = string.Empty;
|
private string _fileinputid = string.Empty;
|
||||||
private string _progressinfoid = string.Empty;
|
private string _progressinfoid = string.Empty;
|
||||||
private string _progressbarid = string.Empty;
|
private string _progressbarid = string.Empty;
|
||||||
private string _filter = "*";
|
private string _filter = "*";
|
||||||
private bool _haseditpermission = false;
|
private bool _haseditpermission = false;
|
||||||
private string _image = string.Empty;
|
private string _image = string.Empty;
|
||||||
private File _file = null;
|
private File _file = null;
|
||||||
private string _guid;
|
private string _guid;
|
||||||
private string _message = string.Empty;
|
private string _message = string.Empty;
|
||||||
private MessageType _messagetype;
|
private MessageType _messagetype;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Id { get; set; } // optional - for setting the id of the FileManager component for accessibility
|
public string Id { get; set; } // optional - for setting the id of the FileManager component for accessibility
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public int FolderId { get; set; } = -1; // optional - for setting a specific default folder by folderid
|
public int FolderId { get; set; } = -1; // optional - for setting a specific default folder by folderid
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Folder { get; set; } = ""; // optional - for setting a specific default folder by folder path
|
public string Folder { get; set; } = ""; // optional - for setting a specific default folder by folder path
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public int FileId { get; set; } = -1; // optional - for selecting a specific file by default
|
public int FileId { get; set; } = -1; // optional - for selecting a specific file by default
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Filter { get; set; } // optional - comma delimited list of file types that can be selected or uploaded ie. "jpg,gif"
|
public string Filter { get; set; } // optional - comma delimited list of file types that can be selected or uploaded ie. "jpg,gif"
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool ShowFiles { get; set; } = true; // optional - for indicating whether a list of files should be displayed - default is true
|
public bool ShowFiles { get; set; } = true; // optional - for indicating whether a list of files should be displayed - default is true
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool ShowUpload { get; set; } = true; // optional - for indicating whether a Upload controls should be displayed - default is true
|
public bool ShowUpload { get; set; } = true; // optional - for indicating whether a Upload controls should be displayed - default is true
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool ShowFolders { get; set; } = true; // optional - for indicating whether a list of folders should be displayed - default is true
|
public bool ShowFolders { get; set; } = true; // optional - for indicating whether a list of folders should be displayed - default is true
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool ShowImage { get; set; } = true; // optional - for indicating whether an image thumbnail should be displayed - default is true
|
public bool ShowImage { get; set; } = true; // optional - for indicating whether an image thumbnail should be displayed - default is true
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool ShowSuccess { get; set; } = false; // optional - for indicating whether a success message should be displayed upon successful upload - default is false
|
public bool ShowSuccess { get; set; } = false; // optional - for indicating whether a success message should be displayed upon successful upload - default is false
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool UploadMultiple { get; set; } = false; // optional - enable multiple file uploads - default false
|
public bool UploadMultiple { get; set; } = false; // optional - enable multiple file uploads - default false
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public EventCallback<int> OnUpload { get; set; } // optional - executes a method in the calling component when a file is uploaded
|
public EventCallback<int> OnUpload { get; set; } // optional - executes a method in the calling component when a file is uploaded
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public EventCallback<int> OnSelect { get; set; } // optional - executes a method in the calling component when a file is selected
|
public EventCallback<int> OnSelect { get; set; } // optional - executes a method in the calling component when a file is selected
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public EventCallback<int> OnDelete { get; set; } // optional - executes a method in the calling component when a file is deleted
|
public EventCallback<int> OnDelete { get; set; } // optional - executes a method in the calling component when a file is deleted
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(Id))
|
// packages folder is a framework folder for uploading installable nuget packages
|
||||||
{
|
if (Folder == Constants.PackagesFolder)
|
||||||
_id = Id;
|
{
|
||||||
}
|
ShowFiles = false;
|
||||||
|
ShowFolders = false;
|
||||||
|
Filter = "nupkg";
|
||||||
|
ShowSuccess = true;
|
||||||
|
}
|
||||||
|
|
||||||
// packages folder is a framework folder for uploading installable nuget packages
|
if (!ShowFiles)
|
||||||
if (Folder == Constants.PackagesFolder)
|
{
|
||||||
{
|
ShowImage = false;
|
||||||
ShowFiles = false;
|
}
|
||||||
ShowFolders = false;
|
|
||||||
Filter = "nupkg";
|
|
||||||
ShowSuccess = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ShowFiles)
|
_folders = await FolderService.GetFoldersAsync(ModuleState.SiteId);
|
||||||
{
|
|
||||||
ShowImage = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_folders = await FolderService.GetFoldersAsync(ModuleState.SiteId);
|
if (!string.IsNullOrEmpty(Folder) && Folder != Constants.PackagesFolder)
|
||||||
|
{
|
||||||
|
Folder folder = await FolderService.GetFolderAsync(ModuleState.SiteId, Folder);
|
||||||
|
if (folder != null)
|
||||||
|
{
|
||||||
|
FolderId = folder.FolderId;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FolderId = -1;
|
||||||
|
_message = "Folder Path " + Folder + "Does Not Exist";
|
||||||
|
_messagetype = MessageType.Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Folder) && Folder != Constants.PackagesFolder)
|
if (FileId != -1)
|
||||||
{
|
{
|
||||||
Folder folder = await FolderService.GetFolderAsync(ModuleState.SiteId, Folder);
|
File file = await FileService.GetFileAsync(FileId);
|
||||||
if (folder != null)
|
if (file != null)
|
||||||
{
|
{
|
||||||
FolderId = folder.FolderId;
|
FolderId = file.FolderId;
|
||||||
}
|
await OnSelect.InvokeAsync(FileId);
|
||||||
else
|
}
|
||||||
{
|
else
|
||||||
FolderId = -1;
|
{
|
||||||
_message = "Folder Path " + Folder + "Does Not Exist";
|
FileId = -1; // file does not exist
|
||||||
_messagetype = MessageType.Error;
|
_message = "FileId " + FileId.ToString() + "Does Not Exist";
|
||||||
}
|
_messagetype = MessageType.Error;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (FileId != -1)
|
await SetImage();
|
||||||
{
|
|
||||||
File file = await FileService.GetFileAsync(FileId);
|
|
||||||
if (file != null)
|
|
||||||
{
|
|
||||||
FolderId = file.FolderId;
|
|
||||||
await OnSelect.InvokeAsync(FileId);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
FileId = -1; // file does not exist
|
|
||||||
_message = "FileId " + FileId.ToString() + "Does Not Exist";
|
|
||||||
_messagetype = MessageType.Error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await SetImage();
|
if (!string.IsNullOrEmpty(Filter))
|
||||||
|
{
|
||||||
|
_filter = "." + Filter.Replace(",", ",.");
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Filter))
|
await GetFiles();
|
||||||
{
|
|
||||||
_filter = "." + Filter.Replace(",", ",.");
|
|
||||||
}
|
|
||||||
|
|
||||||
await GetFiles();
|
// create unique id for component
|
||||||
|
_guid = Guid.NewGuid().ToString("N");
|
||||||
|
_fileinputid = "FileInput_" + _guid;
|
||||||
|
_progressinfoid = "ProgressInfo_" + _guid;
|
||||||
|
_progressbarid = "ProgressBar_" + _guid;
|
||||||
|
|
||||||
// create unique id for component
|
_initialized = true;
|
||||||
_guid = Guid.NewGuid().ToString("N");
|
}
|
||||||
_fileinputid = _guid + "FileInput";
|
|
||||||
_progressinfoid = _guid + "ProgressInfo";
|
|
||||||
_progressbarid = _guid + "ProgressBar";
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task GetFiles()
|
private async Task GetFiles()
|
||||||
{
|
{
|
||||||
_haseditpermission = false;
|
_haseditpermission = false;
|
||||||
if (Folder == Constants.PackagesFolder)
|
if (Folder == Constants.PackagesFolder)
|
||||||
{
|
{
|
||||||
_haseditpermission = UserSecurity.IsAuthorized(PageState.User, RoleNames.Host);
|
_haseditpermission = UserSecurity.IsAuthorized(PageState.User, RoleNames.Host);
|
||||||
_files = new List<File>();
|
_files = new List<File>();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Folder folder = _folders.FirstOrDefault(item => item.FolderId == FolderId);
|
Folder folder = _folders.FirstOrDefault(item => item.FolderId == FolderId);
|
||||||
if (folder != null)
|
if (folder != null)
|
||||||
{
|
{
|
||||||
_haseditpermission = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, folder.Permissions);
|
_haseditpermission = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, folder.PermissionList);
|
||||||
_files = await FileService.GetFilesAsync(FolderId);
|
_files = await FileService.GetFilesAsync(FolderId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_haseditpermission = false;
|
_haseditpermission = false;
|
||||||
_files = new List<File>();
|
_files = new List<File>();
|
||||||
}
|
}
|
||||||
}
|
if (_filter != "*")
|
||||||
if (_filter != "*")
|
{
|
||||||
{
|
List<File> filtered = new List<File>();
|
||||||
List<File> filtered = new List<File>();
|
foreach (File file in _files)
|
||||||
foreach (File file in _files)
|
{
|
||||||
{
|
if (_filter.ToUpper().IndexOf("." + file.Extension.ToUpper()) != -1)
|
||||||
if (_filter.ToUpper().IndexOf("." + file.Extension.ToUpper()) != -1)
|
{
|
||||||
{
|
filtered.Add(file);
|
||||||
filtered.Add(file);
|
}
|
||||||
}
|
}
|
||||||
}
|
_files = filtered;
|
||||||
_files = filtered;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task FolderChanged(ChangeEventArgs e)
|
private async Task FolderChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
_message = string.Empty;
|
_message = string.Empty;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
FolderId = int.Parse((string)e.Value);
|
FolderId = int.Parse((string)e.Value);
|
||||||
await GetFiles();
|
await GetFiles();
|
||||||
FileId = -1;
|
FileId = -1;
|
||||||
_file = null;
|
_file = null;
|
||||||
_image = string.Empty;
|
_image = string.Empty;
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Loading Files {Error}", ex.Message);
|
await logger.LogError(ex, "Error Loading Files {Error}", ex.Message);
|
||||||
_message = Localizer["Error.File.Load"];
|
_message = Localizer["Error.File.Load"];
|
||||||
_messagetype = MessageType.Error;
|
_messagetype = MessageType.Error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task FileChanged(ChangeEventArgs e)
|
private async Task FileChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
_message = string.Empty;
|
_message = string.Empty;
|
||||||
FileId = int.Parse((string)e.Value);
|
FileId = int.Parse((string)e.Value);
|
||||||
if (FileId != -1)
|
if (FileId != -1)
|
||||||
{
|
{
|
||||||
await OnSelect.InvokeAsync(FileId);
|
await OnSelect.InvokeAsync(FileId);
|
||||||
}
|
}
|
||||||
|
|
||||||
await SetImage();
|
await SetImage();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SetImage()
|
private async Task SetImage()
|
||||||
{
|
{
|
||||||
_image = string.Empty;
|
_image = string.Empty;
|
||||||
_file = null;
|
_file = null;
|
||||||
if (FileId != -1)
|
if (FileId != -1)
|
||||||
{
|
{
|
||||||
_file = await FileService.GetFileAsync(FileId);
|
_file = await FileService.GetFileAsync(FileId);
|
||||||
if (_file != null && ShowImage && _file.ImageHeight != 0 && _file.ImageWidth != 0)
|
if (_file != null && ShowImage && _file.ImageHeight != 0 && _file.ImageWidth != 0)
|
||||||
{
|
{
|
||||||
var maxwidth = 200;
|
var maxwidth = 200;
|
||||||
var maxheight = 200;
|
var maxheight = 200;
|
||||||
|
|
||||||
var ratioX = (double)maxwidth / (double)_file.ImageWidth;
|
var ratioX = (double)maxwidth / (double)_file.ImageWidth;
|
||||||
var ratioY = (double)maxheight / (double)_file.ImageHeight;
|
var ratioY = (double)maxheight / (double)_file.ImageHeight;
|
||||||
var ratio = ratioX < ratioY ? ratioX : ratioY;
|
var ratio = ratioX < ratioY ? ratioX : ratioY;
|
||||||
|
|
||||||
_image = "<img src=\"" + _file.Url + "\" alt=\"" + _file.Name +
|
_image = "<img src=\"" + _file.Url + "\" alt=\"" + _file.Name +
|
||||||
"\" width=\"" + Convert.ToInt32(_file.ImageWidth * ratio).ToString() +
|
"\" width=\"" + Convert.ToInt32(_file.ImageWidth * ratio).ToString() +
|
||||||
"\" height=\"" + Convert.ToInt32(_file.ImageHeight * ratio).ToString() + "\" />";
|
"\" height=\"" + Convert.ToInt32(_file.ImageHeight * ratio).ToString() + "\" />";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UploadFile()
|
private async Task UploadFiles()
|
||||||
{
|
{
|
||||||
_message = string.Empty;
|
_message = string.Empty;
|
||||||
var interop = new Interop(JSRuntime);
|
var interop = new Interop(JSRuntime);
|
||||||
var upload = await interop.GetFiles(_fileinputid);
|
var uploads = await interop.GetFiles(_fileinputid);
|
||||||
if (upload.Length > 0)
|
if (uploads.Length > 0)
|
||||||
{
|
{
|
||||||
string restricted = "";
|
string restricted = "";
|
||||||
foreach (var file in upload)
|
foreach (var upload in uploads)
|
||||||
{
|
{
|
||||||
var extension = (file.LastIndexOf(".") != -1) ? file.Substring(file.LastIndexOf(".") + 1) : "";
|
var extension = (upload.LastIndexOf(".") != -1) ? upload.Substring(upload.LastIndexOf(".") + 1) : "";
|
||||||
if (!Constants.UploadableFiles.Split(',').Contains(extension.ToLower()))
|
if (!Constants.UploadableFiles.Split(',').Contains(extension.ToLower()))
|
||||||
{
|
{
|
||||||
restricted += (restricted == "" ? "" : ",") + extension;
|
restricted += (restricted == "" ? "" : ",") + extension;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (restricted == "")
|
if (restricted == "")
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string result;
|
// upload the files
|
||||||
if (Folder == Constants.PackagesFolder)
|
var posturl = Utilities.TenantUrl(PageState.Alias, "/api/file/upload");
|
||||||
{
|
var folder = (Folder == Constants.PackagesFolder) ? Folder : FolderId.ToString();
|
||||||
result = await FileService.UploadFilesAsync(Folder, upload, _guid);
|
await interop.UploadFiles(posturl, folder, _guid, SiteState.AntiForgeryToken);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = await FileService.UploadFilesAsync(FolderId, upload, _guid);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result == string.Empty)
|
// uploading is asynchronous so we need to wait for the uploads to complete
|
||||||
{
|
// note that this will only wait a maximum of 15 seconds which may not be long enough for very large file uploads
|
||||||
await logger.LogInformation("File Upload Succeeded {Files}", upload);
|
bool success = false;
|
||||||
if (ShowSuccess)
|
int attempts = 0;
|
||||||
{
|
while (attempts < 5 && !success)
|
||||||
_message = Localizer["Success.File.Upload"];
|
{
|
||||||
_messagetype = MessageType.Success;
|
attempts += 1;
|
||||||
}
|
Thread.Sleep(1000 * attempts); // progressive retry
|
||||||
|
|
||||||
// set FileId to first file in upload collection
|
success = true;
|
||||||
await GetFiles();
|
List<File> files = await FileService.GetFilesAsync(folder);
|
||||||
var file = _files.Where(item => item.Name == upload[0]).FirstOrDefault();
|
if (files.Count > 0)
|
||||||
if (file != null)
|
{
|
||||||
{
|
foreach (string upload in uploads)
|
||||||
FileId = file.FileId;
|
{
|
||||||
await SetImage();
|
if (!files.Exists(item => item.Name == upload))
|
||||||
await OnUpload.InvokeAsync(FileId);
|
{
|
||||||
}
|
success = false;
|
||||||
StateHasChanged();
|
}
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{
|
}
|
||||||
await logger.LogError("File Upload Failed For {Files}", result.Replace(",", ", "));
|
|
||||||
|
|
||||||
_message = Localizer["Error.File.Upload"];
|
// reset progress indicators
|
||||||
_messagetype = MessageType.Error;
|
await interop.SetElementAttribute(_guid + "ProgressInfo", "style", "display: none;");
|
||||||
}
|
await interop.SetElementAttribute(_guid + "ProgressBar", "style", "display: none;");
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
await logger.LogInformation("File Upload Succeeded {Files}", uploads);
|
||||||
|
if (ShowSuccess)
|
||||||
|
{
|
||||||
|
_message = Localizer["Success.File.Upload"];
|
||||||
|
_messagetype = MessageType.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await logger.LogInformation("File Upload Failed Or Is Still In Progress {Files}", uploads);
|
||||||
|
_message = Localizer["Error.File.Upload"];
|
||||||
|
_messagetype = MessageType.Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Folder == Constants.PackagesFolder)
|
||||||
|
{
|
||||||
|
await OnUpload.InvokeAsync(-1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// set FileId to first file in upload collection
|
||||||
|
await GetFiles();
|
||||||
|
var file = _files.Where(item => item.Name == uploads[0]).FirstOrDefault();
|
||||||
|
if (file != null)
|
||||||
|
{
|
||||||
|
FileId = file.FileId;
|
||||||
|
await SetImage();
|
||||||
|
await OnUpload.InvokeAsync(FileId);
|
||||||
|
}
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "File Upload Failed {Error}", ex.Message);
|
await logger.LogError(ex, "File Upload Failed {Error}", ex.Message);
|
||||||
|
|
||||||
_message = Localizer["Error.File.Upload"];
|
_message = Localizer["Error.File.Upload"];
|
||||||
_messagetype = MessageType.Error;
|
_messagetype = MessageType.Error;
|
||||||
}
|
}
|
||||||
|
@ -8,16 +8,16 @@
|
|||||||
@if ((Toolbar == "Top" || Toolbar == "Both") && _pages > 0 && Items.Count() > _maxItems)
|
@if ((Toolbar == "Top" || Toolbar == "Both") && _pages > 0 && Items.Count() > _maxItems)
|
||||||
{
|
{
|
||||||
<ul class="pagination justify-content-center my-2">
|
<ul class="pagination justify-content-center my-2">
|
||||||
<li class="page-item@((_page > 1) ? "" : " disabled")">
|
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
<a class="page-link" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
@if (_pages > _displayPages && _displayPages > 1)
|
@if (_pages > _displayPages && _displayPages > 1)
|
||||||
{
|
{
|
||||||
<li class="page-item@((_page > _displayPages) ? "" : " disabled")">
|
<li class="page-item@((_page > _displayPages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => SkipPages("back"))><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
<a class="page-link" @onclick=@(async () => SkipPages("back"))><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
<li class="page-item@((_page > 1) ? "" : " disabled")">
|
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => NavigateToPage("previous"))><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
|
<a class="page-link" @onclick=@(async () => NavigateToPage("previous"))><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
@for (int i = _startPage; i <= _endPage; i++)
|
@for (int i = _startPage; i <= _endPage; i++)
|
||||||
@ -25,27 +25,27 @@
|
|||||||
var pager = i;
|
var pager = i;
|
||||||
if (pager == _page)
|
if (pager == _page)
|
||||||
{
|
{
|
||||||
<li class="page-item active">
|
<li class="page-item app-pager-pointer active">
|
||||||
<a class="page-link" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
<a class="page-link" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<li class="page-item">
|
<li class="page-item app-pager-pointer">
|
||||||
<a class="page-link" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
<a class="page-link" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<li class="page-item@((_page < _pages) ? "" : " disabled")">
|
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => NavigateToPage("next"))><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
<a class="page-link" @onclick=@(async () => NavigateToPage("next"))><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
@if (_pages > _displayPages && _displayPages > 1)
|
@if (_pages > _displayPages && _displayPages > 1)
|
||||||
{
|
{
|
||||||
<li class="page-item@((_endPage < _pages) ? "" : " disabled")">
|
<li class="page-item@((_endPage < _pages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => SkipPages("forward"))><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
<a class="page-link" @onclick=@(async () => SkipPages("forward"))><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
<li class="page-item@((_page < _pages) ? "" : " disabled")">
|
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => UpdateList(_pages))><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
<a class="page-link" @onclick=@(async () => UpdateList(_pages))><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
<li class="page-item disabled">
|
<li class="page-item disabled">
|
||||||
@ -55,46 +55,46 @@
|
|||||||
}
|
}
|
||||||
@if (Format == "Table" && Row != null)
|
@if (Format == "Table" && Row != null)
|
||||||
{
|
{
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="@Class">
|
<table class="@Class">
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="@RowClass">@Header</tr>
|
<tr class="@RowClass">@Header</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@foreach (var item in ItemList)
|
@foreach (var item in ItemList)
|
||||||
{
|
{
|
||||||
<tr class="@RowClass">@Row(item)</tr>
|
<tr class="@RowClass">@Row(item)</tr>
|
||||||
@if (Detail != null)
|
@if (Detail != null)
|
||||||
{
|
{
|
||||||
<tr>@Detail(item)</tr>
|
<tr>@Detail(item)</tr>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</tbody>
|
</tbody>
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr class="@RowClass">@Footer</tr>
|
<tr class="@RowClass">@Footer</tr>
|
||||||
</tfoot>
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@if (Format == "Grid" && Row != null)
|
@if (Format == "Grid" && Row != null)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
int rows = 0;
|
int rows = 0;
|
||||||
int cols = 0;
|
int cols = 0;
|
||||||
if (ItemList != null)
|
if (ItemList != null)
|
||||||
{
|
{
|
||||||
if (_columns == 0)
|
if (_columns == 0)
|
||||||
{
|
{
|
||||||
count = ItemList.Count();
|
count = ItemList.Count();
|
||||||
rows = 1;
|
rows = 1;
|
||||||
cols = count;
|
cols = count;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
count = (int)Math.Ceiling(ItemList.Count() / (decimal)_columns) * _columns;
|
count = (int)Math.Ceiling(ItemList.Count() / (decimal)_columns) * _columns;
|
||||||
rows = count / _columns;
|
rows = count / _columns;
|
||||||
cols = _columns;
|
cols = _columns;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<div class="@Class">
|
<div class="@Class">
|
||||||
@for (int row = 0; row < rows; row++)
|
@for (int row = 0; row < rows; row++)
|
||||||
@ -116,19 +116,19 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@if ((Toolbar == "Bottom" || Toolbar == "Both") && _pages > 0 && Items.Count() > _maxItems)
|
@if ((Toolbar == "Bottom" || Toolbar == "Both") && _pages > 0 && Items.Count() > _maxItems)
|
||||||
{
|
{
|
||||||
<ul class="pagination justify-content-center my-2">
|
<ul class="pagination justify-content-center my-2">
|
||||||
<li class="page-item@((_page > 1) ? "" : " disabled")">
|
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
<a class="page-link" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
@if (_pages > _displayPages && _displayPages > 1)
|
@if (_pages > _displayPages && _displayPages > 1)
|
||||||
{
|
{
|
||||||
<li class="page-item@((_page > _displayPages) ? "" : " disabled")">
|
<li class="page-item@((_page > _displayPages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => SkipPages("back"))><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
<a class="page-link" @onclick=@(async () => SkipPages("back"))><span class="oi oi-media-skip-backward" title="skip back" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
<li class="page-item@((_page > 1) ? "" : " disabled")">
|
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => NavigateToPage("previous"))><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
|
<a class="page-link" @onclick=@(async () => NavigateToPage("previous"))><span class="oi oi-chevron-left" title="previous" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
@for (int i = _startPage; i <= _endPage; i++)
|
@for (int i = _startPage; i <= _endPage; i++)
|
||||||
@ -136,100 +136,100 @@
|
|||||||
var pager = i;
|
var pager = i;
|
||||||
if (pager == _page)
|
if (pager == _page)
|
||||||
{
|
{
|
||||||
<li class="page-item active">
|
<li class="page-item app-pager-pointer active">
|
||||||
<a class="page-link" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
<a class="page-link" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<li class="page-item">
|
<li class="page-item app-pager-pointer">
|
||||||
<a class="page-link" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
<a class="page-link" @onclick=@(async () => UpdateList(pager))>@pager</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<li class="page-item@((_page < _pages) ? "" : " disabled")">
|
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => NavigateToPage("next"))><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
<a class="page-link" @onclick=@(async () => NavigateToPage("next"))><span class="oi oi-chevron-right" title="next" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
@if (_pages > _displayPages && _displayPages > 1)
|
@if (_pages > _displayPages && _displayPages > 1)
|
||||||
{
|
{
|
||||||
<li class="page-item@((_endPage < _pages) ? "" : " disabled")">
|
<li class="page-item@((_endPage < _pages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => SkipPages("forward"))><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
<a class="page-link" @onclick=@(async () => SkipPages("forward"))><span class="oi oi-media-skip-forward" title="skip forward" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
<li class="page-item@((_page < _pages) ? "" : " disabled")">
|
<li class="page-item@((_page < _pages) ? " app-pager-pointer" : " disabled")">
|
||||||
<a class="page-link" @onclick=@(async () => UpdateList(_pages))><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
<a class="page-link" @onclick=@(async () => UpdateList(_pages))><span class="oi oi-media-step-forward" title="end" aria-hidden="true"></span></a>
|
||||||
</li>
|
</li>
|
||||||
<li class="page-item disabled">
|
<li class="page-item disabled">
|
||||||
<a class="page-link" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
|
<a class="page-link" style="white-space: nowrap;">@Localizer["PageOfPages", _page, _pages]</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private IStringLocalizer Localizer;
|
private IStringLocalizer Localizer;
|
||||||
private int _pages = 0;
|
private int _pages = 0;
|
||||||
private int _page = 1;
|
private int _page = 1;
|
||||||
private int _maxItems = 10;
|
private int _maxItems = 10;
|
||||||
private int _displayPages = 5;
|
private int _displayPages = 5;
|
||||||
private int _startPage = 0;
|
private int _startPage = 0;
|
||||||
private int _endPage = 0;
|
private int _endPage = 0;
|
||||||
private int _columns = 0;
|
private int _columns = 0;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Format { get; set; } // Table or Grid
|
public string Format { get; set; } // Table or Grid
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Toolbar { get; set; } // Top, Bottom or Both
|
public string Toolbar { get; set; } // Top, Bottom or Both
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public RenderFragment Header { get; set; } = null; // only applicable to Table layouts
|
public RenderFragment Header { get; set; } = null; // only applicable to Table layouts
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public RenderFragment<TableItem> Row { get; set; } = null; // required
|
public RenderFragment<TableItem> Row { get; set; } = null; // required
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public RenderFragment Footer { get; set; } = null; // only applicable to Table layouts
|
public RenderFragment Footer { get; set; } = null; // only applicable to Table layouts
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public RenderFragment<TableItem> Detail { get; set; } = null; // only applicable to Table layouts
|
public RenderFragment<TableItem> Detail { get; set; } = null; // only applicable to Table layouts
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public IEnumerable<TableItem> Items { get; set; } // the IEnumerable data source
|
public IEnumerable<TableItem> Items { get; set; } // the IEnumerable data source
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string PageSize { get; set; } // number of items to display on a page
|
public string PageSize { get; set; } // number of items to display on a page
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Columns { get; set; } // only applicable to Grid layouts - default is zero indicating use responsive behavior
|
public string Columns { get; set; } // only applicable to Grid layouts - default is zero indicating use responsive behavior
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string CurrentPage { get; set; } // sets the initial page to display
|
public string CurrentPage { get; set; } // sets the initial page to display
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string DisplayPages { get; set; } // maximum number of page numbers to display for user selection
|
public string DisplayPages { get; set; } // maximum number of page numbers to display for user selection
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Class { get; set; } // class for the containing element - ie. <table> for Table or <div> for Grid
|
public string Class { get; set; } // class for the containing element - ie. <table> for Table or <div> for Grid
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string RowClass { get; set; } // class for row element - ie. <tr> for Table or <div> for Grid
|
public string RowClass { get; set; } // class for row element - ie. <tr> for Table or <div> for Grid
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string ColumnClass { get; set; } // class for column element - only applicable to Grid format
|
public string ColumnClass { get; set; } // class for column element - only applicable to Grid format
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public Action<int> OnPageChange { get; set; } // a method to be executed in the calling component when the page changes
|
public Action<int> OnPageChange { get; set; } // a method to be executed in the calling component when the page changes
|
||||||
|
|
||||||
private IEnumerable<TableItem> ItemList { get; set; }
|
private IEnumerable<TableItem> ItemList { get; set; }
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
Localizer = LocalizerFactory.Create(GetType().FullName);
|
Localizer = LocalizerFactory.Create(GetType().FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(Format))
|
if (string.IsNullOrEmpty(Format))
|
||||||
{
|
{
|
||||||
Format = "Table";
|
Format = "Table";
|
||||||
@ -262,8 +262,8 @@
|
|||||||
{
|
{
|
||||||
RowClass = "row";
|
RowClass = "row";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(ColumnClass))
|
if (string.IsNullOrEmpty(ColumnClass))
|
||||||
{
|
{
|
||||||
if (Format == "Table")
|
if (Format == "Table")
|
||||||
@ -274,9 +274,9 @@
|
|||||||
{
|
{
|
||||||
ColumnClass = "col";
|
ColumnClass = "col";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(PageSize))
|
if (!string.IsNullOrEmpty(PageSize))
|
||||||
{
|
{
|
||||||
_maxItems = int.Parse(PageSize);
|
_maxItems = int.Parse(PageSize);
|
||||||
}
|
}
|
||||||
@ -299,7 +299,7 @@
|
|||||||
{
|
{
|
||||||
_page = 1;
|
_page = 1;
|
||||||
}
|
}
|
||||||
if (_page < 1) _page = 1;
|
if (_page < 1) _page = 1;
|
||||||
|
|
||||||
_startPage = 0;
|
_startPage = 0;
|
||||||
_endPage = 0;
|
_endPage = 0;
|
||||||
@ -311,7 +311,6 @@
|
|||||||
{
|
{
|
||||||
_page = _pages;
|
_page = _pages;
|
||||||
}
|
}
|
||||||
ItemList = Items.Skip((_page - 1) * _maxItems).Take(_maxItems);
|
|
||||||
SetPagerSize();
|
SetPagerSize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -324,13 +323,13 @@
|
|||||||
{
|
{
|
||||||
_endPage = _pages;
|
_endPage = _pages;
|
||||||
}
|
}
|
||||||
OnPageChange?.Invoke(_page);
|
ItemList = Items.Skip((_page - 1) * _maxItems).Take(_maxItems);
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
OnPageChange?.Invoke(_page);
|
||||||
|
}
|
||||||
|
|
||||||
public void UpdateList(int page)
|
public void UpdateList(int page)
|
||||||
{
|
{
|
||||||
ItemList = Items.Skip((page - 1) * _maxItems).Take(_maxItems);
|
|
||||||
_page = page;
|
_page = page;
|
||||||
SetPagerSize();
|
SetPagerSize();
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
@namespace Oqtane.Modules.Controls
|
@namespace Oqtane.Modules.Controls
|
||||||
|
@using System.Text.Json
|
||||||
@inherits ModuleControlBase
|
@inherits ModuleControlBase
|
||||||
@inject IRoleService RoleService
|
@inject IRoleService RoleService
|
||||||
@inject IUserService UserService
|
@inject IUserService UserService
|
||||||
|
@inject IUserRoleService UserRoleService
|
||||||
@inject IStringLocalizer<PermissionGrid> Localizer
|
@inject IStringLocalizer<PermissionGrid> Localizer
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
@ -14,20 +16,19 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">@Localizer["Role"]</th>
|
<th scope="col">@Localizer["Role"]</th>
|
||||||
@foreach (PermissionString permission in _permissions)
|
@foreach (var permissionname in _permissionnames)
|
||||||
{
|
{
|
||||||
<th style="text-align: center; width: 1px;">@Localizer[permission.PermissionName]</th>
|
<th style="text-align: center; width: 1px;">@((MarkupString)DisplayPermissionName(permissionname).Replace(" ", "<br />"))</th>
|
||||||
}
|
}
|
||||||
</tr>
|
</tr>
|
||||||
@foreach (Role role in _roles)
|
@foreach (Role role in _roles)
|
||||||
{
|
{
|
||||||
<tr>
|
<tr>
|
||||||
<td>@role.Name</td>
|
<td>@role.Name</td>
|
||||||
@foreach (PermissionString permission in _permissions)
|
@foreach (var permissionname in _permissionnames)
|
||||||
{
|
{
|
||||||
var p = permission;
|
|
||||||
<td style="text-align: center;">
|
<td style="text-align: center;">
|
||||||
<TriStateCheckBox Value=@GetPermissionValue(p.Permissions, role.Name) Disabled=@GetPermissionDisabled(role.Name) OnChange="@(e => PermissionChanged(e, p.PermissionName, role.Name))" />
|
<TriStateCheckBox Value=@GetPermissionValue(permissionname, role.Name, -1) Disabled="@GetPermissionDisabled(permissionname, role.Name)" OnChange="@(e => PermissionChanged(e, permissionname, role.Name, -1))" />
|
||||||
</td>
|
</td>
|
||||||
}
|
}
|
||||||
</tr>
|
</tr>
|
||||||
@ -49,23 +50,21 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">@Localizer["User"]</th>
|
<th scope="col">@Localizer["User"]</th>
|
||||||
@foreach (PermissionString permission in _permissions)
|
@foreach (var permissionname in _permissionnames)
|
||||||
{
|
{
|
||||||
<th style="text-align: center; width: 1px;">@Localizer[permission.PermissionName]</th>
|
<th style="text-align: center; width: 1px;">@((MarkupString)DisplayPermissionName(permissionname).Replace(" ", "<br />"))</th>
|
||||||
}
|
}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@foreach (User user in _users)
|
@foreach (User user in _users)
|
||||||
{
|
{
|
||||||
string userid = "[" + user.UserId.ToString() + "]";
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>@user.DisplayName</td>
|
<td>@user.DisplayName</td>
|
||||||
@foreach (PermissionString permission in _permissions)
|
@foreach (var permissionname in _permissionnames)
|
||||||
{
|
{
|
||||||
var p = permission;
|
|
||||||
<td style="text-align: center; width: 1px;">
|
<td style="text-align: center; width: 1px;">
|
||||||
<TriStateCheckBox Value=@GetPermissionValue(p.Permissions, userid) Disabled=false OnChange="@(e => PermissionChanged(e, p.PermissionName, userid))" />
|
<TriStateCheckBox Value=@GetPermissionValue(permissionname, "", user.UserId) Disabled="@GetPermissionDisabled(permissionname, "")" OnChange="@(e => PermissionChanged(e, permissionname, "", user.UserId))" />
|
||||||
</td>
|
</td>
|
||||||
}
|
}
|
||||||
</tr>
|
</tr>
|
||||||
@ -77,34 +76,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col-11">
|
||||||
<table class="table table-borderless">
|
<AutoComplete OnSearch="GetUsers" Placeholder="@Localizer["Username.Enter"]" @ref="_user" />
|
||||||
<tbody>
|
</div>
|
||||||
<tr>
|
<div class="col-1">
|
||||||
<td class="input-group">
|
<button type="button" class="btn btn-primary" @onclick="AddUser">@SharedLocalizer["Add"]</button>
|
||||||
<input type="text" name="Username" class="form-control" placeholder="@Localizer["Username.Enter"]" @bind="@_username" />
|
|
||||||
<button type="button" class="btn btn-primary" @onclick="AddUser">@SharedLocalizer["Add"]</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<br />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<ModuleMessage Type="MessageType.Error" Message="@_message" />
|
<ModuleMessage Type="MessageType.Warning" Message="@_message" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private string _permissionnames = string.Empty;
|
private List<string> _permissionnames;
|
||||||
|
private List<Permission> _permissions;
|
||||||
private List<Role> _roles;
|
private List<Role> _roles;
|
||||||
private List<PermissionString> _permissions;
|
|
||||||
private List<User> _users = new List<User>();
|
private List<User> _users = new List<User>();
|
||||||
private string _username = string.Empty;
|
private AutoComplete _user;
|
||||||
private string _message = string.Empty;
|
private string _message = string.Empty;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
@ -114,17 +106,16 @@
|
|||||||
public string PermissionNames { get; set; }
|
public string PermissionNames { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Permissions { get; set; }
|
public string Permissions { get; set; } // deprecated - use PermissionList instead
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public List<Permission> PermissionList { get; set; }
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(PermissionNames))
|
if (!string.IsNullOrEmpty(Permissions))
|
||||||
{
|
{
|
||||||
_permissionnames = Shared.PermissionNames.View + "," + Shared.PermissionNames.Edit;
|
PermissionList = JsonSerializer.Deserialize<List<Permission>>(Permissions);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_permissionnames = PermissionNames;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_roles = await RoleService.GetRolesAsync(ModuleState.SiteId, true);
|
_roles = await RoleService.GetRolesAsync(ModuleState.SiteId, true);
|
||||||
@ -133,140 +124,212 @@
|
|||||||
_roles.RemoveAll(item => item.Name == RoleNames.Host);
|
_roles.RemoveAll(item => item.Name == RoleNames.Host);
|
||||||
}
|
}
|
||||||
|
|
||||||
_permissions = new List<PermissionString>();
|
// get permission names
|
||||||
|
if (string.IsNullOrEmpty(PermissionNames))
|
||||||
foreach (string permissionname in _permissionnames.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
|
||||||
{
|
{
|
||||||
// initialize with admin role
|
_permissionnames = new List<string>();
|
||||||
_permissions.Add(new PermissionString { PermissionName = permissionname, Permissions = RoleNames.Admin });
|
_permissionnames.Add(Shared.PermissionNames.View);
|
||||||
|
_permissionnames.Add(Shared.PermissionNames.Edit);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_permissionnames = PermissionNames.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Permissions))
|
// initialize permissions
|
||||||
|
_permissions = new List<Permission>();
|
||||||
|
if (PermissionList != null && PermissionList.Any())
|
||||||
{
|
{
|
||||||
// populate permissions
|
foreach (var permission in PermissionList)
|
||||||
foreach (PermissionString permissionstring in UserSecurity.GetPermissionStrings(Permissions))
|
|
||||||
{
|
{
|
||||||
if (_permissions.Find(item => item.PermissionName == permissionstring.PermissionName) != null)
|
_permissions.Add(permission);
|
||||||
|
if (permission.UserId != null)
|
||||||
{
|
{
|
||||||
_permissions[_permissions.FindIndex(item => item.PermissionName == permissionstring.PermissionName)].Permissions = permissionstring.Permissions;
|
if (!_users.Any(item => item.UserId == permission.UserId.Value))
|
||||||
}
|
|
||||||
|
|
||||||
if (permissionstring.Permissions.Contains("["))
|
|
||||||
{
|
|
||||||
foreach (string user in permissionstring.Permissions.Split(new char[] { '[' }, StringSplitOptions.RemoveEmptyEntries))
|
|
||||||
{
|
{
|
||||||
if (user.Contains("]"))
|
_users.Add(await UserService.GetUserAsync(permission.UserId.Value, ModuleState.SiteId));
|
||||||
{
|
|
||||||
var userid = int.Parse(user.Substring(0, user.IndexOf("]")));
|
|
||||||
if (_users.Where(item => item.UserId == userid).FirstOrDefault() == null)
|
|
||||||
{
|
|
||||||
_users.Add(await UserService.GetUserAsync(userid, ModuleState.SiteId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (string permissionname in _permissionnames)
|
||||||
|
{
|
||||||
|
// permission names can be in the form of "EntityName:PermissionName:Roles"
|
||||||
|
if (permissionname.Contains(":"))
|
||||||
|
{
|
||||||
|
var segments = permissionname.Split(':');
|
||||||
|
if (segments.Length == 3)
|
||||||
|
{
|
||||||
|
foreach (var role in segments[2].Split(';'))
|
||||||
|
{
|
||||||
|
_permissions.Add(new Permission(ModuleState.SiteId, segments[0], segments[1], role, null, true));
|
||||||
|
}
|
||||||
|
// ensure admin access
|
||||||
|
if (!_permissions.Any(item => item.EntityName == segments[0] && item.PermissionName == segments[1] && item.RoleName == RoleNames.Admin))
|
||||||
|
{
|
||||||
|
_permissions.Add(new Permission(ModuleState.SiteId, segments[0], segments[1], RoleNames.Admin, null, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_permissions.Add(new Permission(ModuleState.SiteId, EntityName, permissionname, RoleNames.Admin, null, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool? GetPermissionValue(string permissions, string securityKey)
|
private string GetPermissionName(string permissionName)
|
||||||
{
|
{
|
||||||
if ((";" + permissions + ";").Contains(";" + "!" + securityKey + ";"))
|
return (permissionName.Contains(":")) ? permissionName.Split(':')[1] : permissionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetEntityName(string permissionName)
|
||||||
|
{
|
||||||
|
return (permissionName.Contains(":")) ? permissionName.Split(':')[0] : EntityName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string DisplayPermissionName(string permissionName)
|
||||||
|
{
|
||||||
|
var name = Localizer[GetPermissionName(permissionName)].ToString();
|
||||||
|
name += " " + Localizer[GetEntityName(permissionName)].ToString();
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool? GetPermissionValue(string permissionName, string roleName, int userId)
|
||||||
|
{
|
||||||
|
bool? isauthorized = null;
|
||||||
|
if (roleName != "")
|
||||||
{
|
{
|
||||||
return false; // deny permission
|
var permission = _permissions.FirstOrDefault(item => item.EntityName == GetEntityName(permissionName) && item.PermissionName == GetPermissionName(permissionName) && item.RoleName == roleName);
|
||||||
|
if (permission != null)
|
||||||
|
{
|
||||||
|
isauthorized = permission.IsAuthorized;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((";" + permissions + ";").Contains(";" + securityKey + ";"))
|
var permission = _permissions.FirstOrDefault(item => item.EntityName == GetEntityName(permissionName) && item.PermissionName == GetPermissionName(permissionName) && item.UserId == userId);
|
||||||
|
if (permission != null)
|
||||||
{
|
{
|
||||||
return true; // grant permission
|
isauthorized = permission.IsAuthorized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isauthorized;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool GetPermissionDisabled(string permissionName, string roleName)
|
||||||
|
{
|
||||||
|
if (roleName == RoleNames.Admin && !UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (GetEntityName(permissionName) != EntityName && !UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return null; // not specified
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool GetPermissionDisabled(string roleName)
|
private void PermissionChanged(bool? value, string permissionName, string roleName, int userId)
|
||||||
=> (roleName == RoleNames.Admin && !UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) ? true : false;
|
{
|
||||||
|
if (roleName != "")
|
||||||
|
{
|
||||||
|
var permission = _permissions.FirstOrDefault(item => item.EntityName == GetEntityName(permissionName) && item.PermissionName == GetPermissionName(permissionName) && item.RoleName == roleName);
|
||||||
|
if (permission != null)
|
||||||
|
{
|
||||||
|
_permissions.Remove(permission);
|
||||||
|
}
|
||||||
|
if (value != null)
|
||||||
|
{
|
||||||
|
_permissions.Add(new Permission(ModuleState.SiteId, GetEntityName(permissionName), GetPermissionName(permissionName), roleName, null, value.Value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var permission = _permissions.FirstOrDefault(item => item.EntityName == GetEntityName(permissionName) && item.PermissionName == GetPermissionName(permissionName) && item.UserId == userId);
|
||||||
|
if (permission != null)
|
||||||
|
{
|
||||||
|
_permissions.Remove(permission);
|
||||||
|
}
|
||||||
|
if (value != null)
|
||||||
|
{
|
||||||
|
_permissions.Add(new Permission(ModuleState.SiteId, GetEntityName(permissionName), GetPermissionName(permissionName), null, userId, value.Value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Dictionary<string, string>> GetUsers(string filter)
|
||||||
|
{
|
||||||
|
var users = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId, RoleNames.Registered);
|
||||||
|
return users.Where(item => item.User.DisplayName.Contains(filter, StringComparison.OrdinalIgnoreCase))
|
||||||
|
.ToDictionary(item => item.UserId.ToString(), item => item.User.DisplayName);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task AddUser()
|
private async Task AddUser()
|
||||||
{
|
{
|
||||||
if (_users.Where(item => item.Username == _username).FirstOrDefault() == null)
|
if (!string.IsNullOrEmpty(_user.Key))
|
||||||
{
|
{
|
||||||
try
|
var user = await UserService.GetUserAsync(int.Parse(_user.Key), ModuleState.SiteId);
|
||||||
|
if (user != null && !_users.Any(item => item.UserId == user.UserId))
|
||||||
{
|
{
|
||||||
var user = await UserService.GetUserAsync(_username, ModuleState.SiteId);
|
_users.Add(user);
|
||||||
if (user != null)
|
|
||||||
{
|
|
||||||
_users.Add(user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
_message = Localizer["Message.Username.DontExist"];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
_username = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PermissionChanged(bool? value, string permissionName, string securityId)
|
|
||||||
{
|
|
||||||
var selected = value;
|
|
||||||
var permission = _permissions.Find(item => item.PermissionName == permissionName);
|
|
||||||
if (permission != null)
|
|
||||||
{
|
{
|
||||||
var ids = permission.Permissions.Split(';').ToList();
|
_message = Localizer["Message.Username.DontExist"];
|
||||||
|
|
||||||
ids.Remove(securityId); // remove grant permission
|
|
||||||
ids.Remove("!" + securityId); // remove deny permission
|
|
||||||
|
|
||||||
switch (selected)
|
|
||||||
{
|
|
||||||
case true:
|
|
||||||
ids.Add(securityId); // add grant permission
|
|
||||||
break;
|
|
||||||
case false:
|
|
||||||
ids.Add("!" + securityId); // add deny permission
|
|
||||||
break;
|
|
||||||
case null:
|
|
||||||
break; // permission not specified
|
|
||||||
}
|
|
||||||
|
|
||||||
_permissions[_permissions.FindIndex(item => item.PermissionName == permissionName)].Permissions = string.Join(";", ids.ToArray());
|
|
||||||
}
|
}
|
||||||
|
_user.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetPermissions()
|
public string GetPermissions()
|
||||||
{
|
{
|
||||||
ValidatePermissions();
|
ValidatePermissions();
|
||||||
return UserSecurity.SetPermissionStrings(_permissions);
|
return JsonSerializer.Serialize(_permissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Permission> GetPermissionList()
|
||||||
|
{
|
||||||
|
ValidatePermissions();
|
||||||
|
return _permissions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ValidatePermissions()
|
private void ValidatePermissions()
|
||||||
{
|
{
|
||||||
PermissionString permission;
|
// remove deny all users, unauthenticated, and registered users
|
||||||
for (int i = 0; i < _permissions.Count; i++)
|
var permissions = _permissions.Where(item => !item.IsAuthorized &&
|
||||||
|
(item.RoleName == RoleNames.Everyone || item.RoleName == RoleNames.Unauthenticated || item.RoleName == RoleNames.Registered)).ToList();
|
||||||
|
foreach (var permission in permissions)
|
||||||
{
|
{
|
||||||
permission = _permissions[i];
|
_permissions.Remove(permission);
|
||||||
List<string> ids = permission.Permissions.Split(';', StringSplitOptions.RemoveEmptyEntries).ToList();
|
}
|
||||||
ids.Remove("!" + RoleNames.Everyone); // remove deny all users
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
ids.Remove("!" + RoleNames.Unauthenticated); // remove deny unauthenticated
|
{
|
||||||
ids.Remove("!" + RoleNames.Registered); // remove deny registered users
|
// remove deny administrators and host users
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
permissions = _permissions.Where(item => !item.IsAuthorized &&
|
||||||
|
(item.RoleName == RoleNames.Admin || item.RoleName == RoleNames.Host)).ToList();
|
||||||
|
foreach (var permission in permissions)
|
||||||
{
|
{
|
||||||
ids.Remove("!" + RoleNames.Admin); // remove deny administrators
|
_permissions.Remove(permission);
|
||||||
ids.Remove("!" + RoleNames.Host); // remove deny host users
|
}
|
||||||
if (!ids.Contains(RoleNames.Host) && !ids.Contains(RoleNames.Admin))
|
foreach (var permissionname in _permissionnames)
|
||||||
|
{
|
||||||
|
// add administrators role if neither host or administrator is assigned
|
||||||
|
if (!_permissions.Any(item => item.EntityName == GetEntityName(permissionname) && item.PermissionName == GetPermissionName(permissionname) &&
|
||||||
|
(item.RoleName == RoleNames.Admin || item.RoleName == RoleNames.Host)))
|
||||||
{
|
{
|
||||||
// add administrators role if host user role is not assigned
|
_permissions.Add(new Permission(ModuleState.SiteId, GetEntityName(permissionname), GetPermissionName(permissionname), RoleNames.Admin, null, true));
|
||||||
ids.Add(RoleNames.Admin);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
permission.Permissions = string.Join(";", ids.ToArray());
|
}
|
||||||
_permissions[i] = permission;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,13 @@
|
|||||||
|
|
||||||
@if (Name == Parent.ActiveTab)
|
@if (Name == Parent.ActiveTab)
|
||||||
{
|
{
|
||||||
<div id="@Name" class="tab-pane fade show active" role="tabpanel">
|
<div id="@(Parent.Id + Name)" class="tab-pane fade show active" role="tabpanel">
|
||||||
@ChildContent
|
@ChildContent
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<div id="@Name" class="tab-pane fade" role="tabpanel">
|
<div id="@(Parent.Id + Name)" class="tab-pane fade" role="tabpanel">
|
||||||
@ChildContent
|
@ChildContent
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -10,13 +10,13 @@
|
|||||||
<li class="nav-item" @key="tabPanel.Name">
|
<li class="nav-item" @key="tabPanel.Name">
|
||||||
@if (tabPanel.Name == ActiveTab)
|
@if (tabPanel.Name == ActiveTab)
|
||||||
{
|
{
|
||||||
<a class="nav-link active" data-bs-toggle="tab" href="#@tabPanel.Name" role="tab" @onclick:preventDefault="true">
|
<a class="nav-link active" data-bs-toggle="tab" href="#@(Id + tabPanel.Name)" role="tab" @onclick:preventDefault="true">
|
||||||
@tabPanel.DisplayHeading()
|
@tabPanel.DisplayHeading()
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<a class="nav-link" data-bs-toggle="tab" href="#@tabPanel.Name" role="tab" @onclick:preventDefault="true">
|
<a class="nav-link" data-bs-toggle="tab" href="#@(Id + tabPanel.Name)" role="tab" @onclick:preventDefault="true">
|
||||||
@tabPanel.DisplayHeading()
|
@tabPanel.DisplayHeading()
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
@ -32,18 +32,31 @@
|
|||||||
</CascadingValue>
|
</CascadingValue>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<TabPanel> _tabPanels;
|
private List<TabPanel> _tabPanels;
|
||||||
|
private string _tabpanelid = string.Empty;
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public RenderFragment ChildContent { get; set; } // contains the TabPanels
|
public RenderFragment ChildContent { get; set; } // contains the TabPanels
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string ActiveTab { get; set; } // optional - defaults to first TabPanel if not specified. Can also be set using a "tab=" querystring parameter.
|
public string ActiveTab { get; set; } // optional - defaults to first TabPanel if not specified. Can also be set using a "tab=" querystring parameter.
|
||||||
|
|
||||||
[Parameter]
|
[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.
|
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 OnParametersSet()
|
[Parameter]
|
||||||
|
public string Id { get; set; } // optional - used to uniquely identify an instance of a tab strip component (will be set automatically if no value provided)
|
||||||
|
|
||||||
|
protected override void OnInitialized()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(Id))
|
||||||
|
{
|
||||||
|
// create unique id for component
|
||||||
|
Id = "TabStrip_" + Guid.NewGuid().ToString("N") + "_" ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
if (PageState.QueryString.ContainsKey("tab"))
|
if (PageState.QueryString.ContainsKey("tab"))
|
||||||
{
|
{
|
||||||
@ -80,10 +93,10 @@
|
|||||||
authorized = true;
|
authorized = true;
|
||||||
break;
|
break;
|
||||||
case SecurityAccessLevel.View:
|
case SecurityAccessLevel.View:
|
||||||
authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, ModuleState.Permissions);
|
authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, ModuleState.PermissionList);
|
||||||
break;
|
break;
|
||||||
case SecurityAccessLevel.Edit:
|
case SecurityAccessLevel.Edit:
|
||||||
authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, ModuleState.Permissions);
|
authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, ModuleState.PermissionList);
|
||||||
break;
|
break;
|
||||||
case SecurityAccessLevel.Admin:
|
case SecurityAccessLevel.Admin:
|
||||||
authorized = UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin);
|
authorized = UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin);
|
||||||
|
@ -72,15 +72,24 @@ namespace Oqtane.Modules
|
|||||||
{
|
{
|
||||||
if (Resources != null && Resources.Exists(item => item.ResourceType == ResourceType.Script))
|
if (Resources != null && Resources.Exists(item => item.ResourceType == ResourceType.Script))
|
||||||
{
|
{
|
||||||
|
var interop = new Interop(JSRuntime);
|
||||||
var scripts = new List<object>();
|
var scripts = new List<object>();
|
||||||
|
var inline = 0;
|
||||||
foreach (Resource resource in Resources.Where(item => item.ResourceType == ResourceType.Script))
|
foreach (Resource resource in Resources.Where(item => item.ResourceType == ResourceType.Script))
|
||||||
{
|
{
|
||||||
var url = (resource.Url.Contains("://")) ? resource.Url : PageState.Alias.BaseUrl + resource.Url;
|
if (!string.IsNullOrEmpty(resource.Url))
|
||||||
scripts.Add(new { href = url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", es6module = resource.ES6Module });
|
{
|
||||||
|
var url = (resource.Url.Contains("://")) ? resource.Url : PageState.Alias.BaseUrl + resource.Url;
|
||||||
|
scripts.Add(new { href = url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", es6module = resource.ES6Module });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inline += 1;
|
||||||
|
await interop.IncludeScript(GetType().Namespace.ToLower() + inline.ToString(), "", "", "", resource.Content, resource.Location.ToString().ToLower());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (scripts.Any())
|
if (scripts.Any())
|
||||||
{
|
{
|
||||||
var interop = new Interop(JSRuntime);
|
|
||||||
await interop.IncludeScripts(scripts.ToArray());
|
await interop.IncludeScripts(scripts.ToArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -181,12 +190,7 @@ namespace Oqtane.Modules
|
|||||||
|
|
||||||
public string AddUrlParameters(params object[] parameters)
|
public string AddUrlParameters(params object[] parameters)
|
||||||
{
|
{
|
||||||
var url = "";
|
return Utilities.AddUrlParameters(parameters);
|
||||||
for (var i = 0; i < parameters.Length; i++)
|
|
||||||
{
|
|
||||||
url += "/" + parameters[i].ToString();
|
|
||||||
}
|
|
||||||
return url;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// template is in the form of a standard route template ie. "/{id}/{name}" and produces dictionary of key/value pairs
|
// template is in the form of a standard route template ie. "/{id}/{name}" and produces dictionary of key/value pairs
|
||||||
@ -306,15 +310,10 @@ namespace Oqtane.Modules
|
|||||||
{
|
{
|
||||||
int pageId = ModuleState.PageId;
|
int pageId = ModuleState.PageId;
|
||||||
int moduleId = ModuleState.ModuleId;
|
int moduleId = ModuleState.ModuleId;
|
||||||
int? userId = null;
|
|
||||||
if (PageState.User != null)
|
|
||||||
{
|
|
||||||
userId = PageState.User.UserId;
|
|
||||||
}
|
|
||||||
string category = GetType().AssemblyQualifiedName;
|
string category = GetType().AssemblyQualifiedName;
|
||||||
string feature = Utilities.GetTypeNameLastSegment(category, 1);
|
string feature = Utilities.GetTypeNameLastSegment(category, 1);
|
||||||
|
|
||||||
await LoggingService.Log(alias, pageId, moduleId, userId, category, feature, function, level, exception, message, args);
|
await LoggingService.Log(alias, pageId, moduleId, PageState.User?.UserId, category, feature, function, level, exception, message, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Logger
|
public class Logger
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<RazorLangVersion>3.0</RazorLangVersion>
|
<RazorLangVersion>3.0</RazorLangVersion>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
<Version>3.2.1</Version>
|
<Version>3.4.3</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -13,7 +13,7 @@
|
|||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.2.1</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.3</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<RootNamespace>Oqtane</RootNamespace>
|
<RootNamespace>Oqtane</RootNamespace>
|
||||||
|
@ -16,6 +16,7 @@ using Microsoft.JSInterop;
|
|||||||
using Oqtane.Documentation;
|
using Oqtane.Documentation;
|
||||||
using Oqtane.Modules;
|
using Oqtane.Modules;
|
||||||
using Oqtane.Services;
|
using Oqtane.Services;
|
||||||
|
using Oqtane.Shared;
|
||||||
using Oqtane.UI;
|
using Oqtane.UI;
|
||||||
|
|
||||||
namespace Oqtane.Client
|
namespace Oqtane.Client
|
||||||
@ -56,7 +57,11 @@ namespace Oqtane.Client
|
|||||||
RegisterClientStartups(assembly, builder.Services);
|
RegisterClientStartups(assembly, builder.Services);
|
||||||
}
|
}
|
||||||
|
|
||||||
await builder.Build().RunAsync();
|
var host = builder.Build();
|
||||||
|
|
||||||
|
await SetCultureFromLocalizationCookie(host.Services);
|
||||||
|
|
||||||
|
await host.RunAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task LoadClientAssemblies(HttpClient http, IServiceProvider serviceProvider)
|
private static async Task LoadClientAssemblies(HttpClient http, IServiceProvider serviceProvider)
|
||||||
@ -193,23 +198,37 @@ namespace Oqtane.Client
|
|||||||
private static void RegisterModuleServices(Assembly assembly, IServiceCollection services)
|
private static void RegisterModuleServices(Assembly assembly, IServiceCollection services)
|
||||||
{
|
{
|
||||||
// dynamically register module scoped services
|
// dynamically register module scoped services
|
||||||
var implementationTypes = assembly.GetInterfaces<IService>();
|
try
|
||||||
foreach (var implementationType in implementationTypes)
|
|
||||||
{
|
{
|
||||||
if (implementationType.AssemblyQualifiedName != null)
|
var implementationTypes = assembly.GetInterfaces<IService>();
|
||||||
|
foreach (var implementationType in implementationTypes)
|
||||||
{
|
{
|
||||||
var serviceType = Type.GetType(implementationType.AssemblyQualifiedName.Replace(implementationType.Name, $"I{implementationType.Name}"));
|
if (implementationType.AssemblyQualifiedName != null)
|
||||||
services.AddScoped(serviceType ?? implementationType, implementationType);
|
{
|
||||||
|
var serviceType = Type.GetType(implementationType.AssemblyQualifiedName.Replace(implementationType.Name, $"I{implementationType.Name}"));
|
||||||
|
services.AddScoped(serviceType ?? implementationType, implementationType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// could not interrogate assembly - likely missing dependencies
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RegisterClientStartups(Assembly assembly, IServiceCollection services)
|
private static void RegisterClientStartups(Assembly assembly, IServiceCollection services)
|
||||||
{
|
{
|
||||||
var startUps = assembly.GetInstances<IClientStartup>();
|
try
|
||||||
foreach (var startup in startUps)
|
|
||||||
{
|
{
|
||||||
startup.ConfigureServices(services);
|
var startUps = assembly.GetInstances<IClientStartup>();
|
||||||
|
foreach (var startup in startUps)
|
||||||
|
{
|
||||||
|
startup.ConfigureServices(services);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// could not interrogate assembly - likely missing dependencies
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +239,7 @@ namespace Oqtane.Client
|
|||||||
var localizationCookie = await interop.GetCookie(CookieRequestCultureProvider.DefaultCookieName);
|
var localizationCookie = await interop.GetCookie(CookieRequestCultureProvider.DefaultCookieName);
|
||||||
var culture = CookieRequestCultureProvider.ParseCookieValue(localizationCookie)?.UICultures?[0].Value;
|
var culture = CookieRequestCultureProvider.ParseCookieValue(localizationCookie)?.UICultures?[0].Value;
|
||||||
var localizationService = serviceProvider.GetRequiredService<ILocalizationService>();
|
var localizationService = serviceProvider.GetRequiredService<ILocalizationService>();
|
||||||
var cultures = await localizationService.GetCulturesAsync();
|
var cultures = await localizationService.GetCulturesAsync(false);
|
||||||
|
|
||||||
if (culture == null || !cultures.Any(c => c.Name.Equals(culture, StringComparison.OrdinalIgnoreCase)))
|
if (culture == null || !cultures.Any(c => c.Name.Equals(culture, StringComparison.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
|
@ -136,7 +136,7 @@
|
|||||||
<value>Please Enter All Required Fields. Ensure Passwords Match And Email Address Provided Is Valid.</value>
|
<value>Please Enter All Required Fields. Ensure Passwords Match And Email Address Provided Is Valid.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.Password.Invalid" xml:space="preserve">
|
<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>
|
<value>The Password Provided Does Not Meet The Complexity Policy. Passwords Must Be At Least 6 Characters In Length And Contain Uppercase, Lowercase, Numeric, And Punctuation Characters.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Register" xml:space="preserve">
|
<data name="Register" xml:space="preserve">
|
||||||
<value>Please Register Me For Major Product Updates And Security Bulletins</value>
|
<value>Please Register Me For Major Product Updates And Security Bulletins</value>
|
||||||
@ -172,7 +172,7 @@
|
|||||||
<value>Enter a complete connection string including all parameters and delimiters</value>
|
<value>Enter a complete connection string including all parameters and delimiters</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ConnectionString.Text" xml:space="preserve">
|
<data name="ConnectionString.Text" xml:space="preserve">
|
||||||
<value>String:</value>
|
<value>Settings:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="EnterConnectionParameters" xml:space="preserve">
|
<data name="EnterConnectionParameters" xml:space="preserve">
|
||||||
<value>Enter Connection Parameters</value>
|
<value>Enter Connection Parameters</value>
|
||||||
|
126
Oqtane.Client/Resources/Modules/Admin/Api/Edit.resx
Normal file
126
Oqtane.Client/Resources/Modules/Admin/Api/Edit.resx
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
<?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="EntityName.HelpText" xml:space="preserve">
|
||||||
|
<value>The Name Of The Entity</value>
|
||||||
|
</data>
|
||||||
|
<data name="EntityName.Text" xml:space="preserve">
|
||||||
|
<value>Entity:</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
126
Oqtane.Client/Resources/Modules/Admin/Api/Index.resx
Normal file
126
Oqtane.Client/Resources/Modules/Admin/Api/Index.resx
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
<?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="Entity" xml:space="preserve">
|
||||||
|
<value>Entity</value>
|
||||||
|
</data>
|
||||||
|
<data name="Permissions" xml:space="preserve">
|
||||||
|
<value>Permissions</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
@ -193,6 +193,6 @@
|
|||||||
<value>Execute Once</value>
|
<value>Execute Once</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.NoJobs" xml:space="preserve">
|
<data name="Message.NoJobs" xml:space="preserve">
|
||||||
<value>Please Note That After An Initial Installation You Must &lt;a href={0}&gt;Restart&lt;/a&gt; The Application In Order To Activate The Default Scheduled Jobs.</value>
|
<value>Please Note That After An Initial Installation You Must <a href={0}>Restart</a> The Application In Order To Activate The Default Scheduled Jobs.</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
@ -117,9 +117,6 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<data name="The Only Supported Culture That Has Been Defined Is English" xml:space="preserve">
|
|
||||||
<value>The Only Supported Culture That Has Been Defined Is English</value>
|
|
||||||
</data>
|
|
||||||
<data name="Error.Language.Add" xml:space="preserve">
|
<data name="Error.Language.Add" xml:space="preserve">
|
||||||
<value>Error Adding Language</value>
|
<value>Error Adding Language</value>
|
||||||
</data>
|
</data>
|
||||||
@ -135,29 +132,11 @@
|
|||||||
<data name="IsDefault.Text" xml:space="preserve">
|
<data name="IsDefault.Text" xml:space="preserve">
|
||||||
<value>Default?</value>
|
<value>Default?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AllLanguages" xml:space="preserve">
|
|
||||||
<value>All The Installed Languages Have Been Added.</value>
|
|
||||||
</data>
|
|
||||||
<data name="Error.Language.Download" xml:space="preserve">
|
|
||||||
<value>Error Downloading Translation</value>
|
|
||||||
</data>
|
|
||||||
<data name="OnlyEnglish" xml:space="preserve">
|
|
||||||
<value>The Only Installed Language Is English</value>
|
|
||||||
</data>
|
|
||||||
<data name="Success.Language.Download" xml:space="preserve">
|
<data name="Success.Language.Download" xml:space="preserve">
|
||||||
<value>Translation Downloaded Successfully. Click Install To Complete Installation.</value>
|
<value>Translation Package Saved Successfully. You Must <a href={0}>Restart</a> To Complete The Installation.</value>
|
||||||
</data>
|
|
||||||
<data name="Success.Language.Install" xml:space="preserve">
|
|
||||||
<value>Translations Installed Successfully. You Must <a href={0}>Restart</a> Your Application To Apply These Changes.</value>
|
|
||||||
</data>
|
|
||||||
<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>Translations</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="LanguageUpload.HelpText" xml:space="preserve">
|
<data name="LanguageUpload.HelpText" xml:space="preserve">
|
||||||
<value>Upload one or more translation packages. Once they are uploaded click Install to complete the installation.</value>
|
<value>Upload one or more translation packages.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LanguageUpload.Text" xml:space="preserve">
|
<data name="LanguageUpload.Text" xml:space="preserve">
|
||||||
<value>Translation</value>
|
<value>Translation</value>
|
||||||
|
@ -132,12 +132,12 @@
|
|||||||
<data name="DeleteLanguage.Header" xml:space="preserve">
|
<data name="DeleteLanguage.Header" xml:space="preserve">
|
||||||
<value>Delete Language</value>
|
<value>Delete Language</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Success.Language.Download" xml:space="preserve">
|
||||||
|
<value>Translation Package Saved Successfully. You Must <a href={0}>Restart</a> Your Application To Complete The Installation.</value>
|
||||||
|
</data>
|
||||||
<data name="Error.Language.Download" xml:space="preserve">
|
<data name="Error.Language.Download" xml:space="preserve">
|
||||||
<value>Error Downloading Translation</value>
|
<value>Error Downloading Translation</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Success.Language.Install" xml:space="preserve">
|
|
||||||
<value>Translation Installed Successfully. You Must <a href={0}>Restart</a> Your Application To Apply These Changes.</value>
|
|
||||||
</data>
|
|
||||||
<data name="Default" xml:space="preserve">
|
<data name="Default" xml:space="preserve">
|
||||||
<value>Default</value>
|
<value>Default</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -123,17 +123,14 @@
|
|||||||
<data name="Error.Package.Load" xml:space="preserve">
|
<data name="Error.Package.Load" xml:space="preserve">
|
||||||
<value>Error Loading Packages</value>
|
<value>Error Loading Packages</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Success.Module.Install" xml:space="preserve">
|
|
||||||
<value>Module Installed Successfully. You Must <a href={0}>Restart</a> Your Application To Apply These Changes.</value>
|
|
||||||
</data>
|
|
||||||
<data name="Success.Module.Download" xml:space="preserve">
|
<data name="Success.Module.Download" xml:space="preserve">
|
||||||
<value>Module Downloaded Successfully. Click Install To Complete Installation.</value>
|
<value>Module Package Saved Successfully. You Must <a href={0}>Restart</a> Your Application To Complete The Installation.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Error.Module.Download" xml:space="preserve">
|
<data name="Error.Module.Download" xml:space="preserve">
|
||||||
<value>Error Downloading Module</value>
|
<value>Error Downloading Module</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Module.HelpText" xml:space="preserve">
|
<data name="Module.HelpText" xml:space="preserve">
|
||||||
<value>Upload one or more module packages. Once they are uploaded click Install to complete the installation.</value>
|
<value>Upload one or more module packages.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Search.NoResults" xml:space="preserve">
|
<data name="Search.NoResults" xml:space="preserve">
|
||||||
<value>No Modules Match The Criteria Provided Or Package Service Is Disabled</value>
|
<value>No Modules Match The Criteria Provided Or Package Service Is Disabled</value>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
@ -204,16 +204,19 @@
|
|||||||
<data name="Error.Translation.Download" xml:space="preserve">
|
<data name="Error.Translation.Download" xml:space="preserve">
|
||||||
<value>Error Downloading Translation</value>
|
<value>Error Downloading Translation</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Search.PackageNameMissing" xml:space="preserve">
|
||||||
|
<value>A Package Name Was Not Provided For The Module</value>
|
||||||
|
</data>
|
||||||
<data name="Search.NoResults" xml:space="preserve">
|
<data name="Search.NoResults" xml:space="preserve">
|
||||||
<value>No Translations Exist For This Module Or Package Service Is Disabled</value>
|
<value>No Translations Exist For This Module Or Package Service Is Disabled</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Success.Translation.Download" xml:space="preserve">
|
<data name="Success.Translation.Download" xml:space="preserve">
|
||||||
<value>Translation Downloaded Successfully. Click Install To Complete Installation.</value>
|
<value>Translation Package Saved Successfully. You Must <a href={0}>Restart</a> Your Application To Complete The Installation.</value>
|
||||||
</data>
|
|
||||||
<data name="Success.Translation.Install" xml:space="preserve">
|
|
||||||
<value>Translation Installed Successfully. You Must <a href={0}>Restart</a> Your Application To Apply These Changes.</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="Translations.Heading" xml:space="preserve">
|
<data name="Translations.Heading" xml:space="preserve">
|
||||||
<value>Translations</value>
|
<value>Translations</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Message.DuplicateName" xml:space="preserve">
|
||||||
|
<value>A Module With The Name Specified Already Exists</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
@ -166,7 +166,7 @@
|
|||||||
<value>Email:</value>
|
<value>Email:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Password.HelpText" xml:space="preserve">
|
<data name="Password.HelpText" xml:space="preserve">
|
||||||
<value>Please choose a sufficiently secure password and enter it here</value>
|
<value>Please enter a sufficiently secure password which meets the password complexity requirements</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Password.Text" xml:space="preserve">
|
<data name="Password.Text" xml:space="preserve">
|
||||||
<value>Password:</value>
|
<value>Password:</value>
|
||||||
@ -177,4 +177,19 @@
|
|||||||
<data name="Username.Text" xml:space="preserve">
|
<data name="Username.Text" xml:space="preserve">
|
||||||
<value>Username:</value>
|
<value>Username:</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Password.ValidationCriteria" xml:space="preserve">
|
||||||
|
<value>Passwords Must Have A Minimum Length Of {0} Characters, Including At Least {1} Unique Character(s), {2}{3}{4}{5} To Satisfy Password Compexity Requirements For This Site.</value>
|
||||||
|
</data>
|
||||||
|
<data name="Password.DigitRequirement" xml:space="preserve">
|
||||||
|
<value>At Least One Digit</value>
|
||||||
|
</data>
|
||||||
|
<data name="Password.LowercaseRequirement" xml:space="preserve">
|
||||||
|
<value>At Least One Lowercase Letter</value>
|
||||||
|
</data>
|
||||||
|
<data name="Password.PunctuationRequirement" xml:space="preserve">
|
||||||
|
<value>At Least One Punctuation Mark</value>
|
||||||
|
</data>
|
||||||
|
<data name="Password.UppercaseRequirement" xml:space="preserve">
|
||||||
|
<value>At Least One Uppercase Letter</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
@ -121,7 +121,7 @@
|
|||||||
<value>User: </value>
|
<value>User: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="User.Select" xml:space="preserve">
|
<data name="User.Select" xml:space="preserve">
|
||||||
<value>Select User</value>
|
<value>Enter User's Name</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Users" xml:space="preserve">
|
<data name="Users" xml:space="preserve">
|
||||||
<value>Users</value>
|
<value>Users</value>
|
||||||
@ -129,9 +129,6 @@
|
|||||||
<data name="Error.User.Load" xml:space="preserve">
|
<data name="Error.User.Load" xml:space="preserve">
|
||||||
<value>Error Loading Users</value>
|
<value>Error Loading Users</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Error.User.LoadRole" xml:space="preserve">
|
|
||||||
<value>Error Loading User Roles</value>
|
|
||||||
</data>
|
|
||||||
<data name="Success.User.AssignedRole" xml:space="preserve">
|
<data name="Success.User.AssignedRole" xml:space="preserve">
|
||||||
<value>User Assigned To Role</value>
|
<value>User Assigned To Role</value>
|
||||||
</data>
|
</data>
|
||||||
@ -151,7 +148,7 @@
|
|||||||
<value>The role you are assigning users to</value>
|
<value>The role you are assigning users to</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="User.HelpText" xml:space="preserve">
|
<data name="User.HelpText" xml:space="preserve">
|
||||||
<value>Select a user</value>
|
<value>Enter the name of a user</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="EffectiveDate.HelpText" xml:space="preserve">
|
<data name="EffectiveDate.HelpText" xml:space="preserve">
|
||||||
<value>The date that this role assignment is active</value>
|
<value>The date that this role assignment is active</value>
|
||||||
|
@ -163,7 +163,7 @@
|
|||||||
<value>Enter the site name</value>
|
<value>Enter the site name</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Tenant.HelpText" xml:space="preserve">
|
<data name="Tenant.HelpText" xml:space="preserve">
|
||||||
<value>Enter the tenant for the site</value>
|
<value>The name of the database used for the site</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Aliases.HelpText" xml:space="preserve">
|
<data name="Aliases.HelpText" xml:space="preserve">
|
||||||
<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).</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).</value>
|
||||||
@ -195,13 +195,13 @@
|
|||||||
<data name="UseSsl.HelpText" xml:space="preserve">
|
<data name="UseSsl.HelpText" xml:space="preserve">
|
||||||
<value>Specify if SSL is required for your SMTP server</value>
|
<value>Specify if SSL is required for your SMTP server</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SmptUsername.HelpText" xml:space="preserve">
|
<data name="SmtpUsername.HelpText" xml:space="preserve">
|
||||||
<value>Enter the username for your SMTP account</value>
|
<value>Enter the username for your SMTP account</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SmtpPassword.HelpText" xml:space="preserve">
|
<data name="SmtpPassword.HelpText" xml:space="preserve">
|
||||||
<value>Enter the password for your SMTP account</value>
|
<value>Enter the password for your SMTP account</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SmptSender.HelpText" xml:space="preserve">
|
<data name="SmtpSender.HelpText" xml:space="preserve">
|
||||||
<value>Enter the email which emails will be sent from. Please note that this email address may need to be authorized with the SMTP server.</value>
|
<value>Enter the email which emails will be sent from. Please note that this email address may need to be authorized with the SMTP server.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="EnablePWA.HelpText" xml:space="preserve">
|
<data name="EnablePWA.HelpText" xml:space="preserve">
|
||||||
@ -214,7 +214,7 @@
|
|||||||
<value>Include a splash icon for your PWA. It should be a PNG which is 512 X 512 pixels in dimension.</value>
|
<value>Include a splash icon for your PWA. It should be a PNG which is 512 X 512 pixels in dimension.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Tenant.Text" xml:space="preserve">
|
<data name="Tenant.Text" xml:space="preserve">
|
||||||
<value>Tenant: </value>
|
<value>Database: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Aliases.Text" xml:space="preserve">
|
<data name="Aliases.Text" xml:space="preserve">
|
||||||
<value>Aliases: </value>
|
<value>Aliases: </value>
|
||||||
@ -243,13 +243,13 @@
|
|||||||
<data name="UseSsl.Text" xml:space="preserve">
|
<data name="UseSsl.Text" xml:space="preserve">
|
||||||
<value>SSL Enabled: </value>
|
<value>SSL Enabled: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SmptUsername.Text" xml:space="preserve">
|
<data name="SmtpUsername.Text" xml:space="preserve">
|
||||||
<value>Username: </value>
|
<value>Username: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SmtpPassword.Text" xml:space="preserve">
|
<data name="SmtpPassword.Text" xml:space="preserve">
|
||||||
<value>Password: </value>
|
<value>Password: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="SmptSender.Text" xml:space="preserve">
|
<data name="SmtpSender.Text" xml:space="preserve">
|
||||||
<value>Email Sender: </value>
|
<value>Email Sender: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="EnablePWA.Text" xml:space="preserve">
|
<data name="EnablePWA.Text" xml:space="preserve">
|
||||||
@ -292,7 +292,7 @@
|
|||||||
<value>Browse</value>
|
<value>Browse</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TenantInformation.Heading" xml:space="preserve">
|
<data name="TenantInformation.Heading" xml:space="preserve">
|
||||||
<value>Tenant Information</value>
|
<value>Database</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PWASettings.Heading" xml:space="preserve">
|
<data name="PWASettings.Heading" xml:space="preserve">
|
||||||
<value>PWA Settings</value>
|
<value>PWA Settings</value>
|
||||||
@ -304,13 +304,13 @@
|
|||||||
<value>Connection:</value>
|
<value>Connection:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Database.Text" xml:space="preserve">
|
<data name="Database.Text" xml:space="preserve">
|
||||||
<value>Database:</value>
|
<value>Type:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ConnectionString.HelpText" xml:space="preserve">
|
<data name="ConnectionString.HelpText" xml:space="preserve">
|
||||||
<value>The connection information for the database</value>
|
<value>The connection information for the database</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Database.HelpText" xml:space="preserve">
|
<data name="Database.HelpText" xml:space="preserve">
|
||||||
<value>The database for the tenant</value>
|
<value>The type of database</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DeleteSite.Text" xml:space="preserve">
|
<data name="DeleteSite.Text" xml:space="preserve">
|
||||||
<value>Delete Site</value>
|
<value>Delete Site</value>
|
||||||
@ -339,4 +339,16 @@
|
|||||||
<data name="HomePage.Text" xml:space="preserve">
|
<data name="HomePage.Text" xml:space="preserve">
|
||||||
<value>Home Page:</value>
|
<value>Home Page:</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="SmtpRelay.HelpText" xml:space="preserve">
|
||||||
|
<value>Only specify this option if you have properly configured an SMTP Relay Service to route your outgoing mail. This option will send notifications from the user's email rather than from the Email Sender specified above.</value>
|
||||||
|
</data>
|
||||||
|
<data name="SmtpRelay.Text" xml:space="preserve">
|
||||||
|
<value>Relay Configured?</value>
|
||||||
|
</data>
|
||||||
|
<data name="SiteMap.HelpText" xml:space="preserve">
|
||||||
|
<value>The site map url for this site which can be submitted to search engines for indexing</value>
|
||||||
|
</data>
|
||||||
|
<data name="SiteMap.Text" xml:space="preserve">
|
||||||
|
<value>Site Map:</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -123,9 +123,6 @@
|
|||||||
<data name="SqlServer" xml:space="preserve">
|
<data name="SqlServer" xml:space="preserve">
|
||||||
<value>SQL Server</value>
|
<value>SQL Server</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Server.Text" xml:space="preserve">
|
|
||||||
<value>Server: </value>
|
|
||||||
</data>
|
|
||||||
<data name="Container.Select" xml:space="preserve">
|
<data name="Container.Select" xml:space="preserve">
|
||||||
<value>Select Container</value>
|
<value>Select Container</value>
|
||||||
</data>
|
</data>
|
||||||
@ -145,7 +142,7 @@
|
|||||||
<value>Select the default container for the site</value>
|
<value>Select the default container for the site</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Tenant.Text" xml:space="preserve">
|
<data name="Tenant.Text" xml:space="preserve">
|
||||||
<value>Tenant: </value>
|
<value>Database: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Aliases.Text" xml:space="preserve">
|
<data name="Aliases.Text" xml:space="preserve">
|
||||||
<value>Aliases: </value>
|
<value>Aliases: </value>
|
||||||
@ -157,10 +154,10 @@
|
|||||||
<value>Select Site Template</value>
|
<value>Select Site Template</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Tenant.Select" xml:space="preserve">
|
<data name="Tenant.Select" xml:space="preserve">
|
||||||
<value>Select Tenant</value>
|
<value>Select Database</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Tenant.Add" xml:space="preserve">
|
<data name="Tenant.Add" xml:space="preserve">
|
||||||
<value>Create New Tenant</value>
|
<value>Create Database</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Error.Theme.LoadContainers" xml:space="preserve">
|
<data name="Error.Theme.LoadContainers" xml:space="preserve">
|
||||||
<value>Error Loading Containers For Theme</value>
|
<value>Error Loading Containers For Theme</value>
|
||||||
@ -172,19 +169,19 @@
|
|||||||
<value>Invalid Host Password</value>
|
<value>Invalid Host Password</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Error.TenantName.Exists" xml:space="preserve">
|
<data name="Error.TenantName.Exists" xml:space="preserve">
|
||||||
<value>Tenant Name Is Missing Or Already Exists</value>
|
<value>Database Name Is Missing Or Already Exists</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.SiteName.InUse" xml:space="preserve">
|
<data name="Message.SiteName.InUse" xml:space="preserve">
|
||||||
<value>{0} Already Used For Another Site</value>
|
<value>{0} Already Used For Another Site</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.Required.Tenant" xml:space="preserve">
|
<data name="Message.Required.Tenant" xml:space="preserve">
|
||||||
<value>You Must Provide A Tenant, Site Name, Alias, Default Theme/Container, And Site Template</value>
|
<value>You Must Provide A Database, Site Name, Alias, Default Theme/Container, And Site Template</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Name.HelpText" xml:space="preserve">
|
<data name="Name.HelpText" xml:space="preserve">
|
||||||
<value>Enter the name of the site</value>
|
<value>Enter the name of the site</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DefaultTheme.HelpText" xml:space="preserve">
|
<data name="DefaultTheme.HelpText" xml:space="preserve">
|
||||||
<value>Select the default theme for the website</value>
|
<value>Select the default theme for the site</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AdminContainer.HelpText" xml:space="preserve">
|
<data name="AdminContainer.HelpText" xml:space="preserve">
|
||||||
<value>Select the admin container for the site</value>
|
<value>Select the admin container for the site</value>
|
||||||
@ -193,28 +190,13 @@
|
|||||||
<value>Select the site template</value>
|
<value>Select the site template</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Tenant.HelpText" xml:space="preserve">
|
<data name="Tenant.HelpText" xml:space="preserve">
|
||||||
<value>Select the tenant for the site</value>
|
<value>Select the database for the site</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TenantName.HelpText" xml:space="preserve">
|
<data name="TenantName.HelpText" xml:space="preserve">
|
||||||
<value>Enter the name for the tenant</value>
|
<value>Enter the name for the database</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DatabaseType.HelpText" xml:space="preserve">
|
<data name="DatabaseType.HelpText" xml:space="preserve">
|
||||||
<value>Select the database type for the tenant</value>
|
<value>Select the database type</value>
|
||||||
</data>
|
|
||||||
<data name="DatabaseServer.HelpText" xml:space="preserve">
|
|
||||||
<value>Enter the server for the tenant</value>
|
|
||||||
</data>
|
|
||||||
<data name="Database.HelpText" xml:space="preserve">
|
|
||||||
<value>Enter the database for the tenant</value>
|
|
||||||
</data>
|
|
||||||
<data name="IntegratedSecurity.HelpText" xml:space="preserve">
|
|
||||||
<value>Select if you want integrated security or not</value>
|
|
||||||
</data>
|
|
||||||
<data name="DatabaseUsername.HelpText" xml:space="preserve">
|
|
||||||
<value>Enter the username for the integrated security</value>
|
|
||||||
</data>
|
|
||||||
<data name="DatabasePassword.HelpText" xml:space="preserve">
|
|
||||||
<value>Enter the password for the integrated security</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="HostUsername.HelpText" xml:space="preserve">
|
<data name="HostUsername.HelpText" xml:space="preserve">
|
||||||
<value>Enter the username of an existing host user</value>
|
<value>Enter the username of an existing host user</value>
|
||||||
@ -232,23 +214,14 @@
|
|||||||
<value>Site Template: </value>
|
<value>Site Template: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TenantName.Text" xml:space="preserve">
|
<data name="TenantName.Text" xml:space="preserve">
|
||||||
<value>Tenant Name: </value>
|
<value>Name: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DatabaseType.Text" xml:space="preserve">
|
<data name="DatabaseType.Text" xml:space="preserve">
|
||||||
<value>Database Type: </value>
|
<value>Type: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Database.Text" xml:space="preserve">
|
<data name="Database.Text" xml:space="preserve">
|
||||||
<value>Database: </value>
|
<value>Database: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IntegratedSecurity.Text" xml:space="preserve">
|
|
||||||
<value>Integrated Security: </value>
|
|
||||||
</data>
|
|
||||||
<data name="DatabaseUsername.Text" xml:space="preserve">
|
|
||||||
<value>Database Username: </value>
|
|
||||||
</data>
|
|
||||||
<data name="DatabasePassword.Text" xml:space="preserve">
|
|
||||||
<value>Database Password: </value>
|
|
||||||
</data>
|
|
||||||
<data name="HostUsername.Text" xml:space="preserve">
|
<data name="HostUsername.Text" xml:space="preserve">
|
||||||
<value>Host Username:</value>
|
<value>Host Username:</value>
|
||||||
</data>
|
</data>
|
||||||
@ -274,7 +247,7 @@
|
|||||||
<value>Enter a complete connection string including all parameters and delimiters</value>
|
<value>Enter a complete connection string including all parameters and delimiters</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ConnectionString.Text" xml:space="preserve">
|
<data name="ConnectionString.Text" xml:space="preserve">
|
||||||
<value>String:</value>
|
<value>Settings:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="EnterConnectionParameters" xml:space="preserve">
|
<data name="EnterConnectionParameters" xml:space="preserve">
|
||||||
<value>Enter Connection Parameters</value>
|
<value>Enter Connection Parameters</value>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
@ -117,30 +117,75 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
|
<data name="Connection.Text" xml:space="preserve">
|
||||||
|
<value>Connection: </value>
|
||||||
|
</data>
|
||||||
|
<data name="Connection.HelpText" xml:space="preserve">
|
||||||
|
<value>Select a database connection (from appsettings.json)</value>
|
||||||
|
</data>
|
||||||
|
<data name="Connection.Select" xml:space="preserve">
|
||||||
|
<value>Select Connection</value>
|
||||||
|
</data>
|
||||||
|
<data name="Connection.Add" xml:space="preserve">
|
||||||
|
<value>Add Connection</value>
|
||||||
|
</data>
|
||||||
|
<data name="Name.Text" xml:space="preserve">
|
||||||
|
<value>Name: </value>
|
||||||
|
</data>
|
||||||
|
<data name="Name.HelpText" xml:space="preserve">
|
||||||
|
<value>Enter the name of the connection</value>
|
||||||
|
</data>
|
||||||
|
<data name="DatabaseType.Text" xml:space="preserve">
|
||||||
|
<value>Type: </value>
|
||||||
|
</data>
|
||||||
|
<data name="DatabaseType.HelpText" xml:space="preserve">
|
||||||
|
<value>Select the database type</value>
|
||||||
|
</data>
|
||||||
|
<data name="Type.Select" xml:space="preserve">
|
||||||
|
<value>Select Type</value>
|
||||||
|
</data>
|
||||||
|
<data name="EnterConnectionParameters" xml:space="preserve">
|
||||||
|
<value>Enter Connection Parameters</value>
|
||||||
|
</data>
|
||||||
|
<data name="EnterConnectionString" xml:space="preserve">
|
||||||
|
<value>Enter Connection String</value>
|
||||||
|
</data>
|
||||||
|
<data name="ConnectionString.Text" xml:space="preserve">
|
||||||
|
<value>Settings: </value>
|
||||||
|
</data>
|
||||||
|
<data name="ConnectionString.HelpText" xml:space="preserve">
|
||||||
|
<value>A complete connection string including all parameters and delimiters</value>
|
||||||
|
</data>
|
||||||
|
<data name="Add" xml:space="preserve">
|
||||||
|
<value>Add</value>
|
||||||
|
</data>
|
||||||
<data name="Tenant.Text" xml:space="preserve">
|
<data name="Tenant.Text" xml:space="preserve">
|
||||||
<value>Tenant: </value>
|
<value>Database: </value>
|
||||||
</data>
|
|
||||||
<data name="Tenant.Select" xml:space="preserve">
|
|
||||||
<value>Select Tenant</value>
|
|
||||||
</data>
|
|
||||||
<data name="Execute" xml:space="preserve">
|
|
||||||
<value>Execute</value>
|
|
||||||
</data>
|
|
||||||
<data name="Message.Required.Tenant" xml:space="preserve">
|
|
||||||
<value>You Must Select A Tenant And Provide A Valid SQL Query</value>
|
|
||||||
</data>
|
|
||||||
<data name="Return.NoResult" xml:space="preserve">
|
|
||||||
<value>No Results Returned</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="Tenant.HelpText" xml:space="preserve">
|
<data name="Tenant.HelpText" xml:space="preserve">
|
||||||
<value>Select the tenant for the SQL server</value>
|
<value>The database using this connection</value>
|
||||||
</data>
|
|
||||||
<data name="SqlQuery.HelpText" xml:space="preserve">
|
|
||||||
<value>Enter the query for the SQL server</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="SqlQuery.Text" xml:space="preserve">
|
<data name="SqlQuery.Text" xml:space="preserve">
|
||||||
<value>SQL Query: </value>
|
<value>SQL Query: </value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="SqlQuery.HelpText" xml:space="preserve">
|
||||||
|
<value>Enter a valid SQL query for the database</value>
|
||||||
|
</data>
|
||||||
|
<data name="Execute" xml:space="preserve">
|
||||||
|
<value>Execute</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.Required.Tenant" xml:space="preserve">
|
||||||
|
<value>You Must Select A Database Type And Provide A Valid SQL Query</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.Required.Connection" xml:space="preserve">
|
||||||
|
<value>You Must Provide A Connection Name And Settings</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.Connection.Added" xml:space="preserve">
|
||||||
|
<value>Connection Added Successfully</value>
|
||||||
|
</data>
|
||||||
|
<data name="Return.NoResult" xml:space="preserve">
|
||||||
|
<value>No Results Returned</value>
|
||||||
|
</data>
|
||||||
<data name="Success.QueryExecuted" xml:space="preserve">
|
<data name="Success.QueryExecuted" xml:space="preserve">
|
||||||
<value>SQL Query Executed</value>
|
<value>SQL Query Executed</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -210,7 +210,10 @@
|
|||||||
<data name="Options.Heading" xml:space="preserve">
|
<data name="Options.Heading" xml:space="preserve">
|
||||||
<value>Options</value>
|
<value>Options</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Register" xml:space="preserve">
|
<data name="Log.Heading" xml:space="preserve">
|
||||||
|
<value>Log</value>
|
||||||
|
</data>
|
||||||
|
<data name="Register" xml:space="preserve">
|
||||||
<value>Please Register Me For Major Product Updates And Security Bulletins</value>
|
<value>Please Register Me For Major Product Updates And Security Bulletins</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Success.Register" xml:space="preserve">
|
<data name="Success.Register" xml:space="preserve">
|
||||||
@ -276,4 +279,19 @@
|
|||||||
<data name="Environment.Text" xml:space="preserve">
|
<data name="Environment.Text" xml:space="preserve">
|
||||||
<value>Environment:</value>
|
<value>Environment:</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Log.Text" xml:space="preserve">
|
||||||
|
<value>Log:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Log.HelpText" xml:space="preserve">
|
||||||
|
<value>System log information for current day</value>
|
||||||
|
</data>
|
||||||
|
<data name="Clear" xml:space="preserve">
|
||||||
|
<value>Clear</value>
|
||||||
|
</data>
|
||||||
|
<data name="Success.ClearLog" xml:space="preserve">
|
||||||
|
<value>System Log Has Been Successfully Cleared</value>
|
||||||
|
</data>
|
||||||
|
<data name="Error.ClearLog" xml:space="preserve">
|
||||||
|
<value>Ann Error Occurred Clearing The System Log</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
@ -123,17 +123,14 @@
|
|||||||
<data name="Theme.Text" xml:space="preserve">
|
<data name="Theme.Text" xml:space="preserve">
|
||||||
<value>Theme: </value>
|
<value>Theme: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Success.Theme.Install" xml:space="preserve">
|
|
||||||
<value>Theme Installed Successfully. You Must <a href={0}>Restart</a> Your Application To Apply These Changes.</value>
|
|
||||||
</data>
|
|
||||||
<data name="Success.Theme.Download" xml:space="preserve">
|
<data name="Success.Theme.Download" xml:space="preserve">
|
||||||
<value>Theme Downloaded Successfully. Click Install To Complete Installation.</value>
|
<value>Theme Package Saved Successfully. You Must <a href={0}>Restart</a> Your Application To Complete The Installation.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Error.Theme.Download" xml:space="preserve">
|
<data name="Error.Theme.Download" xml:space="preserve">
|
||||||
<value>Error Downloading Theme</value>
|
<value>Error Downloading Theme</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Theme.HelpText" xml:space="preserve">
|
<data name="Theme.HelpText" xml:space="preserve">
|
||||||
<value>Upload one or more theme packages. Once they are uploaded click Install to complete the installation.</value>
|
<value>Upload one or more theme packages.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Search.NoResults" xml:space="preserve">
|
<data name="Search.NoResults" xml:space="preserve">
|
||||||
<value>No Themes Match The Criteria Provided Or Package Service Is Disabled</value>
|
<value>No Themes Match The Criteria Provided Or Package Service Is Disabled</value>
|
||||||
|
@ -120,6 +120,9 @@
|
|||||||
<data name="Message.Password.Invalid" xml:space="preserve">
|
<data name="Message.Password.Invalid" xml:space="preserve">
|
||||||
<value>Passwords Entered Do Not Match</value>
|
<value>Passwords Entered Do Not Match</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Message.Password.Complexity" xml:space="preserve">
|
||||||
|
<value>Password Provided Does Not Meet The Complexity Policy</value>
|
||||||
|
</data>
|
||||||
<data name="From" xml:space="preserve">
|
<data name="From" xml:space="preserve">
|
||||||
<value>From</value>
|
<value>From</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -120,6 +120,9 @@
|
|||||||
<data name="Message.Password.NoMatch" xml:space="preserve">
|
<data name="Message.Password.NoMatch" xml:space="preserve">
|
||||||
<value>Passwords Entered Do Not Match</value>
|
<value>Passwords Entered Do Not Match</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Message.Password.Complexity" xml:space="preserve">
|
||||||
|
<value>Password Provided Does Not Meet The Complexity Policy</value>
|
||||||
|
</data>
|
||||||
<data name="Identity.Name" xml:space="preserve">
|
<data name="Identity.Name" xml:space="preserve">
|
||||||
<value>Identity</value>
|
<value>Identity</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -387,7 +387,13 @@
|
|||||||
<data name="RoleClaimType.HelpText" xml:space="preserve">
|
<data name="RoleClaimType.HelpText" xml:space="preserve">
|
||||||
<value>Optionally provide the name of the role claim provided by the identity provider. These roles will be used in addition to any internal user roles assigned within the site.</value>
|
<value>Optionally provide the name of the role claim provided by the identity provider. These roles will be used in addition to any internal user roles assigned within the site.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RoleClaimType.Text" xml:space="preserve">
|
<data name="RoleClaimType.Text" xml:space="preserve">
|
||||||
<value>Role Claim Type:</value>
|
<value>Role Claim:</value>
|
||||||
|
</data>
|
||||||
|
<data name="ProfileClaimTypes.HelpText" xml:space="preserve">
|
||||||
|
<value>Optionally provide a comma delimited list of user profile claims provided by the identity provider, as well as mappings to your user profile definition. For example if the identity provider includes a 'given_name' claim and you have a 'FirstName' user profile definition you should specify 'given_name:FirstName'.</value>
|
||||||
|
</data>
|
||||||
|
<data name="ProfileClaimTypes.Text" xml:space="preserve">
|
||||||
|
<value>User Profile Claims:</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
@ -127,7 +127,7 @@
|
|||||||
<value>Error Loading Files</value>
|
<value>Error Loading Files</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Error.File.Upload" xml:space="preserve">
|
<data name="Error.File.Upload" xml:space="preserve">
|
||||||
<value>File Upload Failed</value>
|
<value>File Upload Failed Or Is Still In Progress</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.File.NotSelected" xml:space="preserve">
|
<data name="Message.File.NotSelected" xml:space="preserve">
|
||||||
<value>You Have Not Selected A File To Upload</value>
|
<value>You Have Not Selected A File To Upload</value>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
@ -124,9 +124,9 @@
|
|||||||
<value>User</value>
|
<value>User</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Username.Enter" xml:space="preserve">
|
<data name="Username.Enter" xml:space="preserve">
|
||||||
<value>Enter Username</value>
|
<value>Enter User's Name</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.Username.DontExist" xml:space="preserve">
|
<data name="Message.Username.DontExist" xml:space="preserve">
|
||||||
<value>Username Does Not Exist</value>
|
<value>User Does Not Exist With Name Specified</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
@ -340,6 +340,48 @@
|
|||||||
<value>Visitor Management</value>
|
<value>Visitor Management</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Oqtane.Marketplace" xml:space="preserve">
|
<data name="Oqtane.Marketplace" xml:space="preserve">
|
||||||
<value>Please note that the third party extensions displayed above have been registered in the <a href="https://www.oqtane.net" target="_new">Oqtane Marketplace</a> which enables them to be seamlessly downloaded and installed into the framework.</value>
|
<value>Please note that third party extensions are registered in the <a href="https://www.oqtane.net" target="_new">Oqtane Marketplace</a> which enables them to be seamlessly downloaded and installed into the framework.</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
<data name="Home" xml:space="preserve">
|
||||||
|
<value>Home</value>
|
||||||
|
</data>
|
||||||
|
<data name="Close" xml:space="preserve">
|
||||||
|
<value>Close</value>
|
||||||
|
</data>
|
||||||
|
<data name="OK" xml:space="preserve">
|
||||||
|
<value>OK</value>
|
||||||
|
</data>
|
||||||
|
<data name="Apply" xml:space="preserve">
|
||||||
|
<value>Apply</value>
|
||||||
|
</data>
|
||||||
|
<data name="Select" xml:space="preserve">
|
||||||
|
<value>Select</value>
|
||||||
|
</data>
|
||||||
|
<data name="Next" xml:space="preserve">
|
||||||
|
<value>Next</value>
|
||||||
|
</data>
|
||||||
|
<data name="Previous" xml:space="preserve">
|
||||||
|
<value>Previous</value>
|
||||||
|
</data>
|
||||||
|
<data name="Submit" xml:space="preserve">
|
||||||
|
<value>Submit</value>
|
||||||
|
</data>
|
||||||
|
<data name="Refresh" xml:space="preserve">
|
||||||
|
<value>Refresh</value>
|
||||||
|
</data>
|
||||||
|
<data name="Back" xml:space="preserve">
|
||||||
|
<value>Back</value>
|
||||||
|
</data>
|
||||||
|
<data name="Return" xml:space="preserve">
|
||||||
|
<value>Return</value>
|
||||||
|
</data>
|
||||||
|
<data name="New" xml:space="preserve">
|
||||||
|
<value>New</value>
|
||||||
|
</data>
|
||||||
|
<data name="View" xml:space="preserve">
|
||||||
|
<value>View</value>
|
||||||
|
</data>
|
||||||
|
<data name="Confirm" xml:space="preserve">
|
||||||
|
<value>Confirm</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
|
@ -2,27 +2,17 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.JSInterop;
|
|
||||||
using Oqtane.Documentation;
|
using Oqtane.Documentation;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
using Oqtane.UI;
|
|
||||||
|
|
||||||
namespace Oqtane.Services
|
namespace Oqtane.Services
|
||||||
{
|
{
|
||||||
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
|
||||||
public class FileService : ServiceBase, IFileService
|
public class FileService : ServiceBase, IFileService
|
||||||
{
|
{
|
||||||
private readonly SiteState _siteState;
|
public FileService(HttpClient http, SiteState siteState) : base(http, siteState) { }
|
||||||
private readonly IJSRuntime _jsRuntime;
|
|
||||||
|
|
||||||
public FileService(HttpClient http, SiteState siteState, IJSRuntime jsRuntime) : base(http, siteState)
|
|
||||||
{
|
|
||||||
_siteState = siteState;
|
|
||||||
_jsRuntime = jsRuntime;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string Apiurl => CreateApiUrl("File");
|
private string Apiurl => CreateApiUrl("File");
|
||||||
|
|
||||||
@ -75,54 +65,6 @@ namespace Oqtane.Services
|
|||||||
return await GetJsonAsync<File>($"{Apiurl}/upload?url={WebUtility.UrlEncode(url)}&folderid={folderId}&name={name}");
|
return await GetJsonAsync<File>($"{Apiurl}/upload?url={WebUtility.UrlEncode(url)}&folderid={folderId}&name={name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> UploadFilesAsync(int folderId, string[] files, string id)
|
|
||||||
{
|
|
||||||
return await UploadFilesAsync(folderId.ToString(), files, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<string> UploadFilesAsync(string folder, string[] files, string id)
|
|
||||||
{
|
|
||||||
string result = "";
|
|
||||||
|
|
||||||
var interop = new Interop(_jsRuntime);
|
|
||||||
await interop.UploadFiles($"{Apiurl}/upload", folder, id, _siteState.AntiForgeryToken);
|
|
||||||
|
|
||||||
// uploading files is asynchronous so we need to wait for the upload to complete
|
|
||||||
bool success = false;
|
|
||||||
int attempts = 0;
|
|
||||||
while (attempts < 5 && success == false)
|
|
||||||
{
|
|
||||||
Thread.Sleep(2000); // wait 2 seconds
|
|
||||||
result = "";
|
|
||||||
|
|
||||||
List<File> fileList = await GetFilesAsync(folder);
|
|
||||||
if (fileList.Count > 0)
|
|
||||||
{
|
|
||||||
success = true;
|
|
||||||
foreach (string file in files)
|
|
||||||
{
|
|
||||||
if (!fileList.Exists(item => item.Name == file))
|
|
||||||
{
|
|
||||||
success = false;
|
|
||||||
result += file + ",";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
attempts += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
await interop.SetElementAttribute(id + "ProgressInfo", "style", "display: none;");
|
|
||||||
await interop.SetElementAttribute(id + "ProgressBar", "style", "display: none;");
|
|
||||||
|
|
||||||
if (!success)
|
|
||||||
{
|
|
||||||
result = result.Substring(0, result.Length - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<byte[]> DownloadFileAsync(int fileId)
|
public async Task<byte[]> DownloadFileAsync(int fileId)
|
||||||
{
|
{
|
||||||
return await GetByteArrayAsync($"{Apiurl}/download/{fileId}");
|
return await GetByteArrayAsync($"{Apiurl}/download/{fileId}");
|
||||||
|
@ -66,27 +66,6 @@ namespace Oqtane.Services
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<File> UploadFileAsync(string url, int folderId, string name);
|
Task<File> UploadFileAsync(string url, int folderId, string name);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Upload one or more files.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="folderId">Target <see cref="Folder"/></param>
|
|
||||||
/// <param name="files">The files to upload, serialized as a string.</param>
|
|
||||||
/// <param name="fileUploadName">A task-identifier, to ensure communication about this upload.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<string> UploadFilesAsync(int folderId, string[] files, string fileUploadName);
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Upload one or more files.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="folder">Target <see cref="Folder"/>
|
|
||||||
/// TODO: todoc verify exactly from where the folder path must start
|
|
||||||
/// </param>
|
|
||||||
/// <param name="files">The files to upload, serialized as a string.</param>
|
|
||||||
/// <param name="fileUploadName">A task-identifier, to ensure communication about this upload.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task<string> UploadFilesAsync(string folder, string[] files, string fileUploadName);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get / download a file (the body).
|
/// Get / download a file (the body).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -13,6 +13,6 @@ namespace Oqtane.Services
|
|||||||
/// Returns a collection of supported cultures
|
/// Returns a collection of supported cultures
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<IEnumerable<Culture>> GetCulturesAsync();
|
Task<IEnumerable<Culture>> GetCulturesAsync(bool installed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,13 +33,6 @@ namespace Oqtane.Services
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task UpdateModuleDefinitionAsync(ModuleDefinition moduleDefinition);
|
Task UpdateModuleDefinitionAsync(ModuleDefinition moduleDefinition);
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Installs all module definitions located in //TODO: 2dm where?
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task InstallModuleDefinitionsAsync();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Deletes a module definition
|
/// Deletes a module definition
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -62,7 +62,7 @@ namespace Oqtane.Services
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a key-value dictionary of all page module settings for the given page module
|
/// Returns a key-value dictionary of all page module settings for the given page module
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pageId"></param>
|
/// <param name="pageModuleId"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<Dictionary<string, string>> GetPageModuleSettingsAsync(int pageModuleId);
|
Task<Dictionary<string, string>> GetPageModuleSettingsAsync(int pageModuleId);
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ namespace Oqtane.Services
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a key-value dictionary of all user settings for the given user
|
/// Returns a key-value dictionary of all user settings for the given user
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pageId"></param>
|
/// <param name="userId"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<Dictionary<string, string>> GetUserSettingsAsync(int userId);
|
Task<Dictionary<string, string>> GetUserSettingsAsync(int userId);
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ namespace Oqtane.Services
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a key-value dictionary of all folder settings for the given folder
|
/// Returns a key-value dictionary of all folder settings for the given folder
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pageId"></param>
|
/// <param name="folderId"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<Dictionary<string, string>> GetFolderSettingsAsync(int folderId);
|
Task<Dictionary<string, string>> GetFolderSettingsAsync(int folderId);
|
||||||
|
|
||||||
@ -148,6 +148,21 @@ namespace Oqtane.Services
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task UpdateHostSettingsAsync(Dictionary<string, string> hostSettings);
|
Task UpdateHostSettingsAsync(Dictionary<string, string> hostSettings);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a key-value dictionary of all settings for the given visitor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="visitorId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<Dictionary<string, string>> GetVisitorSettingsAsync(int visitorId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates a visitor setting
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="visitorSettings"></param>
|
||||||
|
/// <param name="visitorId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task UpdateVisitorSettingsAsync(Dictionary<string, string> visitorSettings, int visitorId);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a key-value dictionary of all settings for the given entityName
|
/// Returns a key-value dictionary of all settings for the given entityName
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -164,6 +179,24 @@ namespace Oqtane.Services
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task UpdateSettingsAsync(Dictionary<string, string> settings, string entityName, int entityId);
|
Task UpdateSettingsAsync(Dictionary<string, string> settings, string entityName, int entityId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a specific setting
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entityName"></param>
|
||||||
|
/// <param name="entityId"></param>
|
||||||
|
/// <param name="settingName"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task DeleteSettingAsync(string entityName, int entityId, string settingName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a specific setting
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entityName"></param>
|
||||||
|
/// <param name="entityId"></param>
|
||||||
|
/// <param name="settingName"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<List<Setting>> GetSettingsAsync(string entityName, int entityId, string settingName);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a specific setting
|
/// Returns a specific setting
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -32,11 +32,5 @@ namespace Oqtane.Services
|
|||||||
/// <param name="settings"></param>
|
/// <param name="settings"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task UpdateSystemInfoAsync(Dictionary<string, object> settings);
|
Task UpdateSystemInfoAsync(Dictionary<string, object> settings);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// updates a config value
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task UpdateSystemInfoAsync(string settingKey, object settingValue);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,12 +39,6 @@ namespace Oqtane.Services
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
List<ThemeControl> GetContainerControls(List<Theme> themes, string themeName);
|
List<ThemeControl> GetContainerControls(List<Theme> themes, string themeName);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Installs all themes located in //TODO: 2dm where?
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task InstallThemesAsync();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Deletes a theme
|
/// Deletes a theme
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -14,6 +14,6 @@ namespace Oqtane.Services
|
|||||||
|
|
||||||
private string Apiurl => CreateApiUrl("Localization");
|
private string Apiurl => CreateApiUrl("Localization");
|
||||||
|
|
||||||
public async Task<IEnumerable<Culture>> GetCulturesAsync() => await GetJsonAsync<IEnumerable<Culture>>(Apiurl);
|
public async Task<IEnumerable<Culture>> GetCulturesAsync(bool installed) => await GetJsonAsync<IEnumerable<Culture>>($"{Apiurl}?installed={installed}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,11 +34,6 @@ namespace Oqtane.Services
|
|||||||
await PutJsonAsync($"{Apiurl}/{moduleDefinition.ModuleDefinitionId}", moduleDefinition);
|
await PutJsonAsync($"{Apiurl}/{moduleDefinition.ModuleDefinitionId}", moduleDefinition);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task InstallModuleDefinitionsAsync()
|
|
||||||
{
|
|
||||||
await GetJsonAsync<List<string>>($"{Apiurl}/install");
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteModuleDefinitionAsync(int moduleDefinitionId, int siteId)
|
public async Task DeleteModuleDefinitionAsync(int moduleDefinitionId, int siteId)
|
||||||
{
|
{
|
||||||
await DeleteAsync($"{Apiurl}/{moduleDefinitionId}?siteid={siteId}");
|
await DeleteAsync($"{Apiurl}/{moduleDefinitionId}?siteid={siteId}");
|
||||||
|
@ -18,11 +18,7 @@ namespace Oqtane.Services
|
|||||||
|
|
||||||
public async Task<List<Module>> GetModulesAsync(int siteId)
|
public async Task<List<Module>> GetModulesAsync(int siteId)
|
||||||
{
|
{
|
||||||
List<Module> modules = await GetJsonAsync<List<Module>>($"{Apiurl}?siteid={siteId}");
|
return await GetJsonAsync<List<Module>>($"{Apiurl}?siteid={siteId}");
|
||||||
modules = modules
|
|
||||||
.OrderBy(item => item.Order)
|
|
||||||
.ToList();
|
|
||||||
return modules;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Module> GetModuleAsync(int moduleId)
|
public async Task<Module> GetModuleAsync(int moduleId)
|
||||||
|
@ -111,14 +111,36 @@ namespace Oqtane.Services
|
|||||||
await UpdateSettingsAsync(hostSettings, EntityNames.Host, -1);
|
await UpdateSettingsAsync(hostSettings, EntityNames.Host, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<Dictionary<string, string>> GetVisitorSettingsAsync(int visitorId)
|
||||||
|
{
|
||||||
|
if (visitorId != -1)
|
||||||
|
{
|
||||||
|
return await GetSettingsAsync(EntityNames.Visitor, visitorId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new Dictionary<string, string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateVisitorSettingsAsync(Dictionary<string, string> visitorSettings, int visitorId)
|
||||||
|
{
|
||||||
|
if (visitorId != -1)
|
||||||
|
{
|
||||||
|
await UpdateSettingsAsync(visitorSettings, EntityNames.Visitor, visitorId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<Dictionary<string, string>> GetSettingsAsync(string entityName, int entityId)
|
public async Task<Dictionary<string, string>> GetSettingsAsync(string entityName, int entityId)
|
||||||
{
|
{
|
||||||
var dictionary = new Dictionary<string, string>();
|
var dictionary = new Dictionary<string, string>();
|
||||||
var settings = await GetJsonAsync<List<Setting>>($"{Apiurl}?entityname={entityName}&entityid={entityId}");
|
var settings = await GetJsonAsync<List<Setting>>($"{Apiurl}?entityname={entityName}&entityid={entityId}");
|
||||||
|
if (settings != null)
|
||||||
foreach(Setting setting in settings.OrderBy(item => item.SettingName).ToList())
|
|
||||||
{
|
{
|
||||||
dictionary.Add(setting.SettingName, setting.SettingValue);
|
foreach (Setting setting in settings.OrderBy(item => item.SettingName).ToList())
|
||||||
|
{
|
||||||
|
dictionary.Add(setting.SettingName, setting.SettingValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return dictionary;
|
return dictionary;
|
||||||
}
|
}
|
||||||
@ -170,6 +192,26 @@ namespace Oqtane.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task DeleteSettingAsync(string entityName, int entityId, string settingName)
|
||||||
|
{
|
||||||
|
var settings = await GetJsonAsync<List<Setting>>($"{Apiurl}?entityname={entityName}&entityid={entityId}");
|
||||||
|
var setting = settings.FirstOrDefault(item => item.SettingName == settingName);
|
||||||
|
if (setting != null)
|
||||||
|
{
|
||||||
|
await DeleteAsync($"{Apiurl}/{setting.SettingId}/{entityName}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<Setting>> GetSettingsAsync(string entityName, int entityId, string settingName)
|
||||||
|
{
|
||||||
|
var settings = await GetJsonAsync<List<Setting>>($"{Apiurl}?entityname={entityName}&entityid={entityId}");
|
||||||
|
if (!string.IsNullOrEmpty(settingName))
|
||||||
|
{
|
||||||
|
settings = settings.Where(item => item.SettingName == settingName).ToList();
|
||||||
|
}
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<Setting> GetSettingAsync(string entityName, int settingId)
|
public async Task<Setting> GetSettingAsync(string entityName, int settingId)
|
||||||
{
|
{
|
||||||
return await GetJsonAsync<Setting>($"{Apiurl}/{settingId}/{entityName}");
|
return await GetJsonAsync<Setting>($"{Apiurl}/{settingId}/{entityName}");
|
||||||
|
@ -3,6 +3,7 @@ using System.Threading.Tasks;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Oqtane.Documentation;
|
using Oqtane.Documentation;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
namespace Oqtane.Services
|
namespace Oqtane.Services
|
||||||
{
|
{
|
||||||
@ -32,9 +33,5 @@ namespace Oqtane.Services
|
|||||||
{
|
{
|
||||||
await PostJsonAsync(Apiurl, settings);
|
await PostJsonAsync(Apiurl, settings);
|
||||||
}
|
}
|
||||||
public async Task UpdateSystemInfoAsync(string settingKey, object settingValue)
|
|
||||||
{
|
|
||||||
await PutJsonAsync($"{Apiurl}/{settingKey}/{settingValue}", "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,11 +38,6 @@ namespace Oqtane.Services
|
|||||||
.SelectMany(item => item.Containers).ToList();
|
.SelectMany(item => item.Containers).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task InstallThemesAsync()
|
|
||||||
{
|
|
||||||
await GetJsonAsync<List<string>>($"{ApiUrl}/install");
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteThemeAsync(string themeName)
|
public async Task DeleteThemeAsync(string themeName)
|
||||||
{
|
{
|
||||||
await DeleteAsync($"{ApiUrl}/{themeName}");
|
await DeleteAsync($"{ApiUrl}/{themeName}");
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
@inherits ModuleActionsBase
|
@inherits ModuleActionsBase
|
||||||
@attribute [OqtaneIgnore]
|
@attribute [OqtaneIgnore]
|
||||||
|
|
||||||
@if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions) && PageState.Action == Constants.DefaultAction)
|
@if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList) && PageState.Action == Constants.DefaultAction)
|
||||||
{
|
{
|
||||||
<div class="app-moduleactions py-2 px-3">
|
<div class="app-moduleactions py-2 px-3">
|
||||||
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"></a>
|
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"></a>
|
||||||
|
@ -30,11 +30,11 @@ namespace Oqtane.Themes.Controls
|
|||||||
{
|
{
|
||||||
var actionList = new List<ActionViewModel>();
|
var actionList = new List<ActionViewModel>();
|
||||||
|
|
||||||
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
|
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
||||||
{
|
{
|
||||||
actionList.Add(new ActionViewModel { Icon = Icons.Cog, Name = "Manage Settings", Action = async (u, m) => await Settings(u, m) });
|
actionList.Add(new ActionViewModel { Icon = Icons.Cog, Name = "Manage Settings", Action = async (u, m) => await Settings(u, m) });
|
||||||
|
|
||||||
if (UserSecurity.ContainsRole(ModuleState.Permissions, PermissionNames.View, RoleNames.Everyone))
|
if (UserSecurity.ContainsRole(ModuleState.PermissionList, PermissionNames.View, RoleNames.Everyone))
|
||||||
{
|
{
|
||||||
actionList.Add(new ActionViewModel { Icon = Icons.CircleX, Name = "Unpublish Module", Action = async (s, m) => await Unpublish(s, m) });
|
actionList.Add(new ActionViewModel { Icon = Icons.CircleX, Name = "Unpublish Module", Action = async (s, m) => await Unpublish(s, m) });
|
||||||
}
|
}
|
||||||
@ -44,7 +44,7 @@ namespace Oqtane.Themes.Controls
|
|||||||
}
|
}
|
||||||
actionList.Add(new ActionViewModel { Icon = Icons.Trash, Name = "Delete Module", Action = async (u, m) => await DeleteModule(u, m) });
|
actionList.Add(new ActionViewModel { Icon = Icons.Trash, Name = "Delete Module", Action = async (u, m) => await DeleteModule(u, m) });
|
||||||
|
|
||||||
if (ModuleState.ModuleDefinition != null && ModuleState.ModuleDefinition.ServerManagerType != "")
|
if (ModuleState.ModuleDefinition != null && ModuleState.ModuleDefinition.IsPortable)
|
||||||
{
|
{
|
||||||
actionList.Add(new ActionViewModel { Name = "" });
|
actionList.Add(new ActionViewModel { Name = "" });
|
||||||
actionList.Add(new ActionViewModel { Icon = Icons.CloudUpload, Name = "Import Content", Action = async (u, m) => await EditUrlAsync(u, m.ModuleId, "Import") });
|
actionList.Add(new ActionViewModel { Icon = Icons.CloudUpload, Name = "Import Content", Action = async (u, m) => await EditUrlAsync(u, m.ModuleId, "Import") });
|
||||||
@ -93,7 +93,7 @@ namespace Oqtane.Themes.Controls
|
|||||||
|
|
||||||
protected async Task ModuleAction(ActionViewModel action)
|
protected async Task ModuleAction(ActionViewModel action)
|
||||||
{
|
{
|
||||||
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, ModuleState.Permissions))
|
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, ModuleState.PermissionList))
|
||||||
{
|
{
|
||||||
PageModule pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
|
PageModule pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
|
||||||
|
|
||||||
@ -136,36 +136,32 @@ namespace Oqtane.Themes.Controls
|
|||||||
|
|
||||||
private async Task<string> Publish(string url, PageModule pagemodule)
|
private async Task<string> Publish(string url, PageModule pagemodule)
|
||||||
{
|
{
|
||||||
var permissions = UserSecurity.GetPermissionStrings(pagemodule.Module.Permissions);
|
var permissions = pagemodule.Module.PermissionList;
|
||||||
foreach (var permissionstring in permissions)
|
if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Everyone))
|
||||||
{
|
{
|
||||||
if (permissionstring.PermissionName == PermissionNames.View)
|
permissions.Add(new Permission(ModuleState.SiteId, EntityNames.Page, pagemodule.PageId, PermissionNames.View, RoleNames.Everyone, null, true));
|
||||||
{
|
|
||||||
List<string> ids = permissionstring.Permissions.Split(';').ToList();
|
|
||||||
if (!ids.Contains(RoleNames.Everyone)) ids.Add(RoleNames.Everyone);
|
|
||||||
if (!ids.Contains(RoleNames.Registered)) ids.Add(RoleNames.Registered);
|
|
||||||
permissionstring.Permissions = string.Join(";", ids.ToArray());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pagemodule.Module.Permissions = UserSecurity.SetPermissionStrings(permissions);
|
if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Registered))
|
||||||
|
{
|
||||||
|
permissions.Add(new Permission(ModuleState.SiteId, EntityNames.Page, pagemodule.PageId, PermissionNames.View, RoleNames.Registered, null, true));
|
||||||
|
}
|
||||||
|
pagemodule.Module.PermissionList = permissions;
|
||||||
await ModuleService.UpdateModuleAsync(pagemodule.Module);
|
await ModuleService.UpdateModuleAsync(pagemodule.Module);
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string> Unpublish(string url, PageModule pagemodule)
|
private async Task<string> Unpublish(string url, PageModule pagemodule)
|
||||||
{
|
{
|
||||||
var permissions = UserSecurity.GetPermissionStrings(pagemodule.Module.Permissions);
|
var permissions = pagemodule.Module.PermissionList;
|
||||||
foreach (var permissionstring in permissions)
|
if (permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Everyone))
|
||||||
{
|
{
|
||||||
if (permissionstring.PermissionName == PermissionNames.View)
|
permissions.Remove(permissions.First(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Everyone));
|
||||||
{
|
|
||||||
List<string> ids = permissionstring.Permissions.Split(';').ToList();
|
|
||||||
ids.Remove(RoleNames.Everyone);
|
|
||||||
ids.Remove(RoleNames.Registered);
|
|
||||||
permissionstring.Permissions = string.Join(";", ids.ToArray());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pagemodule.Module.Permissions = UserSecurity.SetPermissionStrings(permissions);
|
if (permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Registered))
|
||||||
|
{
|
||||||
|
permissions.Remove(permissions.First(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Registered));
|
||||||
|
}
|
||||||
|
pagemodule.Module.PermissionList = permissions;
|
||||||
await ModuleService.UpdateModuleAsync(pagemodule.Module);
|
await ModuleService.UpdateModuleAsync(pagemodule.Module);
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
|
@if (_canViewAdminDashboard || UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
||||||
{
|
{
|
||||||
<button type="button" class="btn @ButtonClass" data-bs-toggle="offcanvas" data-bs-target="#offcanvasControlPanel" aria-controls="offcanvasControlPanel">
|
<button type="button" class="btn @ButtonClass" data-bs-toggle="offcanvas" data-bs-target="#offcanvasControlPanel" aria-controls="offcanvasControlPanel">
|
||||||
<span class="oi oi-cog"></span>
|
<span class="oi oi-cog"></span>
|
||||||
@ -46,16 +46,17 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="@BodyClass">
|
<div class="@BodyClass">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
@if (_canViewAdminDashboard)
|
||||||
{
|
{
|
||||||
<div class="row d-flex">
|
<div class="row d-flex">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<button type="button" data-bs-dismiss="offcanvas" class="btn btn-primary col-12" @onclick=@(async () => Navigate("Admin"))>@Localizer["AdminDash"]</button>
|
<button type="button" data-bs-dismiss="offcanvas" class="btn btn-primary col-12" @onclick=@(async () => Navigate("Admin"))>@Localizer["AdminDash"]</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="app-rule" />
|
<hr class="app-rule" />
|
||||||
|
}
|
||||||
|
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
||||||
|
{
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col text-center">
|
<div class="col text-center">
|
||||||
<label class="control-label">@Localizer["Page.Manage"] </label>
|
<label class="control-label">@Localizer["Page.Manage"] </label>
|
||||||
@ -70,7 +71,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="row d-flex">
|
<div class="row d-flex">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
@if (UserSecurity.ContainsRole(PageState.Page.Permissions, PermissionNames.View, RoleNames.Everyone))
|
@if (UserSecurity.ContainsRole(PageState.Page.PermissionList, PermissionNames.View, RoleNames.Everyone))
|
||||||
{
|
{
|
||||||
<button type="button" class="btn btn-secondary col-12" @onclick=@(async () => Publish("unpublish"))>@Localizer["Page.Unpublish"]</button>
|
<button type="button" class="btn btn-secondary col-12" @onclick=@(async () => Publish("unpublish"))>@Localizer["Page.Unpublish"]</button>
|
||||||
}
|
}
|
||||||
@ -80,144 +81,149 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
<hr class="app-rule" />
|
||||||
|
|
||||||
@if (_deleteConfirmation)
|
@if (_deleteConfirmation)
|
||||||
{
|
{
|
||||||
<div class="app-admin-modal">
|
<div class="app-admin-modal">
|
||||||
<div class="modal" tabindex="-1" role="dialog">
|
<div class="modal" tabindex="-1" role="dialog">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title">@Localizer["Page.Delete"]</h5>
|
<h5 class="modal-title">@Localizer["Page.Delete"]</h5>
|
||||||
<button type="button" class="btn-close" aria-label="Close" @onclick="ConfirmDelete"></button>
|
<button type="button" class="btn-close" aria-label="Close" @onclick="ConfirmDelete"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p>Are You Sure You Want To Delete This Page?</p>
|
<p>Are You Sure You Want To Delete This Page?</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-danger" @onclick="DeletePage">@SharedLocalizer["Delete"]</button>
|
<button type="button" class="btn btn-danger" @onclick="DeletePage">@SharedLocalizer["Delete"]</button>
|
||||||
<button type="button" class="btn btn-secondary" @onclick="ConfirmDelete">@SharedLocalizer["Cancel"]</button>
|
<button type="button" class="btn btn-secondary" @onclick="ConfirmDelete">@SharedLocalizer["Cancel"]</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
}
|
||||||
}
|
}
|
||||||
<hr class="app-rule" />
|
|
||||||
<div class="row">
|
@if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
||||||
<div class="col text-center">
|
|
||||||
<label for="Module" class="control-label">@Localizer["Module.Manage"] </label>
|
|
||||||
<select class="form-select" @bind="@ModuleType">
|
|
||||||
<option value="new">@Localizer["Module.AddNew"]</option>
|
|
||||||
<option value="existing">@Localizer["Module.AddExisting"]</option>
|
|
||||||
</select>
|
|
||||||
@if (ModuleType == "new")
|
|
||||||
{
|
|
||||||
@if (_moduleDefinitions != null)
|
|
||||||
{
|
|
||||||
<select class="form-select" @onchange="(e => CategoryChanged(e))">
|
|
||||||
@foreach (var category in _categories)
|
|
||||||
{
|
|
||||||
if (category == Category)
|
|
||||||
{
|
|
||||||
<option value="@category" selected>@category @Localizer["Modules"]</option>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<option value="@category">@category @Localizer["Modules"]</option>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
<select class="form-select" @onchange="(e => ModuleChanged(e))">
|
|
||||||
@if (ModuleDefinitionName == "-")
|
|
||||||
{
|
|
||||||
<option value="-" selected><@Localizer["Module.Select"]></option>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<option value="-"><@Localizer["Module.Select"]></option>
|
|
||||||
}
|
|
||||||
@foreach (var moduledefinition in _moduleDefinitions)
|
|
||||||
{
|
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Utilize, moduledefinition.Permissions))
|
|
||||||
{
|
|
||||||
if (moduledefinition.Runtimes == "" || moduledefinition.Runtimes.Contains(PageState.Runtime.ToString()))
|
|
||||||
{
|
|
||||||
<option value="@moduledefinition.ModuleDefinitionName">@moduledefinition.Name</option>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<select class="form-select" @onchange="(e => PageChanged(e))">
|
|
||||||
<option value="-"><@Localizer["Page.Select"]></option>
|
|
||||||
@foreach (Page p in _pages)
|
|
||||||
{
|
|
||||||
<option value="@p.PageId">@p.Name</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
<select class="form-select" @bind="@ModuleId">
|
|
||||||
<option value="-"><@Localizer["Module.Select"]></option>
|
|
||||||
@foreach (Module module in _modules)
|
|
||||||
{
|
|
||||||
<option value="@module.ModuleId">@module.Title</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col text-center">
|
|
||||||
<label for="Title" class="control-label">@Localizer["Title"] </label>
|
|
||||||
<input type="text" name="Title" class="form-control" @bind="@Title" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@if (_pane.Length > 1)
|
|
||||||
{
|
{
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col text-center">
|
<div class="col text-center">
|
||||||
<label for="Pane" class="control-label">@Localizer["Pane"] </label>
|
<label for="Module" class="control-label">@Localizer["Module.Manage"] </label>
|
||||||
<select class="form-select" @bind="@Pane">
|
<select class="form-select" @bind="@ModuleType">
|
||||||
@foreach (string pane in PageState.Page.Panes)
|
<option value="new">@Localizer["Module.AddNew"]</option>
|
||||||
|
<option value="existing">@Localizer["Module.AddExisting"]</option>
|
||||||
|
</select>
|
||||||
|
@if (ModuleType == "new")
|
||||||
|
{
|
||||||
|
@if (_moduleDefinitions != null)
|
||||||
{
|
{
|
||||||
<option value="@pane">@pane Pane</option>
|
<select class="form-select" @onchange="(e => CategoryChanged(e))">
|
||||||
|
@foreach (var category in _categories)
|
||||||
|
{
|
||||||
|
if (category == Category)
|
||||||
|
{
|
||||||
|
<option value="@category" selected>@category @Localizer["Modules"]</option>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<option value="@category">@category @Localizer["Modules"]</option>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
<select class="form-select" @onchange="(e => ModuleChanged(e))">
|
||||||
|
@if (ModuleDefinitionName == "-")
|
||||||
|
{
|
||||||
|
<option value="-" selected><@Localizer["Module.Select"]></option>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<option value="-"><@Localizer["Module.Select"]></option>
|
||||||
|
}
|
||||||
|
@foreach (var moduledefinition in _moduleDefinitions)
|
||||||
|
{
|
||||||
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Utilize, moduledefinition.PermissionList))
|
||||||
|
{
|
||||||
|
if (moduledefinition.Runtimes == "" || moduledefinition.Runtimes.Contains(PageState.Runtime.ToString()))
|
||||||
|
{
|
||||||
|
<option value="@moduledefinition.ModuleDefinitionName">@moduledefinition.Name</option>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<select class="form-select" @onchange="(e => PageChanged(e))">
|
||||||
|
<option value="-"><@Localizer["Page.Select"]></option>
|
||||||
|
@foreach (Page p in _pages)
|
||||||
|
{
|
||||||
|
<option value="@p.PageId">@p.Name</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
<select class="form-select" @bind="@ModuleId">
|
||||||
|
<option value="-"><@Localizer["Module.Select"]></option>
|
||||||
|
@foreach (Module module in _modules)
|
||||||
|
{
|
||||||
|
<option value="@module.ModuleId">@module.Title</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col text-center">
|
||||||
|
<label for="Title" class="control-label">@Localizer["Title"] </label>
|
||||||
|
<input type="text" name="Title" class="form-control" @bind="@Title" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if (_pane.Length > 1)
|
||||||
|
{
|
||||||
|
<div class="row">
|
||||||
|
<div class="col text-center">
|
||||||
|
<label for="Pane" class="control-label">@Localizer["Pane"] </label>
|
||||||
|
<select class="form-select" @bind="@Pane">
|
||||||
|
@foreach (string pane in PageState.Page.Panes)
|
||||||
|
{
|
||||||
|
<option value="@pane">@pane Pane</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col text-center">
|
||||||
|
<label for="Container" class="control-label">@Localizer["Container"] </label>
|
||||||
|
<select class="form-select" @bind="@ContainerType">
|
||||||
|
@foreach (var container in _containers)
|
||||||
|
{
|
||||||
|
<option value="@container.TypeName">@container.Name</option>
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col text-center">
|
||||||
|
<label for="visibility" class="control-label">@Localizer["Visibility"]</label>
|
||||||
|
<select class="form-select" @bind="@Visibility">
|
||||||
|
<option value="view">@Localizer["VisibilityView"]</option>
|
||||||
|
<option value="edit">@Localizer["VisibilityEdit"]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-primary col-12 mt-4" @onclick="@AddModule">@Localizer["Page.Module.Add"]</button>
|
||||||
|
@((MarkupString)Message)
|
||||||
}
|
}
|
||||||
<div class="row">
|
|
||||||
<div class="col text-center">
|
|
||||||
<label for="Container" class="control-label">@Localizer["Container"] </label>
|
|
||||||
<select class="form-select" @bind="@ContainerType">
|
|
||||||
@foreach (var container in _containers)
|
|
||||||
{
|
|
||||||
<option value="@container.TypeName">@container.Name</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col text-center">
|
|
||||||
<label for="visibility" class="control-label">@Localizer["Visibility"]</label>
|
|
||||||
<select class="form-select" @bind="@Visibility">
|
|
||||||
<option value="edit" selected>@Localizer["VisibilityEdit"]</option>
|
|
||||||
<option value="view">@Localizer["VisibilityView"]</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button type="button" class="btn btn-primary col-12 mt-4" @onclick="@AddModule">@Localizer["Page.Module.Add"]</button>
|
|
||||||
@((MarkupString) Message)
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@code{
|
@code{
|
||||||
|
private bool _canViewAdminDashboard = false;
|
||||||
private bool _showEditMode = false;
|
private bool _showEditMode = false;
|
||||||
private bool _deleteConfirmation = false;
|
private bool _deleteConfirmation = false;
|
||||||
private List<string> _categories = new List<string>();
|
private List<string> _categories = new List<string>();
|
||||||
@ -265,7 +271,7 @@
|
|||||||
|
|
||||||
protected string Title { get; private set; } = "";
|
protected string Title { get; private set; } = "";
|
||||||
protected string ContainerType { get; private set; } = "";
|
protected string ContainerType { get; private set; } = "";
|
||||||
protected string Visibility { get; private set; } = "edit";
|
protected string Visibility { get; private set; } = "view";
|
||||||
protected string Message { get; private set; } = "";
|
protected string Message { get; private set; } = "";
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
@ -286,15 +292,16 @@
|
|||||||
|
|
||||||
protected override async Task OnParametersSetAsync()
|
protected override async Task OnParametersSetAsync()
|
||||||
{
|
{
|
||||||
|
_canViewAdminDashboard = CanViewAdminDashboard();
|
||||||
_showEditMode = false;
|
_showEditMode = false;
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
||||||
{
|
{
|
||||||
_showEditMode = true;
|
_showEditMode = true;
|
||||||
_pages?.Clear();
|
_pages?.Clear();
|
||||||
|
|
||||||
foreach (Page p in PageState.Pages)
|
foreach (Page p in PageState.Pages)
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||||
{
|
{
|
||||||
_pages.Add(p);
|
_pages.Add(p);
|
||||||
}
|
}
|
||||||
@ -312,7 +319,7 @@
|
|||||||
{
|
{
|
||||||
foreach (var module in PageState.Modules.Where(item => item.PageId == PageState.Page.PageId))
|
foreach (var module in PageState.Modules.Where(item => item.PageId == PageState.Page.PageId))
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, module.Permissions))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, module.PermissionList))
|
||||||
{
|
{
|
||||||
_showEditMode = true;
|
_showEditMode = true;
|
||||||
break;
|
break;
|
||||||
@ -321,6 +328,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool CanViewAdminDashboard()
|
||||||
|
{
|
||||||
|
var admin = PageState.Pages.FirstOrDefault(item => item.Path == "admin");
|
||||||
|
if (admin != null)
|
||||||
|
{
|
||||||
|
foreach (var page in PageState.Pages.Where(item => item.ParentId == admin?.PageId))
|
||||||
|
{
|
||||||
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.PermissionList))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private void CategoryChanged(ChangeEventArgs e)
|
private void CategoryChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
Category = (string)e.Value;
|
Category = (string)e.Value;
|
||||||
@ -348,7 +371,7 @@
|
|||||||
{
|
{
|
||||||
_modules = PageState.Modules
|
_modules = PageState.Modules
|
||||||
.Where(module => module.PageId == int.Parse(PageId) &&
|
.Where(module => module.PageId == int.Parse(PageId) &&
|
||||||
UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions))
|
UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.PermissionList))
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
ModuleId = "-";
|
ModuleId = "-";
|
||||||
@ -357,7 +380,7 @@
|
|||||||
|
|
||||||
private async Task AddModule()
|
private async Task AddModule()
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
||||||
{
|
{
|
||||||
if ((ModuleType == "new" && ModuleDefinitionName != "-") || (ModuleType != "new" && ModuleId != "-"))
|
if ((ModuleType == "new" && ModuleDefinitionName != "-") || (ModuleType != "new" && ModuleId != "-"))
|
||||||
{
|
{
|
||||||
@ -369,18 +392,20 @@
|
|||||||
module.ModuleDefinitionName = ModuleDefinitionName;
|
module.ModuleDefinitionName = ModuleDefinitionName;
|
||||||
module.AllPages = false;
|
module.AllPages = false;
|
||||||
|
|
||||||
List<PermissionString> permissions = UserSecurity.GetPermissionStrings(PageState.Page.Permissions);
|
var permissions = new List<Permission>();
|
||||||
if (Visibility == "view")
|
if (Visibility == "view")
|
||||||
{
|
{
|
||||||
// set module view permissions to page view permissions
|
// set module view permissions to page view permissions
|
||||||
permissions.Find(p => p.PermissionName == PermissionNames.View).Permissions = permissions.Find(p => p.PermissionName == PermissionNames.View).Permissions;
|
permissions = SetPermissions(permissions, module.SiteId, PermissionNames.View, PermissionNames.View);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// set module view permissions to page edit permissions
|
// set module view permissions to page edit permissions
|
||||||
permissions.Find(p => p.PermissionName == PermissionNames.View).Permissions = permissions.Find(p => p.PermissionName == PermissionNames.Edit).Permissions;
|
permissions = SetPermissions(permissions, module.SiteId, PermissionNames.View, PermissionNames.Edit);
|
||||||
}
|
}
|
||||||
module.Permissions = UserSecurity.SetPermissionStrings(permissions);
|
// set module edit permissions to page edit permissions
|
||||||
|
permissions = SetPermissions(permissions, module.SiteId, PermissionNames.Edit, PermissionNames.Edit);
|
||||||
|
module.PermissionList = permissions;
|
||||||
|
|
||||||
module = await ModuleService.AddModuleAsync(module);
|
module = await ModuleService.AddModuleAsync(module);
|
||||||
ModuleId = module.ModuleId.ToString();
|
ModuleId = module.ModuleId.ToString();
|
||||||
@ -431,6 +456,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Permission> SetPermissions(List<Permission> permissions, int siteId, string modulePermission, string pagePermission)
|
||||||
|
{
|
||||||
|
foreach (var permission in PageState.Page.PermissionList.Where(item => item.PermissionName == pagePermission))
|
||||||
|
{
|
||||||
|
permissions.Add(new Permission { SiteId = siteId, EntityName = EntityNames.Module, PermissionName = modulePermission, RoleId = permission.RoleId, UserId = permission.UserId, IsAuthorized = permission.IsAuthorized });
|
||||||
|
}
|
||||||
|
return permissions;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ToggleEditMode(bool EditMode)
|
private async Task ToggleEditMode(bool EditMode)
|
||||||
{
|
{
|
||||||
if (_showEditMode)
|
if (_showEditMode)
|
||||||
@ -444,7 +478,7 @@
|
|||||||
PageState.EditMode = true;
|
PageState.EditMode = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, "edit=" + ((PageState.EditMode) ? "1" : "0")));
|
NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, "edit=" + ((PageState.EditMode) ? "true" : "false")));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -452,7 +486,7 @@
|
|||||||
{
|
{
|
||||||
await PageService.AddPageAsync(PageState.Page.PageId, PageState.User.UserId);
|
await PageService.AddPageAsync(PageState.Page.PageId, PageState.User.UserId);
|
||||||
PageState.EditMode = true;
|
PageState.EditMode = true;
|
||||||
NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, "edit=" + ((PageState.EditMode) ? "1" : "0")));
|
NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, "edit=" + ((PageState.EditMode) ? "true" : "false")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -465,12 +499,10 @@
|
|||||||
case "Admin":
|
case "Admin":
|
||||||
// get admin dashboard moduleid
|
// get admin dashboard moduleid
|
||||||
module = PageState.Modules.FirstOrDefault(item => item.ModuleDefinitionName == Constants.AdminDashboardModule);
|
module = PageState.Modules.FirstOrDefault(item => item.ModuleDefinitionName == Constants.AdminDashboardModule);
|
||||||
|
|
||||||
if (module != null)
|
if (module != null)
|
||||||
{
|
{
|
||||||
NavigationManager.NavigateTo(EditUrl(PageState.Page.Path, module.ModuleId, "Index", ""));
|
NavigationManager.NavigateTo(EditUrl(PageState.Page.Path, module.ModuleId, "Index", ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "Add":
|
case "Add":
|
||||||
case "Edit":
|
case "Edit":
|
||||||
@ -502,34 +534,19 @@
|
|||||||
|
|
||||||
private async void Publish(string action)
|
private async void Publish(string action)
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
|
||||||
{
|
{
|
||||||
List<PermissionString> permissions;
|
var permissions = PageState.Page.PermissionList;
|
||||||
|
if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Everyone))
|
||||||
// publish/unpublish page
|
{
|
||||||
var page = PageState.Page;
|
permissions.Add(new Permission(PageState.Site.SiteId, EntityNames.Page, PageState.Page.PageId, PermissionNames.View, RoleNames.Everyone, null, true));
|
||||||
permissions = UserSecurity.GetPermissionStrings(page.Permissions);
|
}
|
||||||
foreach (var permissionstring in permissions)
|
if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Registered))
|
||||||
{
|
{
|
||||||
if (permissionstring.PermissionName == PermissionNames.View)
|
permissions.Add(new Permission(PageState.Site.SiteId, EntityNames.Page, PageState.Page.PageId, PermissionNames.View, RoleNames.Registered, null, true));
|
||||||
{
|
}
|
||||||
List<string> ids = permissionstring.Permissions.Split(';').ToList();
|
PageState.Page.PermissionList = permissions;
|
||||||
switch (action)
|
await PageService.UpdatePageAsync(PageState.Page);
|
||||||
{
|
|
||||||
case "publish":
|
|
||||||
if (!ids.Contains(RoleNames.Everyone)) ids.Add(RoleNames.Everyone);
|
|
||||||
if (!ids.Contains(RoleNames.Registered)) ids.Add(RoleNames.Registered);
|
|
||||||
break;
|
|
||||||
case "unpublish":
|
|
||||||
ids.Remove(RoleNames.Everyone);
|
|
||||||
ids.Remove(RoleNames.Registered);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
permissionstring.Permissions = string.Join(";", ids.ToArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
page.Permissions = UserSecurity.SetPermissionStrings(permissions);
|
|
||||||
await PageService.UpdatePageAsync(page);
|
|
||||||
NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, true));
|
NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -551,19 +568,19 @@
|
|||||||
{
|
{
|
||||||
page.IsDeleted = true;
|
page.IsDeleted = true;
|
||||||
await PageService.UpdatePageAsync(page);
|
await PageService.UpdatePageAsync(page);
|
||||||
await logger.Log(page.PageId, null, PageState.User.UserId, GetType().AssemblyQualifiedName, "ControlPanel", LogFunction.Delete, LogLevel.Information, null, "Page Deleted {Page}", page);
|
await logger.Log(page.PageId, null, PageState.User?.UserId, GetType().AssemblyQualifiedName, "ControlPanel", LogFunction.Delete, LogLevel.Information, null, "Page Deleted {Page}", page);
|
||||||
NavigationManager.NavigateTo(NavigateUrl(""));
|
NavigationManager.NavigateTo(NavigateUrl(""));
|
||||||
}
|
}
|
||||||
else // personalized page
|
else // personalized page
|
||||||
{
|
{
|
||||||
await PageService.DeletePageAsync(page.PageId);
|
await PageService.DeletePageAsync(page.PageId);
|
||||||
await logger.Log(page.PageId, null, PageState.User.UserId, GetType().AssemblyQualifiedName, "ControlPanel", LogFunction.Delete, LogLevel.Information, null, "Page Deleted {Page}", page);
|
await logger.Log(page.PageId, null, PageState.User?.UserId, GetType().AssemblyQualifiedName, "ControlPanel", LogFunction.Delete, LogLevel.Information, null, "Page Deleted {Page}", page);
|
||||||
NavigationManager.NavigateTo(NavigateUrl());
|
NavigationManager.NavigateTo(NavigateUrl());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.Log(page.PageId, null, PageState.User.UserId, GetType().AssemblyQualifiedName, "ControlPanel", LogFunction.Delete, LogLevel.Information, ex, "Page Deleted {Page} {Error}", page, ex.Message);
|
await logger.Log(page.PageId, null, PageState.User?.UserId, GetType().AssemblyQualifiedName, "ControlPanel", LogFunction.Delete, LogLevel.Information, ex, "Page Deleted {Page} {Error}", page, ex.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -596,8 +613,8 @@
|
|||||||
private async Task UpdateSettingsAsync()
|
private async Task UpdateSettingsAsync()
|
||||||
{
|
{
|
||||||
Dictionary<string, string> settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
|
Dictionary<string, string> settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
|
||||||
SettingService.SetSetting(settings, settingCategory, _category);
|
settings = SettingService.SetSetting(settings, settingCategory, _category);
|
||||||
SettingService.SetSetting(settings, settingPane, _pane);
|
settings = SettingService.SetSetting(settings, settingPane, _pane);
|
||||||
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
|
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.JSInterop;
|
using Microsoft.JSInterop;
|
||||||
using Oqtane.Enums;
|
using Oqtane.Enums;
|
||||||
|
using Oqtane.Models;
|
||||||
using Oqtane.Providers;
|
using Oqtane.Providers;
|
||||||
using Oqtane.Security;
|
using Oqtane.Security;
|
||||||
using Oqtane.Services;
|
using Oqtane.Services;
|
||||||
@ -22,21 +24,19 @@ namespace Oqtane.Themes.Controls
|
|||||||
|
|
||||||
protected void LoginUser()
|
protected void LoginUser()
|
||||||
{
|
{
|
||||||
var returnurl = PageState.Alias.Path;
|
Route route = new Route(PageState.Uri.AbsoluteUri, PageState.Alias.Path);
|
||||||
if (PageState.Page.Path != "/")
|
NavigationManager.NavigateTo(NavigateUrl("login", "?returnurl=" + WebUtility.UrlEncode(route.PathAndQuery)));
|
||||||
{
|
|
||||||
returnurl += "/" + PageState.Page.Path;
|
|
||||||
}
|
|
||||||
NavigationManager.NavigateTo(NavigateUrl("login", "?returnurl=" + returnurl));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task LogoutUser()
|
protected async Task LogoutUser()
|
||||||
{
|
{
|
||||||
await LoggingService.Log(PageState.Alias, PageState.Page.PageId, null, PageState.User.UserId, GetType().AssemblyQualifiedName, "Logout", LogFunction.Security, LogLevel.Information, null, "User Logout For Username {Username}", PageState.User.Username);
|
await LoggingService.Log(PageState.Alias, PageState.Page.PageId, null, PageState.User?.UserId, GetType().AssemblyQualifiedName, "Logout", LogFunction.Security, LogLevel.Information, null, "User Logout For Username {Username}", PageState.User?.Username);
|
||||||
|
|
||||||
// check if anonymous user can access page
|
Route route = new Route(PageState.Uri.AbsoluteUri, PageState.Alias.Path);
|
||||||
var url = PageState.Alias.Path + "/" + PageState.Page.Path;
|
var url = route.PathAndQuery;
|
||||||
if (!UserSecurity.IsAuthorized(null, PermissionNames.View, PageState.Page.Permissions))
|
|
||||||
|
// verify if anonymous users can access page
|
||||||
|
if (!UserSecurity.IsAuthorized(null, PermissionNames.View, PageState.Page.PermissionList))
|
||||||
{
|
{
|
||||||
url = PageState.Alias.Path;
|
url = PageState.Alias.Path;
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ namespace Oqtane.Themes.Controls
|
|||||||
var securityLevel = int.MaxValue;
|
var securityLevel = int.MaxValue;
|
||||||
foreach (Page p in PageState.Pages.Where(item => item.IsNavigation))
|
foreach (Page p in PageState.Pages.Where(item => item.IsNavigation))
|
||||||
{
|
{
|
||||||
if (p.Level <= securityLevel && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
|
if (p.Level <= securityLevel && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
|
||||||
{
|
{
|
||||||
securityLevel = int.MaxValue;
|
securityLevel = int.MaxValue;
|
||||||
yield return p;
|
yield return p;
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
<div class="app-menu navbar-expand-md">
|
<div class="app-menu navbar-expand-md">
|
||||||
<div class="collapse navbar-collapse" id="Menu">
|
<div class="collapse navbar-collapse navbar-nav-scroll" id="Menu">
|
||||||
<MenuItemsHorizontal ParentPage="null" Pages="MenuPages" />
|
<MenuItemsHorizontal ParentPage="null" Pages="MenuPages" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -32,15 +32,24 @@ namespace Oqtane.Themes
|
|||||||
{
|
{
|
||||||
if (Resources != null && Resources.Exists(item => item.ResourceType == ResourceType.Script))
|
if (Resources != null && Resources.Exists(item => item.ResourceType == ResourceType.Script))
|
||||||
{
|
{
|
||||||
|
var interop = new Interop(JSRuntime);
|
||||||
var scripts = new List<object>();
|
var scripts = new List<object>();
|
||||||
|
var inline = 0;
|
||||||
foreach (Resource resource in Resources.Where(item => item.ResourceType == ResourceType.Script))
|
foreach (Resource resource in Resources.Where(item => item.ResourceType == ResourceType.Script))
|
||||||
{
|
{
|
||||||
var url = (resource.Url.Contains("://")) ? resource.Url : PageState.Alias.BaseUrl + resource.Url;
|
if (!string.IsNullOrEmpty(resource.Url))
|
||||||
scripts.Add(new { href = url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", es6module = resource.ES6Module });
|
{
|
||||||
|
var url = (resource.Url.Contains("://")) ? resource.Url : PageState.Alias.BaseUrl + resource.Url;
|
||||||
|
scripts.Add(new { href = url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", es6module = resource.ES6Module });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inline += 1;
|
||||||
|
await interop.IncludeScript(GetType().Namespace.ToLower() + inline.ToString(), "", "", "", resource.Content, resource.Location.ToString().ToLower());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (scripts.Any())
|
if (scripts.Any())
|
||||||
{
|
{
|
||||||
var interop = new Interop(JSRuntime);
|
|
||||||
await interop.IncludeScripts(scripts.ToArray());
|
await interop.IncludeScripts(scripts.ToArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
container = (!string.IsNullOrEmpty(PageState.Site.AdminContainerType)) ? PageState.Site.AdminContainerType : Constants.DefaultAdminContainer;
|
container = (!string.IsNullOrEmpty(PageState.Site.AdminContainerType)) ? PageState.Site.AdminContainerType : Constants.DefaultAdminContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions) && PageState.Action == Constants.DefaultAction)
|
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList) && PageState.Action == Constants.DefaultAction)
|
||||||
{
|
{
|
||||||
_useadminborder = true;
|
_useadminborder = true;
|
||||||
}
|
}
|
||||||
|
@ -60,13 +60,13 @@ namespace Oqtane.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task IncludeMeta(string id, string attribute, string name, string content, string key)
|
public Task IncludeMeta(string id, string attribute, string name, string content)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_jsRuntime.InvokeVoidAsync(
|
_jsRuntime.InvokeVoidAsync(
|
||||||
"Oqtane.Interop.includeMeta",
|
"Oqtane.Interop.includeMeta",
|
||||||
id, attribute, name, content, key);
|
id, attribute, name, content);
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -105,6 +105,7 @@ namespace Oqtane.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// external scripts need to specify src, inline scripts need to specify id and content
|
||||||
public Task IncludeScript(string id, string src, string integrity, string crossorigin, string content, string location)
|
public Task IncludeScript(string id, string src, string integrity, string crossorigin, string content, string location)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -87,10 +87,9 @@ else
|
|||||||
// retrieve friendly localized error
|
// retrieve friendly localized error
|
||||||
_error = Localizer["Error.Module.Exception"];
|
_error = Localizer["Error.Module.Exception"];
|
||||||
// log error
|
// log error
|
||||||
int? userId = (PageState.User != null) ? PageState.User.UserId : null;
|
|
||||||
string category = GetType().AssemblyQualifiedName;
|
string category = GetType().AssemblyQualifiedName;
|
||||||
string feature = Utilities.GetTypeNameLastSegment(category, 1);
|
string feature = Utilities.GetTypeNameLastSegment(category, 1);
|
||||||
await LoggingService.Log(null, ModuleState.PageId, ModuleState.ModuleId, userId, category, feature, LogFunction.Other, LogLevel.Error, exception, "An Unexpected Error Has Occurred In {ModuleDefinitionName}: {Error}", ModuleState.ModuleDefinitionName, exception.Message);
|
await LoggingService.Log(null, ModuleState.PageId, ModuleState.ModuleId, PageState.User?.UserId, category, feature, LogFunction.Other, LogLevel.Error, exception, "An Unexpected Error Has Occurred In {ModuleDefinitionName}: {Error}", ModuleState.ModuleDefinitionName, exception.Message);
|
||||||
await base.OnErrorAsync(exception);
|
await base.OnErrorAsync(exception);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ else
|
|||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions) && PageState.Action == Constants.DefaultAction)
|
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList) && PageState.Action == Constants.DefaultAction)
|
||||||
{
|
{
|
||||||
_useadminborder = true;
|
_useadminborder = true;
|
||||||
_panetitle = "<div class=\"app-pane-admin-title\">" + Name + " Pane</div>";
|
_panetitle = "<div class=\"app-pane-admin-title\">" + Name + " Pane</div>";
|
||||||
@ -58,7 +58,11 @@ else
|
|||||||
}
|
}
|
||||||
if (Name.ToLower() == pane.ToLower())
|
if (Name.ToLower() == pane.ToLower())
|
||||||
{
|
{
|
||||||
Module module = PageState.Modules.FirstOrDefault(item => item.ModuleId == PageState.ModuleId);
|
Module module = PageState.Modules.FirstOrDefault(item => item.PageId == PageState.Page.PageId && item.ModuleId == PageState.ModuleId);
|
||||||
|
if (module == null)
|
||||||
|
{
|
||||||
|
module = PageState.Modules.FirstOrDefault(item => item.ModuleId == PageState.ModuleId);
|
||||||
|
}
|
||||||
if (module != null)
|
if (module != null)
|
||||||
{
|
{
|
||||||
var moduleType = Type.GetType(module.ModuleType);
|
var moduleType = Type.GetType(module.ModuleType);
|
||||||
@ -67,7 +71,7 @@ else
|
|||||||
bool authorized = false;
|
bool authorized = false;
|
||||||
if (Constants.DefaultModuleActions.Contains(PageState.Action))
|
if (Constants.DefaultModuleActions.Contains(PageState.Action))
|
||||||
{
|
{
|
||||||
authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions);
|
authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -77,10 +81,10 @@ else
|
|||||||
authorized = true;
|
authorized = true;
|
||||||
break;
|
break;
|
||||||
case SecurityAccessLevel.View:
|
case SecurityAccessLevel.View:
|
||||||
authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions);
|
authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.PermissionList);
|
||||||
break;
|
break;
|
||||||
case SecurityAccessLevel.Edit:
|
case SecurityAccessLevel.Edit:
|
||||||
authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, module.Permissions);
|
authorized = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, module.PermissionList);
|
||||||
break;
|
break;
|
||||||
case SecurityAccessLevel.Admin:
|
case SecurityAccessLevel.Admin:
|
||||||
authorized = UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin);
|
authorized = UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin);
|
||||||
@ -107,11 +111,15 @@ else
|
|||||||
{
|
{
|
||||||
if (PageState.ModuleId != -1)
|
if (PageState.ModuleId != -1)
|
||||||
{
|
{
|
||||||
Module module = PageState.Modules.FirstOrDefault(item => item.ModuleId == PageState.ModuleId);
|
Module module = PageState.Modules.FirstOrDefault(item => item.PageId == PageState.Page.PageId && item.ModuleId == PageState.ModuleId);
|
||||||
if (module != null && module.Pane.ToLower() == Name.ToLower())
|
if (module == null)
|
||||||
|
{
|
||||||
|
module = PageState.Modules.FirstOrDefault(item => item.ModuleId == PageState.ModuleId);
|
||||||
|
}
|
||||||
|
if (module != null && module.Pane.ToLower() == Name.ToLower())
|
||||||
{
|
{
|
||||||
// check if user is authorized to view module
|
// check if user is authorized to view module
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.PermissionList))
|
||||||
{
|
{
|
||||||
CreateComponent(builder, module);
|
CreateComponent(builder, module);
|
||||||
}
|
}
|
||||||
@ -119,10 +127,10 @@ else
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (Module module in PageState.Modules.Where(item => item.PageId == PageState.Page.PageId && item.Pane.ToLower() == Name.ToLower()).OrderBy(x => x.Order).ToArray())
|
foreach (Module module in PageState.Modules.Where(item => item.PageId == PageState.Page.PageId && item.Pane.ToLower() == Name.ToLower()))
|
||||||
{
|
{
|
||||||
// check if user is authorized to view module
|
// check if user is authorized to view module
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions))
|
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.PermissionList))
|
||||||
{
|
{
|
||||||
CreateComponent(builder, module);
|
CreateComponent(builder, module);
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@
|
|||||||
// reload the client application from the server if there is a forced reload or the user navigated to a site with a different alias
|
// reload the client application from the server if there is a forced reload or the user navigated to a site with a different alias
|
||||||
if (querystring.ContainsKey("reload") || (!NavigationManager.ToBaseRelativePath(_absoluteUri).ToLower().StartsWith(SiteState.Alias.Path.ToLower()) && !string.IsNullOrEmpty(SiteState.Alias.Path)))
|
if (querystring.ContainsKey("reload") || (!NavigationManager.ToBaseRelativePath(_absoluteUri).ToLower().StartsWith(SiteState.Alias.Path.ToLower()) && !string.IsNullOrEmpty(SiteState.Alias.Path)))
|
||||||
{
|
{
|
||||||
if (querystring["reload"] == "post")
|
if (querystring.ContainsKey("reload") && querystring["reload"] == "post")
|
||||||
{
|
{
|
||||||
// post back so that the cookies are set correctly - required on any change to the principal
|
// post back so that the cookies are set correctly - required on any change to the principal
|
||||||
var interop = new Interop(JSRuntime);
|
var interop = new Interop(JSRuntime);
|
||||||
@ -124,6 +124,10 @@
|
|||||||
editmode = PageState.EditMode;
|
editmode = PageState.EditMode;
|
||||||
lastsyncdate = PageState.LastSyncDate;
|
lastsyncdate = PageState.LastSyncDate;
|
||||||
}
|
}
|
||||||
|
if (PageState?.Page.Path != route.PagePath)
|
||||||
|
{
|
||||||
|
editmode = false; // reset edit mode when navigating to different page
|
||||||
|
}
|
||||||
|
|
||||||
// get user
|
// get user
|
||||||
if (PageState == null || refresh || PageState.Alias.SiteId != SiteState.Alias.SiteId)
|
if (PageState == null || refresh || PageState.Alias.SiteId != SiteState.Alias.SiteId)
|
||||||
@ -181,7 +185,6 @@
|
|||||||
if (PageState == null || refresh || PageState.Page.Path != route.PagePath)
|
if (PageState == null || refresh || PageState.Page.Path != route.PagePath)
|
||||||
{
|
{
|
||||||
page = site.Pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase));
|
page = site.Pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase));
|
||||||
editmode = false;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -204,7 +207,7 @@
|
|||||||
if (page != null)
|
if (page != null)
|
||||||
{
|
{
|
||||||
// check if user is authorized to view page
|
// check if user is authorized to view page
|
||||||
if (UserSecurity.IsAuthorized(user, PermissionNames.View, page.Permissions))
|
if (UserSecurity.IsAuthorized(user, PermissionNames.View, page.PermissionList))
|
||||||
{
|
{
|
||||||
// load additional metadata for current page
|
// load additional metadata for current page
|
||||||
page = await ProcessPage(page, site, user);
|
page = await ProcessPage(page, site, user);
|
||||||
@ -250,7 +253,7 @@
|
|||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
// redirect to login page if user not logged in as they may need to be authenticated
|
// redirect to login page if user not logged in as they may need to be authenticated
|
||||||
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "login", "?returnurl=" + route.AbsolutePath));
|
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "login", "?returnurl=" + WebUtility.UrlEncode(route.PathAndQuery)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -299,18 +302,24 @@
|
|||||||
{
|
{
|
||||||
query = query.Substring(1); // ignore "?"
|
query = query.Substring(1); // ignore "?"
|
||||||
}
|
}
|
||||||
foreach (string kvp in query.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries))
|
foreach (string kvp in query.Split('&', StringSplitOptions.RemoveEmptyEntries))
|
||||||
{
|
{
|
||||||
if (kvp != "")
|
if (kvp != "")
|
||||||
{
|
{
|
||||||
if (kvp.Contains("="))
|
if (kvp.Contains("="))
|
||||||
{
|
{
|
||||||
string[] pair = kvp.Split('=');
|
string[] pair = kvp.Split('=');
|
||||||
querystring.Add(pair[0], pair[1]);
|
if (!querystring.ContainsKey(pair[0]))
|
||||||
|
{
|
||||||
|
querystring.Add(pair[0], pair[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
querystring.Add(kvp, "true"); // default parameter when no value is provided
|
if (!querystring.ContainsKey(kvp))
|
||||||
|
{
|
||||||
|
querystring.Add(kvp, "true"); // default parameter when no value is provided
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -358,7 +367,7 @@
|
|||||||
}
|
}
|
||||||
if (!string.IsNullOrEmpty(panes))
|
if (!string.IsNullOrEmpty(panes))
|
||||||
{
|
{
|
||||||
page.Panes = panes.Replace(";", ",").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
page.Panes = panes.Replace(";", ",").Split(',', StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||||
if (!page.Panes.Contains(PaneNames.Default) && !page.Panes.Contains(PaneNames.Admin))
|
if (!page.Panes.Contains(PaneNames.Default) && !page.Panes.Contains(PaneNames.Admin))
|
||||||
{
|
{
|
||||||
_error = "The Current Theme Does Not Contain A Default Or Admin Pane";
|
_error = "The Current Theme Does Not Contain A Default Or Admin Pane";
|
||||||
@ -407,7 +416,7 @@
|
|||||||
// check if the module defines custom action routes
|
// check if the module defines custom action routes
|
||||||
if (module.ModuleDefinition.ControlTypeRoutes != "")
|
if (module.ModuleDefinition.ControlTypeRoutes != "")
|
||||||
{
|
{
|
||||||
foreach (string route in module.ModuleDefinition.ControlTypeRoutes.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
|
foreach (string route in module.ModuleDefinition.ControlTypeRoutes.Split(';', StringSplitOptions.RemoveEmptyEntries))
|
||||||
{
|
{
|
||||||
if (route.StartsWith(action + "="))
|
if (route.StartsWith(action + "="))
|
||||||
{
|
{
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<Version>3.2.1</Version>
|
<Version>3.4.3</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.2.1</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.3</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>Oqtane.Database.MySQL</id>
|
<id>Oqtane.Database.MySQL</id>
|
||||||
<version>3.2.1</version>
|
<version>3.4.3</version>
|
||||||
<authors>Shaun Walker</authors>
|
<authors>Shaun Walker</authors>
|
||||||
<owners>.NET Foundation</owners>
|
<owners>.NET Foundation</owners>
|
||||||
<title>Oqtane MySQL Provider</title>
|
<title>Oqtane MySQL Provider</title>
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||||
<license type="expression">MIT</license>
|
<license type="expression">MIT</license>
|
||||||
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
|
||||||
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.2.1</releaseNotes>
|
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.3</releaseNotes>
|
||||||
<icon>icon.png</icon>
|
<icon>icon.png</icon>
|
||||||
<tags>oqtane</tags>
|
<tags>oqtane</tags>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<Version>3.2.1</Version>
|
<Version>3.4.3</Version>
|
||||||
<Product>Oqtane</Product>
|
<Product>Oqtane</Product>
|
||||||
<Authors>Shaun Walker</Authors>
|
<Authors>Shaun Walker</Authors>
|
||||||
<Company>.NET Foundation</Company>
|
<Company>.NET Foundation</Company>
|
||||||
@ -10,7 +10,7 @@
|
|||||||
<Copyright>.NET Foundation</Copyright>
|
<Copyright>.NET Foundation</Copyright>
|
||||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.2.1</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v3.4.3</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||||
<RepositoryType>Git</RepositoryType>
|
<RepositoryType>Git</RepositoryType>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user