Compare commits

...

129 Commits

Author SHA1 Message Date
a5ccc23604 Revert "Fix for Tabpanel is not updating the UI. #4778" 2024-11-26 13:36:05 -05:00
1ed4c8a094 Merge pull request #4874 from oqtane/revert-4871-HTMLTabError
Revert "Rework for Tabstrip regression issue"
2024-11-26 13:35:37 -05:00
4a74549c1b Revert "Rework for Tabstrip regression issue" 2024-11-26 13:35:21 -05:00
a499cfb98f Merge pull request #4871 from leigh-pointer/HTMLTabError
Rework for Tabstrip regression issue
2024-11-26 11:27:52 -05:00
01038c8296 Merge pull request #4873 from sbwalker/dev
include SECURITY.md
2024-11-26 11:25:35 -05:00
7407f79b3d include SECURITY.md 2024-11-26 11:25:23 -05:00
a845dd1976 Rework for Tabstrip regression issue
Fix for Tabpanel is not updating the UI. #4778 #4828
2024-11-26 15:39:51 +01:00
9d7549da70 Reverted TabStrip and Panel 2024-11-26 10:33:18 +01:00
f5cc61384f Merge pull request #4870 from sbwalker/dev
reference Quill CSS theme using BaseUrl so that it works in .NET MAUI as well as web
2024-11-25 14:20:15 -05:00
844778d36a reference Quill CSS theme using BaseUrl so that it works in .NET MAUI as well as web 2024-11-25 14:19:58 -05:00
871b0a274e Merge pull request #4869 from sbwalker/dev
improve message grammar
2024-11-25 13:48:41 -05:00
737740a3ca improve message grammar 2024-11-25 13:48:28 -05:00
ae8d600600 Update README.md 2024-11-25 09:11:12 -05:00
2f1691bfb0 Update README.md 2024-11-25 09:10:20 -05:00
a3d25f91c8 Update README.md 2024-11-25 09:09:52 -05:00
ff84b50817 Update README.md 2024-11-25 09:09:13 -05:00
0be8242284 Merge pull request #4862 from leigh-pointer/SettingsSetTabOnSave
Updated the Module Settings to use the new ActiveTab parameter
2024-11-25 08:39:45 -05:00
e25a6259ea Merge pull request #4861 from zyhfish/task/fix-4841
Fix #4841: force 2FA validation when it's required in site level.
2024-11-25 08:39:26 -05:00
1578f82efb Updated the Module Settings to use the new ActiveTab parameter 2024-11-23 11:42:22 +01:00
Ben
b5f75f0c5e Fix #4841: force 2FA validation when it's required in site level. 2024-11-23 13:04:27 +08:00
601caab3b6 Merge pull request #4860 from sbwalker/dev
fix #4760 - display update confirmation message in Site Settings
2024-11-22 16:34:46 -05:00
6d3092f440 fix #4760 - display update confirmation message in Site Settings 2024-11-22 16:34:35 -05:00
ef27937c7a Merge pull request #4785 from thabaum/refactored-heading-ifelse
Fixes #4784: Refactor TabPanel Heading Assignment Logic
2024-11-22 15:34:51 -05:00
f4a7b79c4f Merge pull request #4828 from leigh-pointer/TabChange
Fix for Tabpanel is not updating the UI. #4778
2024-11-22 15:30:51 -05:00
2531776a48 Merge pull request #4859 from sbwalker/dev
prepare for 6.0.1
2024-11-22 12:29:56 -05:00
ced80419aa prepare for 6.0.1 2024-11-22 12:29:44 -05:00
ad2816f4e8 Merge pull request #4858 from sbwalker/dev
fix #4848 - remove assemblies from /bin which have been moved to /bin/refs in .NET 9
2024-11-22 12:14:04 -05:00
3528b8c674 fix #4848 - remove assemblies from /bin which have been moved to /bin/refs in .NET 9 2024-11-22 12:13:45 -05:00
80c83c626d Merge pull request #4853 from leigh-pointer/PagerAlignment
Fix for #4852 align the Page numbers container
2024-11-22 11:56:12 -05:00
6a355f2aea Merge pull request #4857 from sbwalker/dev
fix #4855 - dropping required column causes issue on SQLite
2024-11-22 11:55:56 -05:00
7d94e4a53a fix #4855 - dropping required column causes issue on SQLite 2024-11-22 11:55:43 -05:00
823c04742e Merge pull request #4854 from sbwalker/dev
resolve .NET version issue in nuspec files
2024-11-21 10:54:06 -05:00
043fb1abd1 resolve .NET version issue in nuspec files 2024-11-21 10:53:52 -05:00
f01e85b690 Fix for #4852 align the Page numbers container 2024-11-21 16:05:32 +01:00
7eb1298847 Merge pull request #4847 from sbwalker/dev
do not include Oqtane.Server.staticwebassets.endpoints.json in release packages
2024-11-19 13:50:05 -05:00
a5480c9a96 do not include Oqtane.Server.staticwebassets.endpoints.json in release packages 2024-11-19 13:49:45 -05:00
f948600e86 Merge pull request #4845 from sbwalker/dev
fix 2 factor authentication email
2024-11-18 15:04:01 -05:00
420182b9bf fix 2 factor authentication email 2024-11-18 15:03:48 -05:00
8c430ce1a6 Merge pull request #4837 from Trifoia/4803-Add-a-CONTRIBUTING.md
4803 add a contributing.md
2024-11-15 15:02:28 -05:00
d3717dbe19 Remove DefaultDBType value and InstallationId from appsettings.json
The commit removes the value for DefaultDBType and InstallationId from the appsettings.json file.
2024-11-15 10:31:49 -08:00
caa83d769f Create CONTRIBUTING.md 2024-11-15 10:27:53 -08:00
365f87828f Merge remote-tracking branch 'oqtane/dev' into dev 2024-11-15 09:52:50 -08:00
f780887866 Update README.md 2024-11-14 15:46:26 -05:00
43627d4bb8 Merge pull request #4832 from oqtane/master
6.0.0 release
2024-11-14 15:40:38 -05:00
5d7b276cd1 Merge pull request #4831 from oqtane/dev
6.0.0 release
2024-11-14 15:40:17 -05:00
23597eb997 Merge pull request #4827 from leigh-pointer/Search-4824
Fix: for Disabling search does not hide search icon #4824
2024-11-14 07:54:52 -05:00
b6948367f8 Merge pull request #4826 from leigh-pointer/swash
Swashbuckle.AspNetCore updated to 7.0
2024-11-14 07:52:49 -05:00
db6dd5abee Fix for TabPanel is not updating the UI. #4778
Modified that TabStrip and TabPane, now when the ActiveTab is changed the TabPanel is selected
2024-11-14 10:35:15 +01:00
702eb9e466 Revert "Fix for Page Management tab panel is not updating the UI. #4778"
This reverts commit 3c99006226.
2024-11-14 10:33:10 +01:00
3c99006226 Fix for Page Management tab panel is not updating the UI. #4778 2024-11-14 10:31:53 +01:00
aaaf5683a5 Fix: "Search_Enabled" was being saved as Private so unauthorized users can not access this value. 2024-11-14 09:50:05 +01:00
92aa2236c0 Swashbuckle.AspNetCore updated to 7.0 2024-11-14 09:16:55 +01:00
d2592f72d6 Merge pull request #4825 from sbwalker/dev
modifications to get .NET MAUI working on .NET 9 official release
2024-11-13 20:37:24 -05:00
27120d6cc9 modifications to get .NET MAUI working on .NET 9 official release 2024-11-13 20:37:10 -05:00
a2669d35c3 Merge pull request #4823 from sbwalker/dev
exclude wwwroot/_content from official release build
2024-11-13 14:14:47 -05:00
574164081b exclude wwwroot/_content from official release build 2024-11-13 14:14:35 -05:00
00c2f8dcd8 Merge pull request #4822 from sbwalker/dev
adjust gitignore to exclude wwwroot/_content subfolders
2024-11-13 13:52:08 -05:00
0202bf60e5 adjust gitignore to exclude wwwroot/_content subfolders 2024-11-13 13:51:54 -05:00
16436a171b Merge pull request #4821 from zyhfish/task/fix-build-error
add reference to Microsoft.EntityFrameworkCore package.
2024-11-13 10:10:19 -05:00
Ben
4cf4e0eabd add reference to Microsoft.EntityFrameworkCore package. 2024-11-13 23:06:43 +08:00
5edb98dfb4 Merge pull request #4818 from sbwalker/dev
update PostgreSQL provider to official .NET 9 release
2024-11-12 15:50:27 -05:00
899bf22e15 update PostgreSQL provider to official .NET 9 release 2024-11-12 15:50:13 -05:00
9a33167a6c Merge pull request #4817 from sbwalker/dev
Update to official .NET 9 release
2024-11-12 15:43:42 -05:00
2dc068aa21 upgrade to official .NET 9 release 2024-11-12 15:42:57 -05:00
0f2aa4d2e1 update to official .NET 9 release 2024-11-12 15:40:54 -05:00
a699f5c7bc Merge pull request #4815 from mdmontesinos/dev
Fix: Accesibility issue for Search Button
2024-11-12 15:08:23 -05:00
ab807de3c0 Fix: Accesibility issue for Search Button
The search button in Search component does not have the aria-label.
2024-11-12 17:15:56 +01:00
68514bcb36 Merge pull request #4813 from sbwalker/dev
use HttpClient rather than IHttpClientFactory as IHttpClientFactory does not pass cookies in .NET MAUI
2024-11-11 08:15:14 -05:00
422bf8da59 use HttpClient rather than IHttpClientFactory as IHttpClientFactory does not pass cookies in .NET MAUI 2024-11-11 08:14:53 -05:00
de92dc93dd Merge pull request #4811 from sbwalker/dev
resolved issue when setting initial culture cookie
2024-11-08 15:41:36 -05:00
5a91b143b6 resolved issue when setting initial culture cookie 2024-11-08 15:41:24 -05:00
c745e85706 Merge pull request #4810 from sbwalker/dev
make indexing of Files opt-in rather than opt-out
2024-11-08 15:16:45 -05:00
0f698e0c50 make indexing of Files opt-in rather than opt-out 2024-11-08 15:16:32 -05:00
cd16d77bf0 Merge pull request #4809 from sbwalker/dev
Added defensive logic to File Indexer for scenarios where file does not exist on disk. Added ability to reset the search index prior to reindexing.
2024-11-07 17:05:48 -05:00
fdbdd0ef4c Added defensive logic to File Indexer for scenarios where file does not exist on disk. Added ability to reset the search index prior to reindexing. 2024-11-07 17:05:28 -05:00
71485f4a82 Merge pull request #4808 from sbwalker/dev
fix compilation warning
2024-11-07 15:45:47 -05:00
013056a6e5 fix compilation warning 2024-11-07 15:45:34 -05:00
263498fbdc Merge pull request #4807 from sbwalker/dev
remove icrosoft.AspNetCore.Localization from .NET MAUI project
2024-11-07 12:38:31 -05:00
f46ac2c007 remove icrosoft.AspNetCore.Localization from .NET MAUI project 2024-11-07 12:38:16 -05:00
c23841b6db Merge pull request #4806 from sbwalker/dev
default Description to Module Name if not specified in Module Creator
2024-11-07 11:53:15 -05:00
18b1b5fca5 default Description to Module Name if not specified in Module Creator 2024-11-07 11:52:53 -05:00
6707ac2697 Merge pull request #4802 from sbwalker/dev
remove custom JavaScript reconnection script for SignalR
2024-11-05 11:30:32 -05:00
d85a2fc8ce remove custom JavaScript reconnection script for SignalR 2024-11-05 11:30:18 -05:00
a8997e8f17 Merge pull request #4800 from sbwalker/dev
fix #4795 - ensure deterministic ordering of file parts when merging files after upload (credit @HQuast)
2024-11-04 15:29:16 -05:00
c8a22d9537 fix #4795 - ensure deterministic ordering of file parts when merging files after upload (credit @HQuast) 2024-11-04 15:28:59 -05:00
910669f786 Merge pull request #4793 from thabaum/patch-12
Fixes #4792: Update Oqtane.Server.csproj Package Dependencies
2024-11-01 15:40:14 -04:00
89312c6796 Update Oqtane.Server.csproj Package Dependencies 2024-10-30 18:43:42 -07:00
a6aa96fdb0 Merge pull request #4786 from sbwalker/dev
fix #4770 - set a default value for PrincipalSchema to ensure backward compatibility
2024-10-24 17:08:42 -04:00
7deb0b06af fix #4770 - set a default value for PrincipalSchema to ensure backward compatibility 2024-10-24 17:08:25 -04:00
002f8117cb Merge pull request #4783 from sbwalker/dev
get language using CookieRequestCultureProvider
2024-10-24 15:48:28 -04:00
0dfdb12431 get language using CookieRequestCultureProvider 2024-10-24 15:48:14 -04:00
d77e898929 Refactor TabPanel Heading Assignment Logic
- Simplified the logic for setting the Heading property in the TabPanel component.
- Replaced the if-else statement with a ternary operator for improved readability and maintainability.
- Ensured that the functionality remains unchanged and verified correct assignment of headings.
2024-10-24 12:43:20 -07:00
22e3161a9b Merge pull request #4780 from sbwalker/dev
remove Microsoft.AspNetCore.Localization from default module template
2024-10-24 15:20:20 -04:00
b0c8203b24 remove Microsoft.AspNetCore.Localization from default module template 2024-10-24 15:20:07 -04:00
5ee1731c92 Merge pull request #4777 from thabaum/update-html-agility-pack-1.11.69
Fixes #4776: Updates HtmlAgilityPack to 1.11.69
2024-10-24 15:12:17 -04:00
06e8d3b660 Merge pull request #4779 from sbwalker/dev
remove Microsoft.AspNetCore.Http
2024-10-24 15:11:07 -04:00
f09709aedb remove Microsoft.AspNetCore.Http 2024-10-24 15:10:52 -04:00
598d5decac Update HtmlAgilityPack to 1.11.69 2024-10-24 10:18:24 -07:00
7832a6053e Merge pull request #4775 from sbwalker/dev
remove some dependencies on Microsoft.AspNetCore.Http
2024-10-24 13:16:21 -04:00
588748230e remove some dependencies on Microsoft.AspNetCore.Http 2024-10-24 13:16:08 -04:00
8668165c72 Merge pull request #4774 from sbwalker/dev
remove Microsoft.AspNetCore.Localization
2024-10-24 12:25:04 -04:00
a967332f89 remove Microsoft.AspNetCore.Localization 2024-10-24 12:24:46 -04:00
6719d242bd Merge pull request #4756 from zyhfish/task/fix-4752
Fix #4752: validate the username and email.
2024-10-24 09:53:24 -04:00
Ben
3565185808 update the error message. 2024-10-24 20:13:43 +08:00
Ben
ce51262197 update the code to use simple validation. 2024-10-24 20:04:18 +08:00
992a786c2b Merge pull request #4763 from thabaum/ScrollTo-interop-modal
Fixes #4762: Adds logic ScrollTo interop.js method detecting if method is executed inside a modal
2024-10-22 16:28:45 -04:00
038df95aa0 Merge pull request #4759 from thabaum/scroll-to-top-user-settings
Scroll to top after saving settings - Fixes #4758
2024-10-22 16:28:33 -04:00
4ebd660de2 Merge pull request #4766 from sbwalker/dev
resolve compiler warning in .NET MAUI
2024-10-21 15:42:08 -04:00
a9ea41a488 resolve compiler warning in .NET MAUI 2024-10-21 15:41:57 -04:00
196594b490 Merge pull request #4765 from sbwalker/dev
update MAUI project to .NET 9 RC2
2024-10-21 15:34:34 -04:00
1516d5af10 update MAUI project to .NET 9 RC2 2024-10-21 15:34:22 -04:00
ffcd1595a9 Merge pull request #4764 from sbwalker/dev
update Updater to .NET 9
2024-10-21 15:25:27 -04:00
42e5c6e111 update Updater to .NET 9 2024-10-21 15:25:14 -04:00
8a9651dc50 Adds logic for .modal class ScrollTo function 2024-10-21 12:22:01 -07:00
4be2f4f2d9 Update README.md 2024-10-21 15:21:29 -04:00
369bf7a235 Adds logic for .modal class ScrollTo function
fixes #4762
2024-10-21 12:20:24 -07:00
136545b404 Merge pull request #4761 from sbwalker/dev
changes to migrate Oqtane to .NET 9 and version 6.0.0
2024-10-21 14:51:38 -04:00
73ea17ae0f changes to migrate Oqtane to .NET 9 and version 6.0.0 2024-10-21 14:51:20 -04:00
23010acef4 Scroll to top after saving settings - Fixes #4758 2024-10-21 10:36:12 -07:00
Ben
4f74962ce2 Fix #4752: validate the username and email. 2024-10-21 23:11:57 +08:00
7f978c7845 Update README.md 2024-10-17 13:52:21 -04:00
bf175984f3 Merge remote-tracking branch 'origin/dev' into dev 2024-09-11 18:23:41 -07:00
4b17847ea5 Merge remote-tracking branch 'oqtane/dev' into dev 2024-07-05 21:53:14 -07:00
2addcc3ab5 Merge branch 'dev' of https://github.com/Trifoia/oqtane.framework into dev 2024-03-28 13:47:43 -07:00
370b39a139 Merge branch 'release/v5.0.1' into dev 2024-01-27 21:18:58 -08:00
7b7e64576f Update appsettings.json 2024-01-27 20:30:20 -08:00
286928d59e Merge tag 'v5.0.1' into dev 2023-12-29 11:54:39 -08:00
cc65555c3d minor fix to routing 2023-12-05 12:17:02 -08:00
63e3923349 Merge remote-tracking branch 'oqtane/dev' into dev 2023-11-17 12:55:40 -08:00
95 changed files with 984 additions and 524 deletions

3
.gitignore vendored
View File

@ -22,6 +22,9 @@ Oqtane.Server/Packages
Oqtane.Server/wwwroot/Content
Oqtane.Server/wwwroot/Packages/*.log
Oqtane.Server/wwwroot/_content/*
!Oqtane.Server/wwwroot/_content/Placeholder.txt
Oqtane.Server/wwwroot/Modules/*
!Oqtane.Server/wwwroot/Modules/Oqtane.Modules.*
!Oqtane.Server/wwwroot/Modules/Templates

24
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,24 @@
# Contributing to Oqtane
## How to Contribute
We track all of our issues on Github. If you want to contribute, everything starts with an issue. If you don't have an issue yet, you can add one. Then a core contributor will tag it as either an enhancement [ENH] or a bug [BUG]. Tagged issues are open for contribution.
## Use GitHub-flow process
- Make a comment on the issue that you intend to work on it and read all the comments to gain a full understanding.
- Fork the repository
- Create a new branch and update your comment on the issue with a llink to the branch
- Make your changes and commit them
- Push to the branch
- Create a pull request
## Reporting Bugs
- Check if the issue has already been reported.
- Open a new issue if it hasnt been reported.
## Requesting Features
- Use the feature request template in the Issues tab.
Thank you for contributing!

View File

@ -51,6 +51,7 @@ namespace Microsoft.Extensions.DependencyInjection
services.AddScoped<IUrlMappingService, UrlMappingService>();
services.AddScoped<IVisitorService, VisitorService>();
services.AddScoped<ISyncService, SyncService>();
services.AddScoped<ILocalizationCookieService, LocalizationCookieService>();
// providers
services.AddScoped<ITextEditor, Oqtane.Modules.Controls.QuillJSTextEditor>();

View File

@ -15,7 +15,7 @@
<div class="row">
<div class="mx-auto text-center">
<img src="oqtane-black.png" />
<div style="font-weight: bold">@SharedLocalizer["Version"] @Constants.Version (.NET 8)</div>
<div style="font-weight: bold">@SharedLocalizer["Version"] @Constants.Version (.NET 9)</div>
</div>
</div>
<hr class="app-rule" />
@ -156,129 +156,130 @@
private List<SiteTemplate> _templates;
private string _template = Constants.DefaultSiteTemplate;
private bool _register = true;
private string _message = string.Empty;
private string _loadingDisplay = "display: none;";
private string _message = string.Empty;
private string _loadingDisplay = "display: none;";
protected override async Task OnInitializedAsync()
{
protected override async Task OnInitializedAsync()
{
// include CSS
var content = $"<link rel=\"stylesheet\" href=\"{Constants.BootstrapStylesheetUrl}\" integrity=\"{Constants.BootstrapStylesheetIntegrity}\" crossorigin=\"anonymous\" type=\"text/css\"/>";
SiteState.AppendHeadContent(content);
_togglePassword = SharedLocalizer["ShowPassword"];
_toggleConfirmPassword = SharedLocalizer["ShowPassword"];
_toggleConfirmPassword = SharedLocalizer["ShowPassword"];
_databases = await DatabaseService.GetDatabasesAsync();
if (_databases.Exists(item => item.IsDefault))
{
_databaseName = _databases.Find(item => item.IsDefault).Name;
}
else
{
_databaseName = "LocalDB";
}
LoadDatabaseConfigComponent();
_databases = await DatabaseService.GetDatabasesAsync();
if (_databases.Exists(item => item.IsDefault))
{
_databaseName = _databases.Find(item => item.IsDefault).Name;
}
else
{
_databaseName = "LocalDB";
}
LoadDatabaseConfigComponent();
_templates = await SiteTemplateService.GetSiteTemplatesAsync();
}
private void DatabaseChanged(ChangeEventArgs eventArgs)
{
try
{
_databaseName = (string)eventArgs.Value;
_showConnectionString = false;
LoadDatabaseConfigComponent();
}
catch
{
_message = Localizer["Error.DbConfig.Load"];
}
}
private void DatabaseChanged(ChangeEventArgs eventArgs)
{
try
{
_databaseName = (string)eventArgs.Value;
_showConnectionString = false;
LoadDatabaseConfigComponent();
}
catch
{
_message = Localizer["Error.DbConfig.Load"];
}
}
private void LoadDatabaseConfigComponent()
{
var database = _databases.SingleOrDefault(d => d.Name == _databaseName);
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 LoadDatabaseConfigComponent()
{
var database = _databases.SingleOrDefault(d => d.Name == _databaseName);
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();
};
}
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
// include JavaScript
var interop = new Interop(JSRuntime);
var interop = new Interop(JSRuntime);
await interop.IncludeScript("", Constants.BootstrapScriptUrl, Constants.BootstrapScriptIntegrity, "anonymous", "", "head");
}
}
}
}
private async Task Install()
{
var connectionString = String.Empty;
if (_showConnectionString)
{
connectionString = _connectionString;
}
else
{
if (_databaseConfig is IDatabaseConfigControl databaseConfigControl)
{
connectionString = databaseConfigControl.GetConnectionString();
}
}
private async Task Install()
{
var connectionString = String.Empty;
if (_showConnectionString)
{
connectionString = _connectionString;
}
else
{
if (_databaseConfig is IDatabaseConfigControl databaseConfigControl)
{
connectionString = databaseConfigControl.GetConnectionString();
}
}
if (connectionString != "" && !string.IsNullOrEmpty(_hostUsername) && !string.IsNullOrEmpty(_hostPassword) && _hostPassword == _confirmPassword && !string.IsNullOrEmpty(_hostEmail) && _hostEmail.Contains("@"))
{
if (await UserService.ValidatePasswordAsync(_hostPassword))
{
_loadingDisplay = "";
StateHasChanged();
if (connectionString != "" && !string.IsNullOrEmpty(_hostUsername) && !string.IsNullOrEmpty(_hostPassword) && _hostPassword == _confirmPassword && !string.IsNullOrEmpty(_hostEmail) && _hostEmail.Contains("@"))
{
var result = await UserService.ValidateUserAsync(_hostUsername, _hostEmail, _hostPassword);
if (result.Succeeded)
{
_loadingDisplay = "";
StateHasChanged();
Uri uri = new Uri(NavigationManager.Uri);
Uri uri = new Uri(NavigationManager.Uri);
var database = _databases.SingleOrDefault(d => d.Name == _databaseName);
var database = _databases.SingleOrDefault(d => d.Name == _databaseName);
var config = new InstallConfig
{
DatabaseType = database.DBType,
ConnectionString = connectionString,
Aliases = uri.Authority,
HostUsername = _hostUsername,
HostPassword = _hostPassword,
HostEmail = _hostEmail,
HostName = _hostUsername,
TenantName = TenantNames.Master,
IsNewTenant = true,
SiteName = Constants.DefaultSite,
Register = _register,
SiteTemplate = _template,
RenderMode = RenderModes.Static,
Runtime = Runtimes.Server
};
var config = new InstallConfig
{
DatabaseType = database.DBType,
ConnectionString = connectionString,
Aliases = uri.Authority,
HostUsername = _hostUsername,
HostPassword = _hostPassword,
HostEmail = _hostEmail,
HostName = _hostUsername,
TenantName = TenantNames.Master,
IsNewTenant = true,
SiteName = Constants.DefaultSite,
Register = _register,
SiteTemplate = _template,
RenderMode = RenderModes.Static,
Runtime = Runtimes.Server
};
var installation = await InstallationService.Install(config);
if (installation.Success)
{
NavigationManager.NavigateTo(uri.Scheme + "://" + uri.Authority, true);
}
else
{
_message = installation.Message;
_loadingDisplay = "display: none;";
}
}
else
{
_message = Localizer["Message.Password.Invalid"];
var installation = await InstallationService.Install(config);
if (installation.Success)
{
NavigationManager.NavigateTo(uri.Scheme + "://" + uri.Authority, true);
}
else
{
_message = installation.Message;
_loadingDisplay = "display: none;";
}
}
else
{
_message = string.Join("<br />", result.Errors.Select(i => !string.IsNullOrEmpty(i.Value) ? i.Value : Localizer[i.Key]));
}
}
else

View File

@ -1,7 +1,6 @@
@namespace Oqtane.Modules.Admin.Languages
@inherits ModuleBase
@using System.Globalization
@using Microsoft.AspNetCore.Localization
@inject NavigationManager NavigationManager
@inject ILocalizationService LocalizationService
@inject ILanguageService LanguageService

View File

@ -1,7 +1,6 @@
@namespace Oqtane.Modules.Admin.Languages
@inherits ModuleBase
@using System.Globalization
@using Microsoft.AspNetCore.Localization
@inject NavigationManager NavigationManager
@inject ILocalizationService LocalizationService
@inject ILanguageService LanguageService

View File

@ -27,7 +27,7 @@
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="description" HelpText="Enter a short description for the module" ResourceKey="Description">Description: </Label>
<div class="col-sm-9">
<textarea id="description" class="form-control" @bind="@_description" rows="3" maxlength="2000" required></textarea>
<textarea id="description" class="form-control" @bind="@_description" rows="3" maxlength="2000"></textarea>
</div>
</div>
<div class="row mb-1 align-items-center">
@ -118,6 +118,7 @@
{
if (IsValid(_owner) && IsValid(_module) && _owner != _module && _template != "-")
{
if (string.IsNullOrEmpty(_description)) _description = _module;
if (IsValidXML(_description))
{
var template = _templates.FirstOrDefault(item => item.Name == _template);

View File

@ -1,7 +1,6 @@
@namespace Oqtane.Modules.Admin.ModuleDefinitions
@inherits ModuleBase
@using System.Globalization
@using Microsoft.AspNetCore.Localization
@inject IModuleDefinitionService ModuleDefinitionService
@inject IPackageService PackageService
@inject ILanguageService LanguageService

View File

@ -12,7 +12,7 @@
@if (_initialized)
{
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<TabStrip>
<TabStrip ActiveTab="@_activetab">
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings">
@if (_containers != null)
{
@ -162,6 +162,7 @@
private DateTime? _effectivedate = null;
private DateTime? _expirydate = null;
private List<Page> _pages;
private string _activetab = "";
protected override async Task OnInitializedAsync()
{
@ -241,6 +242,7 @@
private async Task SaveModule()
{
validated = true;
var interop = new Interop(JSRuntime);
if (await interop.FormValid(form))
@ -261,21 +263,21 @@
pagemodule.ExpiryDate = Utilities.LocalDateAndTimeAsUtc(_expirydate);
pagemodule.ContainerType = (_containerType != "-") ? _containerType : string.Empty;
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Page.DefaultContainerType)
{
pagemodule.ContainerType = string.Empty;
}
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Site.DefaultContainerType)
{
pagemodule.ContainerType = string.Empty;
}
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
{
pagemodule.ContainerType = string.Empty;
}
if (!string.IsNullOrEmpty(pagemodule.ContainerType) && pagemodule.ContainerType == PageState.Site.DefaultContainerType)
{
pagemodule.ContainerType = string.Empty;
}
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
var module = ModuleState;
module.AllPages = bool.Parse(_allPages);
module.PageModuleId = ModuleState.PageModuleId;
module.PermissionList = _permissionGrid.GetPermissionList();
await ModuleService.UpdateModuleAsync(module);
var module = ModuleState;
module.AllPages = bool.Parse(_allPages);
module.PageModuleId = ModuleState.PageModuleId;
module.PermissionList = _permissionGrid.GetPermissionList();
await ModuleService.UpdateModuleAsync(module);
if (_moduleSettingsType != null)
{
@ -300,11 +302,13 @@
}
else
{
_activetab = "Settings";
AddModuleMessage(Localizer["Message.Required.Title"], MessageType.Warning);
}
}
else
{
_activetab = "Settings";
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
}
}

View File

@ -63,7 +63,7 @@
private string _enabled = "True";
private string _lastIndexedOn = "";
private string _ignorePages = "";
private string _ignoreEntities = "";
private string _ignoreEntities = "File";
private string _minimumWordLength = "3";
private string _ignoreWords = "the,be,to,of,and,a,i,in,that,have,it,for,not,on,with,he,as,you,do,at,this,but,his,by,from,they,we,say,her,she,or,an,will,my,one,all,would,there,their,what,so,up,out,if,about,who,get,which,go,me,when,make,can,like,time,no,just,him,know,take,people,into,year,your,good,some,could,them,see,other,than,then,now,look,only,come,its,over,think,also,back,after,use,two,how,our,work,first,well,way,even,new,want,because,any,these,give,day,most,us";
@ -85,7 +85,7 @@
{
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
settings = SettingService.SetSetting(settings, "Search_SearchProvider", _searchProvider);
settings = SettingService.SetSetting(settings, "Search_Enabled", _enabled, true);
settings = SettingService.SetSetting(settings, "Search_Enabled", _enabled);
settings = SettingService.SetSetting(settings, "Search_LastIndexedOn", _lastIndexedOn, true);
settings = SettingService.SetSetting(settings, "Search_IgnorePages", _ignorePages, true);
settings = SettingService.SetSetting(settings, "Search_IgnoreEntities", _ignoreEntities, true);
@ -106,9 +106,7 @@
try
{
_lastIndexedOn = DateTime.MinValue.ToString();
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
settings = SettingService.SetSetting(settings, "Search_LastIndexedOn", _lastIndexedOn, true);
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
await Save();
AddModuleMessage(Localizer["Message.Reindex"], MessageType.Success);
}
catch (Exception ex)

View File

@ -32,32 +32,32 @@
<option value="-">&lt;@SharedLocalizer["Not Specified"]&gt;</option>
@foreach (Page page in _pages)
{
if (UserSecurity.ContainsRole(page.PermissionList, PermissionNames.View, RoleNames.Everyone))
{
<option value="@(page.PageId)">@(new string('-', page.Level * 2))@(page.Name)</option>
}
if (UserSecurity.ContainsRole(page.PermissionList, PermissionNames.View, RoleNames.Everyone))
{
<option value="@(page.PageId)">@(new string('-', page.Level * 2))@(page.Name)</option>
}
}
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="isDeleted" HelpText="Is this site deleted?" ResourceKey="IsDeleted">Deleted? </Label>
<div class="col-sm-9">
<select id="isDeleted" class="form-select" @bind="@_isdeleted" required>
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
</select>
</div>
</div>
<div 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">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="isDeleted" HelpText="Is this site deleted?" ResourceKey="IsDeleted">Deleted? </Label>
<div class="col-sm-9">
<select id="isDeleted" class="form-select" @bind="@_isdeleted" required>
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
</select>
</div>
</div>
<div 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">
<div class="input-group">
<input id="sitemap" class="form-control" @bind="@_sitemap" disabled />
<a href="@_sitemap" class="btn btn-secondary" target="_new">@Localizer["Browse"]</a>
</div>
</div>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="siteguid" HelpText="The Unique Identifier For The Site" ResourceKey="SiteGuid">ID: </Label>
<div class="col-sm-9">
@ -159,8 +159,8 @@
</div>
</Section>
<Section Name="PageContent" Heading="Page Content" ResourceKey="PageContent">
<div class="container">
<div class="row mb-1 align-items-center">
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="headcontent" HelpText="Optionally enter content to be included in the page head (ie. meta, link, or script tags)" ResourceKey="HeadContent">Head Content: </Label>
<div class="col-sm-9">
<textarea id="headcontent" class="form-control" @bind="@_headcontent" rows="3"></textarea>
@ -213,10 +213,10 @@
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="password" HelpText="Enter the password for your SMTP account" ResourceKey="SmtpPassword">Password: </Label>
<div class="col-sm-9">
<div class="input-group">
<input id="password" type="@_smtppasswordtype" class="form-control" @bind="@_smtppassword" autocomplete="off"/>
<div class="input-group">
<input id="password" type="@_smtppasswordtype" class="form-control" @bind="@_smtppassword" autocomplete="off"/>
<button type="button" class="btn btn-secondary" @onclick="@ToggleSMTPPassword" tabindex="-1">@_togglesmtppassword</button>
</div>
</div>
</div>
</div>
<div class="row mb-1 align-items-center">
@ -225,15 +225,15 @@
<input id="sender" class="form-control" @bind="@_smtpsender" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="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="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="smtpenabled" HelpText="Specify if SMTP is enabled for this site" ResourceKey="SMTPEnabled">Enabled? </Label>
<div class="col-sm-9">
@ -244,10 +244,10 @@
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="retention" HelpText="Number of days of notifications to retain" ResourceKey="Retention">Retention (Days): </Label>
<div class="col-sm-9">
<Label Class="col-sm-3" For="retention" HelpText="Number of days of notifications to retain" ResourceKey="Retention">Retention (Days): </Label>
<div class="col-sm-9">
<input id="retention" class="form-control" type="number" min="0" step="1" @bind="@_retention" />
</div>
</div>
</div>
<button type="button" class="btn btn-secondary" @onclick="SendEmail">@Localizer["Smtp.TestConfig"]</button>
<br /><br />
@ -280,57 +280,57 @@
</Section>
@if (_aliases != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
{
<Section Name="Aliases" Heading="Aliases" ResourceKey="Aliases">
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="aliases" HelpText="The urls for the site. This can include domain names (ie. domain.com), subdomains (ie. sub.domain.com) or virtual folders (ie. domain.com/folder)." ResourceKey="Aliases">Aliases: </Label>
<div class="col-sm-9">
<button type="button" class="btn btn-primary" @onclick="AddAlias">@SharedLocalizer["Add"]</button>
<Pager Items="@_aliases">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>@Localizer["AliasName"]</th>
<th>@Localizer["AliasDefault"]</th>
</Header>
<Row>
@if (context.AliasId != _aliasid)
{
<td>
@if (_aliasid == -1)
{
<button type="button" class="btn btn-primary" @onclick="@(() => EditAlias(context))">@SharedLocalizer["Edit"]</button>
}
</td>
<td>
@if (_aliasid == -1)
{
<ActionDialog Action="Delete" OnClick="@(async () => await DeleteAlias(context))" ResourceKey="DeleteAlias" Class="btn btn-danger" Header="Delete Alias" Message="@string.Format(Localizer["Confirm.Alias.Delete", context.Name])" />
}
</td>
<td>@context.Name</td>
<Section Name="Aliases" Heading="Aliases" ResourceKey="Aliases">
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="aliases" HelpText="The urls for the site. This can include domain names (ie. domain.com), subdomains (ie. sub.domain.com) or virtual folders (ie. domain.com/folder)." ResourceKey="Aliases">Aliases: </Label>
<div class="col-sm-9">
<button type="button" class="btn btn-primary" @onclick="AddAlias">@SharedLocalizer["Add"]</button>
<Pager Items="@_aliases">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>@Localizer["AliasName"]</th>
<th>@Localizer["AliasDefault"]</th>
</Header>
<Row>
@if (context.AliasId != _aliasid)
{
<td>
@if (_aliasid == -1)
{
<button type="button" class="btn btn-primary" @onclick="@(() => EditAlias(context))">@SharedLocalizer["Edit"]</button>
}
</td>
<td>
@if (_aliasid == -1)
{
<ActionDialog Action="Delete" OnClick="@(async () => await DeleteAlias(context))" ResourceKey="DeleteAlias" Class="btn btn-danger" Header="Delete Alias" Message="@string.Format(Localizer["Confirm.Alias.Delete", context.Name])" />
}
</td>
<td>@context.Name</td>
<td>@((context.IsDefault) ? SharedLocalizer["Yes"] : SharedLocalizer["No"])</td>
}
else
{
<td><button type="button" class="btn btn-success" @onclick="@(async () => await SaveAlias())">@SharedLocalizer["Save"]</button></td>
<td><button type="button" class="btn btn-secondary" @onclick="@(async () => await CancelAlias())">@SharedLocalizer["Cancel"]</button></td>
<td>
<input id="aliasname" class="form-control" @bind="@_aliasname" />
</td>
<td>
<select id="defaultalias" class="form-select" @bind="@_defaultalias" required>
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
</select>
</td>
}
</Row>
</Pager>
</div>
</div>
</div>
</Section>
}
else
{
<td><button type="button" class="btn btn-success" @onclick="@(async () => await SaveAlias())">@SharedLocalizer["Save"]</button></td>
<td><button type="button" class="btn btn-secondary" @onclick="@(async () => await CancelAlias())">@SharedLocalizer["Cancel"]</button></td>
<td>
<input id="aliasname" class="form-control" @bind="@_aliasname" />
</td>
<td>
<select id="defaultalias" class="form-select" @bind="@_defaultalias" required>
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
</select>
</td>
}
</Row>
</Pager>
</div>
</div>
</div>
</Section>
<Section Name="Hosting" Heading="Hosting Model" ResourceKey="Hosting">
<div class="container">
<div class="row mb-1 align-items-center">
@ -376,7 +376,7 @@
<Section Name="TenantInformation" Heading="Database" ResourceKey="TenantInformation">
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="tenant" HelpText="The name of the database used for the site. Note that this is not the physical database name but rather the tenant name which is used within the framework to identify a database." ResourceKey="Tenant">Database: </Label>
<Label Class="col-sm-3" For="tenant" HelpText="The name of the database used for the site. Note that this is not the physical database name but rather the tenant name which is used within the framework to identify a database." ResourceKey="Tenant">Database: </Label>
<div class="col-sm-9">
<input id="tenant" class="form-control" @bind="@_tenant" readonly />
</div>
@ -390,7 +390,7 @@
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="connectionstring" HelpText="The name of the connection string in appsettings.json which will be used to connect to the database" ResourceKey="ConnectionString">Connection: </Label>
<div class="col-sm-9">
<input id="connectionstring" class="form-control" @bind="@_connectionstring" readonly />
<input id="connectionstring" class="form-control" @bind="@_connectionstring" readonly />
</div>
</div>
</div>
@ -481,6 +481,11 @@
{
try
{
if (PageState.QueryString.ContainsKey("updated"))
{
AddModuleMessage(Localizer["Success.Settings.SaveSite"], MessageType.Success);
}
Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
if (site != null)
{
@ -736,7 +741,7 @@
await logger.LogInformation("Site Settings Saved {Site}", site);
NavigationManager.NavigateTo(NavigateUrl(), true); // reload
NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, "updated=true"), true); // reload
}
}
else

View File

@ -691,6 +691,10 @@ else
await logger.LogError(ex, "Error Saving Site Settings {Error}", ex.Message);
AddModuleMessage(Localizer["Error.SaveSiteSettings"], MessageType.Error);
}
finally
{
await ScrollToPageTop();
}
}
private void ProviderChanged(ChangeEventArgs e)

View File

@ -196,7 +196,7 @@
else
{
FolderId = -1;
_message = "Folder Path " + Folder + "Does Not Exist";
_message = "Folder Path " + Folder + " Does Not Exist";
_messagetype = MessageType.Error;
}
}
@ -226,9 +226,9 @@
}
else
{
FileId = -1; // file does not exist
_message = "FileId " + FileId.ToString() + "Does Not Exist";
_message = "FileId " + FileId.ToString() + " Does Not Exist";
_messagetype = MessageType.Error;
FileId = -1; // file does not exist
}
}

View File

@ -21,7 +21,7 @@
@if ((Toolbar == "Top" || Toolbar == "Both") && _pages > 0 && Items.Count() > _maxItems)
{
<ul class="pagination justify-content-center my-2">
<ul class="pagination justify-content-@PaginationAlignment.ToLower() my-2">
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
</li>
@ -84,7 +84,7 @@
@if ((Toolbar == "Top" || Toolbar == "Both") && _pages > 0 && Items.Count() > _maxItems)
{
<ul class="pagination justify-content-center my-2">
<ul class="pagination justify-content-@PaginationAlignment.ToLower() my-2">
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" href="@PageUrl(1, _search)"><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
</li>
@ -200,7 +200,7 @@
{
@if (PageState.RenderMode == RenderModes.Interactive || ModuleState.RenderMode == RenderModes.Interactive)
{
<ul class="pagination justify-content-center my-2">
<ul class="pagination justify-content-@PaginationAlignment.ToLower() my-2">
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" @onclick=@(async () => UpdateList(1))><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
</li>
@ -248,7 +248,7 @@
}
else
{
<ul class="pagination justify-content-center my-2">
<ul class="pagination justify-content-@PaginationAlignment.ToLower() my-2">
<li class="page-item@((_page > 1) ? " app-pager-pointer" : " disabled")">
<a class="page-link shadow-none" href="@PageUrl(1, _search)"><span class="oi oi-media-step-backward" title="start" aria-hidden="true"></span></a>
</li>
@ -368,6 +368,12 @@
[SupplyParameterFromForm(FormName = "PagerForm")]
public string _Search { get => ""; set => _search = value; }
/// <summary>
/// Accepted values are Start or Center or End. The default value is Center
/// </summary>
[Parameter]
public string PaginationAlignment { get; set; } = "center"; // Alignment of the Page Numbering start, center, end
private IEnumerable<TableItem> ItemList { get; set; }
protected override void OnInitialized()

View File

@ -277,7 +277,7 @@
{
// include CSS theme
var interop = new Interop(JSRuntime);
await interop.IncludeLink("", "stylesheet", $"css/quill/quill.{_theme}.css", "text/css", "", "", "");
await interop.IncludeLink("", "stylesheet", $"{PageState?.Alias.BaseUrl}/css/quill/quill.{_theme}.css", "text/css", "", "", "");
}
await base.OnAfterRenderAsync(firstRender);

View File

@ -36,14 +36,7 @@ else
Parent.AddTabPanel((TabPanel)this);
if (string.IsNullOrEmpty(Heading))
{
Heading = Localize(nameof(Name), Name);
}
else
{
Heading = Localize(nameof(Heading), Heading);
}
Heading = string.IsNullOrEmpty(Heading) ? Localize(nameof(Name), Name) : Localize(nameof(Heading), Heading);
}
public string DisplayHeading()

View File

@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<OutputType>Exe</OutputType>
<Configurations>Debug;Release</Configurations>
<Version>5.2.4</Version>
<Version>6.0.1</Version>
<Product>Oqtane</Product>
<Authors>Shaun Walker</Authors>
<Company>.NET Foundation</Company>
@ -12,7 +12,7 @@
<Copyright>.NET Foundation</Copyright>
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.4</PackageReleaseNotes>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.0.1</PackageReleaseNotes>
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<RootNamespace>Oqtane</RootNamespace>
@ -22,11 +22,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.10" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.10" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.0" />
</ItemGroup>
<ItemGroup>

View File

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
@ -13,13 +12,13 @@ using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.AspNetCore.Localization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.JSInterop;
using Oqtane.Documentation;
using Oqtane.Models;
using Oqtane.Modules;
using Oqtane.Services;
using Oqtane.Shared;
using Oqtane.UI;
namespace Oqtane.Client
@ -258,7 +257,7 @@ namespace Oqtane.Client
var jsRuntime = serviceProvider.GetRequiredService<IJSRuntime>();
var interop = new Interop(jsRuntime);
var localizationCookie = await interop.GetCookie(CookieRequestCultureProvider.DefaultCookieName);
var culture = CookieRequestCultureProvider.ParseCookieValue(localizationCookie)?.UICultures?[0].Value;
var culture = CookieRequestCultureProvider.ParseCookieValue(localizationCookie)?.UICulture.Name;
var localizationService = serviceProvider.GetRequiredService<ILocalizationService>();
var cultures = await localizationService.GetCulturesAsync(false);

View File

@ -183,4 +183,7 @@
<data name="Template" xml:space="preserve">
<value>Select a site template</value>
</data>
<data name="Message.Username.Invalid" xml:space="preserve">
<value>The Username Provided Does Not Meet The System Requirement, It Can Only Contains Letters Or Digits.</value>
</data>
</root>

View File

@ -139,7 +139,7 @@
<value>Ignore Entities: </value>
</data>
<data name="IgnoreEntities.HelpText" xml:space="preserve">
<value>Comma delimited list of entities which should be ignored</value>
<value>Comma delimited list of entities which should be ignored. By default File entities are ignored.</value>
</data>
<data name="MinimumWordLength.Text" xml:space="preserve">
<value>Word Length: </value>
@ -154,7 +154,7 @@
<value>Comma delimited list of words which should be ignored</value>
</data>
<data name="Success.Save" xml:space="preserve">
<value>Search Settings Saved Successfully</value>
<value>Search Settings Saved Successfully. You Will Need Reindex For Your Changes To Be Reflected In The Search Results.</value>
</data>
<data name="Error.Save" xml:space="preserve">
<value>Error Saving Search Settings</value>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
@ -151,6 +151,6 @@
<value>You Cannot Perform A System Update In A Development Environment</value>
</data>
<data name="Disclaimer.Text" xml:space="preserve">
<value>Please Note That The System Update Capability Is A Simplified Upgrade Process Intended For Small To Medium Sized Installations. For Larger Enterprise Installations You Will Want To Use A Manual Upgrade Process. Also Note That The System Update Capability Is Not Recommended When Using Microsoft Azure Due To The Limitations Of That Environment. </value>
<value>Please Note That The System Update Capability Is A Simplified Upgrade Process Intended For Small To Medium Sized Installations. For Larger Enterprise Installations You Will Want To Use A Manual Upgrade Process. Also Note That The System Update Capability Is Not Recommended When Using Microsoft Azure Due To Environmental Limitations.</value>
</data>
</root>

View File

@ -0,0 +1,17 @@
using System.Threading.Tasks;
namespace Oqtane.Services
{
/// <summary>
/// Service to set localization cookie
/// </summary>
public interface ILocalizationCookieService
{
/// <summary>
/// Set the localization cookie
/// </summary>
/// <param name="culture"></param>
/// <returns></returns>
Task SetLocalizationCookieAsync(string culture);
}
}

View File

@ -113,6 +113,15 @@ namespace Oqtane.Services
/// <returns></returns>
Task<User> VerifyTwoFactorAsync(User user, string token);
/// <summary>
/// Validate identity user info.
/// </summary>
/// <param name="username"></param>
/// <param name="email"></param>
/// <param name="password"></param>
/// <returns></returns>
Task<UserValidateResult> ValidateUserAsync(string username, string email, string password);
/// <summary>
/// Validate a users password against the password policy
/// </summary>

View File

@ -0,0 +1,18 @@
using System.Net.Http;
using System.Threading.Tasks;
using Oqtane.Documentation;
using Oqtane.Shared;
namespace Oqtane.Services
{
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
public class LocalizationCookieService : ServiceBase, ILocalizationCookieService
{
public LocalizationCookieService(HttpClient http, SiteState siteState) : base(http, siteState) { }
public Task SetLocalizationCookieAsync(string culture)
{
return Task.CompletedTask; // only used in server side rendering
}
}
}

View File

@ -4,7 +4,6 @@ using System.Net.Http;
using System.Net.Http.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Net.Http.Headers;
using Oqtane.Shared;
namespace Oqtane.Services
@ -28,9 +27,9 @@ namespace Oqtane.Services
private HttpClient GetHttpClient(string AuthorizationToken)
{
var httpClient = _httpClientFactory.CreateClient("Remote");
if (!httpClient.DefaultRequestHeaders.Contains(HeaderNames.Authorization) && !string.IsNullOrEmpty(AuthorizationToken))
if (!httpClient.DefaultRequestHeaders.Contains("Authorization") && !string.IsNullOrEmpty(AuthorizationToken))
{
httpClient.DefaultRequestHeaders.Add(HeaderNames.Authorization, "Bearer " + AuthorizationToken);
httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + AuthorizationToken);
}
return httpClient;
}

View File

@ -89,6 +89,11 @@ namespace Oqtane.Services
return await PostJsonAsync<User>($"{Apiurl}/twofactor?token={token}", user);
}
public async Task<UserValidateResult> ValidateUserAsync(string username, string email, string password)
{
return await GetJsonAsync<UserValidateResult>($"{Apiurl}/validateuser?username={WebUtility.UrlEncode(username)}&email={WebUtility.UrlEncode(email)}&password={WebUtility.UrlEncode(password)}");
}
public async Task<bool> ValidatePasswordAsync(string password)
{
return await GetJsonAsync<bool>($"{Apiurl}/validate/{WebUtility.UrlEncode(password)}");

View File

@ -1,10 +1,9 @@
@using System.Globalization
@using Microsoft.AspNetCore.Localization
@using Microsoft.AspNetCore.Http
@using Oqtane.Models
@namespace Oqtane.Themes.Controls
@inherits ThemeControlBase
@inject ILanguageService LanguageService
@inject ILocalizationCookieService LocalizationCookieService
@inject NavigationManager NavigationManager
@if (_supportedCultures?.Count() > 1)
@ -38,10 +37,7 @@
[Parameter]
public string ButtonClass { get; set; } = "btn-outline-secondary";
[CascadingParameter]
HttpContext HttpContext { get; set; }
protected override void OnParametersSet()
protected override async Task OnParametersSetAsync()
{
MenuAlignment = DropdownAlignment.ToLower() == "right" ? "dropdown-menu-end" : string.Empty;
@ -52,17 +48,7 @@
var culture = PageState.QueryString["culture"];
if (_supportedCultures.Any(item => item.Name == culture))
{
var localizationCookieValue = CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture));
HttpContext.Response.Cookies.Append(CookieRequestCultureProvider.DefaultCookieName, localizationCookieValue, new CookieOptions
{
Path = "/",
Expires = DateTimeOffset.UtcNow.AddYears(365),
SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Lax, // Set SameSite attribute
Secure = true, // Ensure the cookie is only sent over HTTPS
HttpOnly = false // cookie is updated using JS Interop in Interactive render mode
});
await LocalizationCookieService.SetLocalizationCookieAsync(culture);
}
NavigationManager.NavigateTo(NavigationManager.Uri.Replace($"?culture={culture}", ""));
}

View File

@ -18,7 +18,7 @@
placeholder="@Localizer["SearchPlaceHolder"]"
aria-label="Search" />
}
<button type="submit" class="btn btn-search">
<button type="submit" class="btn btn-search" aria-label="Search Button">
<span class="oi oi-magnifying-glass align-middle"></span>
</button>
</form>

View File

@ -1,7 +1,5 @@
@namespace Oqtane.UI
@using Microsoft.AspNetCore.Http
@inject IInstallationService InstallationService
@inject IJSRuntime JSRuntime
@inject SiteState SiteState
@if (_initialized)
@ -48,9 +46,6 @@
[Parameter]
public string Platform { get; set; } = "";
[CascadingParameter]
HttpContext HttpContext { get; set; }
private bool _initialized = false;
private bool _installed = false;
private string _display = "display: none;";
@ -62,7 +57,7 @@
SiteState.AntiForgeryToken = AntiForgeryToken;
SiteState.AuthorizationToken = AuthorizationToken;
SiteState.Platform = Platform;
SiteState.IsPrerendering = (HttpContext != null) ? true : false;
SiteState.IsPrerendering = !RendererInfo.IsInteractive;
if (Runtime == Runtimes.Hybrid)
{

View File

@ -1,6 +1,5 @@
@using System.Diagnostics.CodeAnalysis
@using System.Net
@using Microsoft.AspNetCore.Http
@using System.Globalization
@using System.Security.Claims
@namespace Oqtane.UI

View File

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Version>5.2.4</Version>
<TargetFramework>net9.0</TargetFramework>
<Version>6.0.1</Version>
<Product>Oqtane</Product>
<Authors>Shaun Walker</Authors>
<Company>.NET Foundation</Company>
@ -10,7 +10,7 @@
<Copyright>.NET Foundation</Copyright>
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.4</PackageReleaseNotes>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.0.1</PackageReleaseNotes>
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
@ -33,7 +33,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MySql.EntityFrameworkCore" Version="8.0.5" />
<PackageReference Include="MySql.EntityFrameworkCore" Version="9.0.0-preview" />
<PackageReference Include="MySql.Data" Version="9.1.0" />
</ItemGroup>
@ -42,7 +42,7 @@
</ItemGroup>
<ItemGroup>
<MySQLFiles Include="$(OutputPath)Oqtane.Database.MySQL.dll;$(OutputPath)Oqtane.Database.MySQL.pdb;$(OutputPath)MySql.EntityFrameworkCore.dll;$(OutputPath)MySql.Data.dll" DestinationPath="..\Oqtane.Server\bin\$(Configuration)\net8.0\%(Filename)%(Extension)" />
<MySQLFiles Include="$(OutputPath)Oqtane.Database.MySQL.dll;$(OutputPath)Oqtane.Database.MySQL.pdb;$(OutputPath)MySql.EntityFrameworkCore.dll;$(OutputPath)MySql.Data.dll" DestinationPath="..\Oqtane.Server\bin\$(Configuration)\net9.0\%(Filename)%(Extension)" />
</ItemGroup>
<Target Name="PublishProvider" AfterTargets="PostBuildEvent" Inputs="@(MySQLFiles)" Outputs="@(MySQLFiles->'%(DestinationPath)')">

View File

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Version>5.2.4</Version>
<TargetFramework>net9.0</TargetFramework>
<Version>6.0.1</Version>
<Product>Oqtane</Product>
<Authors>Shaun Walker</Authors>
<Company>.NET Foundation</Company>
@ -10,7 +10,7 @@
<Copyright>.NET Foundation</Copyright>
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.4</PackageReleaseNotes>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.0.1</PackageReleaseNotes>
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
@ -25,17 +25,18 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<NoWarn>1701;1702;EF1001;AD0001</NoWarn>
<NoWarn>1701;1702;EF1001;AD0001;NU1608</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<NoWarn>1701;1702;EF1001;AD0001</NoWarn>
<NoWarn>1701;1702;EF1001;AD0001;NU1608</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="EFCore.NamingConventions" Version="8.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.10" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.0" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.1" />
</ItemGroup>
<ItemGroup>
@ -43,7 +44,7 @@
</ItemGroup>
<ItemGroup>
<PostgreSQLFiles Include="$(OutputPath)Oqtane.Database.PostgreSQL.dll;$(OutputPath)Oqtane.Database.PostgreSQL.pdb;$(OutputPath)EFCore.NamingConventions.dll;$(OutputPath)Npgsql.EntityFrameworkCore.PostgreSQL.dll;$(OutputPath)Npgsql.dll" DestinationPath="..\Oqtane.Server\bin\$(Configuration)\net8.0\%(Filename)%(Extension)" />
<PostgreSQLFiles Include="$(OutputPath)Oqtane.Database.PostgreSQL.dll;$(OutputPath)Oqtane.Database.PostgreSQL.pdb;$(OutputPath)EFCore.NamingConventions.dll;$(OutputPath)Npgsql.EntityFrameworkCore.PostgreSQL.dll;$(OutputPath)Npgsql.dll" DestinationPath="..\Oqtane.Server\bin\$(Configuration)\net9.0\%(Filename)%(Extension)" />
</ItemGroup>
<Target Name="PublishProvider" AfterTargets="PostBuildEvent" Inputs="@(PostgreSQLFiles)" Outputs="@(PostgreSQLFiles->'%(DestinationPath)')">

View File

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Version>5.2.4</Version>
<TargetFramework>net9.0</TargetFramework>
<Version>6.0.1</Version>
<Product>Oqtane</Product>
<Authors>Shaun Walker</Authors>
<Company>.NET Foundation</Company>
@ -10,7 +10,7 @@
<Copyright>.NET Foundation</Copyright>
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.4</PackageReleaseNotes>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.0.1</PackageReleaseNotes>
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
@ -33,7 +33,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0" />
</ItemGroup>
<ItemGroup>
@ -41,7 +41,7 @@
</ItemGroup>
<ItemGroup>
<SqlServerFiles Include="$(OutputPath)Oqtane.Database.SqlServer.dll;$(OutputPath)Oqtane.Database.SqlServer.pdb;$(OutputPath)Microsoft.EntityFrameworkCore.SqlServer.dll" DestinationPath="..\Oqtane.Server\bin\$(Configuration)\net8.0\%(Filename)%(Extension)" />
<SqlServerFiles Include="$(OutputPath)Oqtane.Database.SqlServer.dll;$(OutputPath)Oqtane.Database.SqlServer.pdb;$(OutputPath)Microsoft.EntityFrameworkCore.SqlServer.dll" DestinationPath="..\Oqtane.Server\bin\$(Configuration)\net9.0\%(Filename)%(Extension)" />
</ItemGroup>
<Target Name="PublishProvider" AfterTargets="PostBuildEvent" Inputs="@(SqlServerFiles)" Outputs="@(SqlServerFiles->'%(DestinationPath)')">

View File

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Version>5.2.4</Version>
<TargetFramework>net9.0</TargetFramework>
<Version>6.0.1</Version>
<Product>Oqtane</Product>
<Authors>Shaun Walker</Authors>
<Company>.NET Foundation</Company>
@ -10,7 +10,7 @@
<Copyright>.NET Foundation</Copyright>
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.4</PackageReleaseNotes>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.0.1</PackageReleaseNotes>
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
@ -33,7 +33,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.0" />
</ItemGroup>
<ItemGroup>
@ -41,7 +41,7 @@
</ItemGroup>
<ItemGroup>
<SqliteFiles Include="$(OutputPath)Oqtane.Database.Sqlite.dll;$(OutputPath)Oqtane.Database.Sqlite.pdb;$(OutputPath)Microsoft.EntityFrameworkCore.Sqlite.dll" DestinationPath="..\Oqtane.Server\bin\$(Configuration)\net8.0\%(Filename)%(Extension)" />
<SqliteFiles Include="$(OutputPath)Oqtane.Database.Sqlite.dll;$(OutputPath)Oqtane.Database.Sqlite.pdb;$(OutputPath)Microsoft.EntityFrameworkCore.Sqlite.dll" DestinationPath="..\Oqtane.Server\bin\$(Configuration)\net9.0\%(Filename)%(Extension)" />
</ItemGroup>
<Target Name="PublishProvider" AfterTargets="PostBuildEvent" Inputs="@(SqliteFiles)" Outputs="@(SqliteFiles->'%(DestinationPath)')">

View File

@ -5,7 +5,10 @@ public partial class App : Application
public App()
{
InitializeComponent();
MainPage = new MainPage();
}
protected override Window CreateWindow(IActivationState activationState)
{
return new Window(new MainPage());
}
}

View File

@ -1,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net9.0-windows10.0.19041.0</TargetFrameworks>
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
<!-- <TargetFrameworks>net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks> -->
<!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> -->
<!-- <TargetFrameworks>net9.0-android;net9.0-ios;net9.0-maccatalyst</TargetFrameworks> -->
<!-- <TargetFrameworks>$(TargetFrameworks);net9.0-tizen</TargetFrameworks> -->
<OutputType>Exe</OutputType>
<Version>5.2.4</Version>
<Version>6.0.1</Version>
<Product>Oqtane</Product>
<Authors>Shaun Walker</Authors>
<Company>.NET Foundation</Company>
@ -14,7 +14,7 @@
<Copyright>.NET Foundation</Copyright>
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.4</PackageReleaseNotes>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.0.1</PackageReleaseNotes>
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<RootNamespace>Oqtane.Maui</RootNamespace>
@ -28,19 +28,21 @@
<!-- App Identifier -->
<ApplicationId>com.oqtane.maui</ApplicationId>
<ApplicationIdGuid>0E29FC31-1B83-48ED-B6E0-9F3C67B775D4</ApplicationIdGuid>
<!-- Versions -->
<ApplicationDisplayVersion>5.2.4</ApplicationDisplayVersion>
<ApplicationDisplayVersion>6.0.1</ApplicationDisplayVersion>
<ApplicationVersion>1</ApplicationVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">14.2</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">14.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">24.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
</PropertyGroup>
<!-- To develop, package, and publish an app to the Microsoft Store, see: https://aka.ms/MauiTemplateUnpackaged -->
<WindowsPackageType>None</WindowsPackageType>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">15.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">24.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
</PropertyGroup>
<ItemGroup>
<!-- App Icon -->
@ -65,23 +67,22 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="8.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.10" />
<PackageReference Include="System.Net.Http.Json" Version="8.0.1" />
<PackageReference Include="Microsoft.Maui.Controls" Version="8.0.91" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="8.0.91" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="8.0.91" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.0" />
<PackageReference Include="System.Net.Http.Json" Version="9.0.0" />
<PackageReference Include="Microsoft.Maui.Controls" Version="9.0.0" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="9.0.0" />
</ItemGroup>
<ItemGroup>
<Reference Include="Oqtane.Client">
<HintPath>..\Oqtane.Server\bin\Debug\net8.0\Oqtane.Client.dll</HintPath>
<HintPath>..\Oqtane.Server\bin\Debug\net9.0\Oqtane.Client.dll</HintPath>
</Reference>
<Reference Include="Oqtane.Shared">
<HintPath>..\Oqtane.Server\bin\Debug\net8.0\Oqtane.Shared.dll</HintPath>
<HintPath>..\Oqtane.Server\bin\Debug\net9.0\Oqtane.Shared.dll</HintPath>
</Reference>
</ItemGroup>

View File

@ -1,7 +1,7 @@
{
"profiles": {
"Windows Machine": {
"commandName": "MsixPackage",
"commandName": "Project",
"nativeDebugging": false
}
}

View File

@ -417,11 +417,20 @@ Oqtane.Interop = {
}
},
scrollTo: function (top, left, behavior) {
window.scrollTo({
top: top,
left: left,
behavior: behavior
});
const modal = document.querySelector('.modal');
if (modal) {
modal.scrollTo({
top: top,
left: left,
behavior: behavior
});
} else {
window.scrollTo({
top: top,
left: left,
behavior: behavior
});
}
},
scrollToId: function (id) {
var element = document.getElementById(id);

View File

@ -2,7 +2,7 @@
<package>
<metadata>
<id>Oqtane.Client</id>
<version>5.2.4</version>
<version>6.0.1</version>
<authors>Shaun Walker</authors>
<owners>.NET Foundation</owners>
<title>Oqtane Framework</title>
@ -12,14 +12,14 @@
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<license type="expression">MIT</license>
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.4</releaseNotes>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.0.1</releaseNotes>
<readme>readme.md</readme>
<icon>icon.png</icon>
<tags>oqtane</tags>
</metadata>
<files>
<file src="..\Oqtane.Client\bin\Release\net8.0\Oqtane.Client.dll" target="lib\net8.0" />
<file src="..\Oqtane.Client\bin\Release\net8.0\Oqtane.Client.pdb" target="lib\net8.0" />
<file src="..\Oqtane.Client\bin\Release\net9.0\Oqtane.Client.dll" target="lib\net9.0" />
<file src="..\Oqtane.Client\bin\Release\net9.0\Oqtane.Client.pdb" target="lib\net9.0" />
<file src="icon.png" target="" />
<file src="readme.md" target="" />
</files>

View File

@ -2,7 +2,7 @@
<package>
<metadata>
<id>Oqtane.Framework</id>
<version>5.2.4</version>
<version>6.0.1</version>
<authors>Shaun Walker</authors>
<owners>.NET Foundation</owners>
<title>Oqtane Framework</title>
@ -11,8 +11,8 @@
<copyright>.NET Foundation</copyright>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<license type="expression">MIT</license>
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v5.2.4/Oqtane.Framework.5.2.4.Upgrade.zip</projectUrl>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.4</releaseNotes>
<projectUrl>https://github.com/oqtane/oqtane.framework/releases/download/v6.0.1/Oqtane.Framework.6.0.1.Upgrade.zip</projectUrl>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.0.1</releaseNotes>
<readme>readme.md</readme>
<icon>icon.png</icon>
<tags>oqtane framework</tags>

View File

@ -2,7 +2,7 @@
<package>
<metadata>
<id>Oqtane.Server</id>
<version>5.2.4</version>
<version>6.0.1</version>
<authors>Shaun Walker</authors>
<owners>.NET Foundation</owners>
<title>Oqtane Framework</title>
@ -12,14 +12,14 @@
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<license type="expression">MIT</license>
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.4</releaseNotes>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.0.1</releaseNotes>
<readme>readme.md</readme>
<icon>icon.png</icon>
<tags>oqtane</tags>
</metadata>
<files>
<file src="..\Oqtane.Server\bin\Release\net8.0\Oqtane.Server.dll" target="lib\net8.0" />
<file src="..\Oqtane.Server\bin\Release\net8.0\Oqtane.Server.pdb" target="lib\net8.0" />
<file src="..\Oqtane.Server\bin\Release\net9.0\Oqtane.Server.dll" target="lib\net9.0" />
<file src="..\Oqtane.Server\bin\Release\net9.0\Oqtane.Server.pdb" target="lib\net9.0" />
<file src="icon.png" target="" />
<file src="readme.md" target="" />
</files>

View File

@ -2,7 +2,7 @@
<package>
<metadata>
<id>Oqtane.Shared</id>
<version>5.2.4</version>
<version>6.0.1</version>
<authors>Shaun Walker</authors>
<owners>.NET Foundation</owners>
<title>Oqtane Framework</title>
@ -12,14 +12,14 @@
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<license type="expression">MIT</license>
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.4</releaseNotes>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.0.1</releaseNotes>
<readme>readme.md</readme>
<icon>icon.png</icon>
<tags>oqtane</tags>
</metadata>
<files>
<file src="..\Oqtane.Shared\bin\Release\net8.0\Oqtane.Shared.dll" target="lib\net8.0" />
<file src="..\Oqtane.Shared\bin\Release\net8.0\Oqtane.Shared.pdb" target="lib\net8.0" />
<file src="..\Oqtane.Shared\bin\Release\net9.0\Oqtane.Shared.dll" target="lib\net9.0" />
<file src="..\Oqtane.Shared\bin\Release\net9.0\Oqtane.Shared.pdb" target="lib\net9.0" />
<file src="icon.png" target="" />
<file src="readme.md" target="" />
</files>

View File

@ -2,7 +2,7 @@
<package>
<metadata>
<id>Oqtane.Updater</id>
<version>5.2.4</version>
<version>6.0.1</version>
<authors>Shaun Walker</authors>
<owners>.NET Foundation</owners>
<title>Oqtane Framework</title>
@ -12,13 +12,13 @@
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<license type="expression">MIT</license>
<projectUrl>https://github.com/oqtane/oqtane.framework</projectUrl>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.4</releaseNotes>
<releaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.0.1</releaseNotes>
<readme>readme.md</readme>
<icon>icon.png</icon>
<tags>oqtane</tags>
</metadata>
<files>
<file src="..\Oqtane.Updater\bin\Release\net8.0\publish\*.*" target="lib\net8.0" />
<file src="..\Oqtane.Updater\bin\Release\net9.0\publish\*.*" target="lib\net9.0" />
<file src="icon.png" target="" />
<file src="readme.md" target="" />
</files>

View File

@ -1 +1 @@
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net8.0\publish\*" -DestinationPath "Oqtane.Framework.5.2.4.Install.zip" -Force
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net9.0\publish\*" -DestinationPath "Oqtane.Framework.6.0.1.Install.zip" -Force

View File

@ -6,14 +6,22 @@ nuget.exe pack Oqtane.Client.nuspec
nuget.exe pack Oqtane.Server.nuspec
nuget.exe pack Oqtane.Shared.nuspec
nuget.exe pack Oqtane.Framework.nuspec
del /F/Q/S "..\Oqtane.Server\bin\Release\net8.0\publish" > NUL
rmdir /Q/S "..\Oqtane.Server\bin\Release\net8.0\publish"
del /F/Q/S "..\Oqtane.Server\bin\Release\net9.0\publish" > NUL
rmdir /Q/S "..\Oqtane.Server\bin\Release\net9.0\publish"
dotnet publish ..\Oqtane.Server\Oqtane.Server.csproj /p:Configuration=Release
del /F/Q/S "..\Oqtane.Server\bin\Release\net8.0\publish\wwwroot\Content" > NUL
rmdir /Q/S "..\Oqtane.Server\bin\Release\net8.0\publish\wwwroot\Content"
del /F/Q/S "..\Oqtane.Server\bin\Release\net9.0\publish\wwwroot\Content" > NUL
rmdir /Q/S "..\Oqtane.Server\bin\Release\net9.0\publish\wwwroot\Content"
setlocal ENABLEDELAYEDEXPANSION
set retain=Placeholder.txt
for /D %%i in ("..\Oqtane.Server\bin\Release\net9.0\publish\wwwroot\_content\*") do (
set /A found=0
for %%j in (%retain%) do (
if "%%~nxi" == "%%j" set /A found=1
)
if not !found! == 1 rmdir /Q/S "%%i"
)
set retain=Oqtane.Modules.Admin.Login,Oqtane.Modules.HtmlText
for /D %%i in ("..\Oqtane.Server\bin\Release\net8.0\publish\wwwroot\Modules\*") do (
for /D %%i in ("..\Oqtane.Server\bin\Release\net9.0\publish\wwwroot\Modules\*") do (
set /A found=0
for %%j in (%retain%) do (
if "%%~nxi" == "%%j" set /A found=1
@ -21,18 +29,19 @@ if "%%~nxi" == "%%j" set /A found=1
if not !found! == 1 rmdir /Q/S "%%i"
)
set retain=Oqtane.Themes.BlazorTheme,Oqtane.Themes.OqtaneTheme
for /D %%i in ("..\Oqtane.Server\bin\Release\net8.0\publish\wwwroot\Themes\*") do (
for /D %%i in ("..\Oqtane.Server\bin\Release\net9.0\publish\wwwroot\Themes\*") do (
set /A found=0
for %%j in (%retain%) do (
if "%%~nxi" == "%%j" set /A found=1
)
if not !found! == 1 rmdir /Q/S "%%i"
)
del "..\Oqtane.Server\bin\Release\net8.0\publish\appsettings.json"
ren "..\Oqtane.Server\bin\Release\net8.0\publish\appsettings.release.json" "appsettings.json"
del "..\Oqtane.Server\bin\Release\net9.0\publish\Oqtane.Server.staticwebassets.endpoints.json"
del "..\Oqtane.Server\bin\Release\net9.0\publish\appsettings.json"
ren "..\Oqtane.Server\bin\Release\net9.0\publish\appsettings.release.json" "appsettings.json"
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe ".\install.ps1"
del "..\Oqtane.Server\bin\Release\net8.0\publish\appsettings.json"
del "..\Oqtane.Server\bin\Release\net8.0\publish\web.config"
del "..\Oqtane.Server\bin\Release\net9.0\publish\appsettings.json"
del "..\Oqtane.Server\bin\Release\net9.0\publish\web.config"
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe ".\upgrade.ps1"
dotnet clean -c Release ..\Oqtane.Updater.sln
dotnet build -c Release ..\Oqtane.Updater.sln

View File

@ -1 +1 @@
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net8.0\publish\*" -DestinationPath "Oqtane.Framework.5.2.4.Upgrade.zip" -Force
Compress-Archive -Path "..\Oqtane.Server\bin\Release\net9.0\publish\*" -DestinationPath "Oqtane.Framework.6.0.1.Upgrade.zip" -Force

View File

@ -179,10 +179,6 @@
ManageScripts(resources, alias);
// generate scripts
if (_renderMode == RenderModes.Interactive && _runtime == Runtimes.Server)
{
_scripts += CreateReconnectScript();
}
if (site.PwaIsEnabled && site.PwaAppIconFileId != null && site.PwaSplashIconFileId != null)
{
_scripts += CreatePWAScript(alias, site, route);
@ -196,28 +192,29 @@
_bodyResources += ParseScripts(site.BodyContent);
// set culture if not specified
string culture = Context.Request.Cookies[CookieRequestCultureProvider.DefaultCookieName];
if (culture == null)
string cultureCookie = Context.Request.Cookies[Shared.CookieRequestCultureProvider.DefaultCookieName];
if (cultureCookie == null)
{
// get default language for site
if (site.Languages.Any())
{
// use default language if specified otherwise use first language in collection
culture = (site.Languages.Where(l => l.IsDefault).SingleOrDefault() ?? site.Languages.First()).Code;
cultureCookie = (site.Languages.Where(l => l.IsDefault).SingleOrDefault() ?? site.Languages.First()).Code;
}
else
{
culture = LocalizationManager.GetDefaultCulture();
// fallback language
cultureCookie = LocalizationManager.GetDefaultCulture();
}
SetLocalizationCookie(culture);
// convert language code to culture cookie format (ie. "c=en|uic=en")
cultureCookie = Shared.CookieRequestCultureProvider.MakeCookieValue(new Models.RequestCulture(cultureCookie));
SetLocalizationCookie(cultureCookie);
}
// set language for page
if (!string.IsNullOrEmpty(culture))
if (!string.IsNullOrEmpty(cultureCookie))
{
// localization cookie value in form of c=en|uic=en
_language = culture.Split('|')[0];
_language = _language.Replace("c=", "");
_language = Shared.CookieRequestCultureProvider.ParseCookieValue(cultureCookie).Culture.Name;
}
// create initial PageState
@ -494,25 +491,6 @@
"</script>" + Environment.NewLine;
}
private string CreateReconnectScript()
{
return Environment.NewLine +
"<script>" + Environment.NewLine +
" // Interactive Blazor Server Reconnect" + Environment.NewLine +
" new MutationObserver((mutations, observer) => {" + Environment.NewLine +
" if (document.querySelector('#components-reconnect-modal h5 a')) {" + Environment.NewLine +
" async function attemptReload() {" + Environment.NewLine +
" await fetch('');" + Environment.NewLine +
" location.reload();" + Environment.NewLine +
" }" + Environment.NewLine +
" observer.disconnect();" + Environment.NewLine +
" attemptReload();" + Environment.NewLine +
" setInterval(attemptReload, 5000);" + Environment.NewLine +
" }" + Environment.NewLine +
" }).observe(document.body, { childList: true, subtree: true });" + Environment.NewLine +
"</script>" + Environment.NewLine;
}
private string CreateScrollPositionScript()
{
return Environment.NewLine +
@ -602,7 +580,7 @@
}
}
private void SetLocalizationCookie(string culture)
private void SetLocalizationCookie(string cookieValue)
{
var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions
{
@ -613,8 +591,8 @@
};
Context.Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
Shared.CookieRequestCultureProvider.DefaultCookieName,
cookieValue,
cookieOptions
);
}

View File

@ -517,7 +517,7 @@ namespace Oqtane.Controllers
bool success = true;
using (var stream = new FileStream(Path.Combine(folder, filename + ".tmp"), FileMode.Create))
{
foreach (string filepart in fileparts)
foreach (string filepart in fileparts.Order())
{
try
{

View File

@ -351,9 +351,9 @@ namespace Oqtane.Controllers
return new Dictionary<string, object>()
{
{ "FrameworkVersion", Constants.Version },
{ "ClientReference", $"<Reference Include=\"Oqtane.Client\"><HintPath>..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net8.0\\Oqtane.Client.dll</HintPath></Reference>" },
{ "ServerReference", $"<Reference Include=\"Oqtane.Server\"><HintPath>..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net8.0\\Oqtane.Server.dll</HintPath></Reference>" },
{ "SharedReference", $"<Reference Include=\"Oqtane.Shared\"><HintPath>..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net8.0\\Oqtane.Shared.dll</HintPath></Reference>" },
{ "ClientReference", $"<Reference Include=\"Oqtane.Client\"><HintPath>..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net9.0\\Oqtane.Client.dll</HintPath></Reference>" },
{ "ServerReference", $"<Reference Include=\"Oqtane.Server\"><HintPath>..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net9.0\\Oqtane.Server.dll</HintPath></Reference>" },
{ "SharedReference", $"<Reference Include=\"Oqtane.Shared\"><HintPath>..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net9.0\\Oqtane.Shared.dll</HintPath></Reference>" },
};
});
}

View File

@ -267,8 +267,8 @@ namespace Oqtane.Controllers
return new Dictionary<string, object>()
{
{ "FrameworkVersion", Constants.Version },
{ "ClientReference", $"<Reference Include=\"Oqtane.Client\"><HintPath>..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net8.0\\Oqtane.Client.dll</HintPath></Reference>" },
{ "SharedReference", $"<Reference Include=\"Oqtane.Shared\"><HintPath>..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net8.0\\Oqtane.Shared.dll</HintPath></Reference>" },
{ "ClientReference", $"<Reference Include=\"Oqtane.Client\"><HintPath>..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net9.0\\Oqtane.Client.dll</HintPath></Reference>" },
{ "SharedReference", $"<Reference Include=\"Oqtane.Shared\"><HintPath>..\\..\\{rootFolder}\\Oqtane.Server\\bin\\Debug\\net9.0\\Oqtane.Shared.dll</HintPath></Reference>" },
};
});
}

View File

@ -136,7 +136,7 @@ namespace Oqtane.Controllers
filtered.PhotoFileId = user.PhotoFileId;
filtered.LastLoginOn = user.LastLoginOn;
filtered.LastIPAddress = user.LastIPAddress;
filtered.TwoFactorRequired = false;
filtered.TwoFactorRequired = user.TwoFactorRequired;
filtered.Roles = user.Roles;
filtered.CreatedBy = user.CreatedBy;
filtered.CreatedOn = user.CreatedOn;
@ -347,6 +347,13 @@ namespace Oqtane.Controllers
return user;
}
// GET api/<controller>/validate/x
[HttpGet("validateuser")]
public async Task<UserValidateResult> ValidateUser(string username, string email, string password)
{
return await _userManager.ValidateUser(username, email, password);
}
// GET api/<controller>/validate/x
[HttpGet("validate/{password}")]
public async Task<bool> Validate(string password)

View File

@ -1,5 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Oqtane.Databases.Interfaces;
// ReSharper disable ConvertToUsingDeclaration
@ -9,7 +10,8 @@ namespace Oqtane.Extensions
{
public static DbContextOptionsBuilder UseOqtaneDatabase([NotNull] this DbContextOptionsBuilder optionsBuilder, IDatabase database, string connectionString)
{
database.UseDatabase(optionsBuilder, connectionString);
database.UseDatabase(optionsBuilder, connectionString)
.ConfigureWarnings(warnings => warnings.Log(RelationalEventId.PendingModelChangesWarning));
return optionsBuilder;
}

View File

@ -113,8 +113,11 @@ namespace Microsoft.Extensions.DependencyInjection
internal static IServiceCollection AddOqtaneTransientServices(this IServiceCollection services)
{
// repositories
// services
services.AddTransient<ISiteService, ServerSiteService>();
services.AddTransient<ILocalizationCookieService, ServerLocalizationCookieService>();
// repositories
services.AddTransient<IModuleDefinitionRepository, ModuleDefinitionRepository>();
services.AddTransient<IThemeRepository, ThemeRepository>();
services.AddTransient<IAliasRepository, AliasRepository>();
@ -130,7 +133,6 @@ namespace Microsoft.Extensions.DependencyInjection
services.AddTransient<IPermissionRepository, PermissionRepository>();
services.AddTransient<ISettingRepository, SettingRepository>();
services.AddTransient<ILogRepository, LogRepository>();
services.AddTransient<ILocalizationManager, LocalizationManager>();
services.AddTransient<IJobRepository, JobRepository>();
services.AddTransient<IJobLogRepository, JobLogRepository>();
services.AddTransient<INotificationRepository, NotificationRepository>();
@ -153,12 +155,12 @@ namespace Microsoft.Extensions.DependencyInjection
services.AddTransient<ILogManager, LogManager>();
services.AddTransient<IUpgradeManager, UpgradeManager>();
services.AddTransient<IUserManager, UserManager>();
// obsolete - replaced by ITenantManager
services.AddTransient<ITenantResolver, TenantResolver>();
services.AddTransient<ILocalizationManager, LocalizationManager>();
services.AddTransient<ITokenReplace, TokenReplace>();
// obsolete
services.AddTransient<ITenantResolver, TenantResolver>(); // replaced by ITenantManager
return services;
}

View File

@ -59,8 +59,15 @@ namespace Oqtane.Infrastructure
var currentTime = DateTime.UtcNow;
var lastIndexedOn = Convert.ToDateTime(siteSettings.GetValue(SearchLastIndexedOnSetting, DateTime.MinValue.ToString()));
if (lastIndexedOn == DateTime.MinValue)
{
// reset index
log += $"*Site Index Reset*<br />";
await searchService.DeleteSearchContentsAsync(site.SiteId);
}
var ignorePages = siteSettings.GetValue(SearchIgnorePagesSetting, "").Split(',');
var ignoreEntities = siteSettings.GetValue(SearchIgnoreEntitiesSetting, "").Split(',');
var ignoreEntities = siteSettings.GetValue(SearchIgnoreEntitiesSetting, "File").Split(',');
var pages = pageRepository.GetPages(site.SiteId);
var pageModules = pageModuleRepository.GetPageModules(site.SiteId);

View File

@ -69,6 +69,9 @@ namespace Oqtane.Infrastructure
case "5.2.1":
Upgrade_5_2_1(tenant, scope);
break;
case "6.0.1":
Upgrade_6_0_1(tenant, scope);
break;
}
}
}
@ -371,7 +374,7 @@ namespace Oqtane.Infrastructure
try
{
// delete legacy Views assemblies which will cause startup errors due to missing HostModel
// note that the following files will be deleted however the framework has already started up so a restart will be required
// note that the following files will be deleted however the framework has already started up so another restart will be required
var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
var filepath = Path.Combine(binFolder, "Oqtane.Server.Views.dll");
if (System.IO.File.Exists(filepath)) System.IO.File.Delete(filepath);
@ -441,6 +444,54 @@ namespace Oqtane.Infrastructure
AddPagesToSites(scope, tenant, pageTemplates);
}
private void Upgrade_6_0_1(Tenant tenant, IServiceScope scope)
{
// assemblies which have been relocated to the bin/refs folder in .NET 9
string[] assemblies = {
"Microsoft.AspNetCore.Authorization.dll",
"Microsoft.AspNetCore.Components.Authorization.dll",
"Microsoft.AspNetCore.Components.dll",
"Microsoft.AspNetCore.Components.Forms.dll",
"Microsoft.AspNetCore.Components.Web.dll",
"Microsoft.AspNetCore.Cryptography.Internal.dll",
"Microsoft.AspNetCore.Cryptography.KeyDerivation.dll",
"Microsoft.AspNetCore.Metadata.dll",
"Microsoft.Extensions.Caching.Memory.dll",
"Microsoft.Extensions.Configuration.Binder.dll",
"Microsoft.Extensions.Configuration.FileExtensions.dll",
"Microsoft.Extensions.Configuration.Json.dll",
"Microsoft.Extensions.DependencyInjection.Abstractions.dll",
"Microsoft.Extensions.DependencyInjection.dll",
"Microsoft.Extensions.Diagnostics.Abstractions.dll",
"Microsoft.Extensions.Diagnostics.dll",
"Microsoft.Extensions.Http.dll",
"Microsoft.Extensions.Identity.Core.dll",
"Microsoft.Extensions.Identity.Stores.dll",
"Microsoft.Extensions.Localization.Abstractions.dll",
"Microsoft.Extensions.Localization.dll",
"Microsoft.Extensions.Logging.Abstractions.dll",
"Microsoft.Extensions.Logging.dll",
"Microsoft.Extensions.Options.dll",
"Microsoft.JSInterop.dll",
"System.Text.Json.dll"
};
foreach (var assembly in assemblies)
{
try
{
var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
var filepath = Path.Combine(binFolder, assembly);
if (System.IO.File.Exists(filepath)) System.IO.File.Delete(filepath);
}
catch (Exception ex)
{
// error deleting asesmbly
Debug.WriteLine($"Oqtane Error: 6.0.1 Upgrade Error Removing {assembly} - {ex}");
}
}
}
private void AddPagesToSites(IServiceScope scope, Tenant tenant, List<PageTemplate> pageTemplates)
{
var tenants = scope.ServiceProvider.GetRequiredService<ITenantManager>();

View File

@ -19,6 +19,7 @@ namespace Oqtane.Managers
Task<User> ResetPassword(User user, string token);
User VerifyTwoFactor(User user, string token);
Task<User> LinkExternalAccount(User user, string token, string type, string key, string name);
Task<UserValidateResult> ValidateUser(string username, string email, string password);
Task<bool> ValidatePassword(string password);
Task<Dictionary<string, string>> ImportUsers(int siteId, string filePath, bool notify);
}

View File

@ -339,20 +339,20 @@ namespace Oqtane.Managers
user = _users.GetUser(user.Username);
if (!user.IsDeleted)
{
if (user.TwoFactorRequired)
var alias = _tenantManager.GetAlias();
var twoFactorSetting = _settings.GetSetting(EntityNames.Site, alias.SiteId, "LoginOptions:TwoFactor")?.SettingValue ?? "false";
var twoFactorRequired = twoFactorSetting == "required" || user.TwoFactorRequired;
if (twoFactorRequired)
{
var token = await _identityUserManager.GenerateTwoFactorTokenAsync(identityuser, "Email");
user.TwoFactorCode = token;
user.TwoFactorExpiry = DateTime.UtcNow.AddMinutes(10);
_users.UpdateUser(user);
var alias = _tenantManager.GetAlias();
string url = alias.Protocol + alias.Name;
string siteName = _sites.GetSite(alias.SiteId).Name;
string subject = _localizer["TwoFactorEmailSubject"];
subject = subject.Replace("[SiteName]", siteName);
string body = _localizer["TwoFactorEmailBody"].Value;
body = body.Replace("[UserDisplayName]", user.DisplayName);
body = body.Replace("[URL]", url);
body = body.Replace("[SiteName]", siteName);
body = body.Replace("[Token]", token);
var notification = new Notification(alias.SiteId, user, subject, body);
@ -540,6 +540,30 @@ namespace Oqtane.Managers
return user;
}
public async Task<UserValidateResult> ValidateUser(string username, string email, string password)
{
var validateResult = new UserValidateResult { Succeeded = true };
//validate username
var allowedChars = _identityUserManager.Options.User.AllowedUserNameCharacters;
if (string.IsNullOrWhiteSpace(username) || (!string.IsNullOrEmpty(allowedChars) && username.Any(c => !allowedChars.Contains(c))))
{
validateResult.Succeeded = false;
validateResult.Errors.Add("Message.Username.Invalid", string.Empty);
}
//validate password
var passwordValidator = new PasswordValidator<IdentityUser>();
var passwordResult = await passwordValidator.ValidateAsync(_identityUserManager, null, password);
if (!passwordResult.Succeeded)
{
validateResult.Succeeded = false;
validateResult.Errors.Add("Message.Password.Invalid", string.Empty);
}
return validateResult;
}
public async Task<bool> ValidatePassword(string password)
{
var validator = new PasswordValidator<IdentityUser>();

View File

@ -44,7 +44,7 @@ namespace Oqtane.Migrations
public string PrincipalColumn { get; }
public string PrincipalSchema { get; }
public string PrincipalSchema { get; } = "";
}

View File

@ -0,0 +1,32 @@
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Oqtane.Databases.Interfaces;
using Oqtane.Migrations.EntityBuilders;
using Oqtane.Repository;
namespace Oqtane.Migrations.Tenant
{
[DbContext(typeof(TenantDBContext))]
[Migration("Tenant.06.00.01.01")]
public class AddLanguageName : MultiDatabaseMigration
{
public AddLanguageName(IDatabase database) : base(database)
{
}
protected override void Up(MigrationBuilder migrationBuilder)
{
// Name column was removed in 5.2.4 however SQLite does not support column removal so it had to be restored
if (ActiveDatabase.Name != "Sqlite")
{
var languageEntityBuilder = new LanguageEntityBuilder(migrationBuilder, ActiveDatabase);
languageEntityBuilder.AddStringColumn("Name", 100, true);
}
}
protected override void Down(MigrationBuilder migrationBuilder)
{
// not implemented
}
}
}

View File

@ -45,10 +45,25 @@ namespace Oqtane.Modules.Admin.Files.Manager
var path = folder.Path + file.Name;
var body = "";
if (DocumentExtensions.Contains(Path.GetExtension(file.Name)))
if (System.IO.File.Exists(_fileRepository.GetFilePath(file)))
{
// get the contents of the file
body = System.IO.File.ReadAllText(_fileRepository.GetFilePath(file));
// only non-binary files can be indexed
if (DocumentExtensions.Contains(Path.GetExtension(file.Name)))
{
// get the contents of the file
try
{
body = System.IO.File.ReadAllText(_fileRepository.GetFilePath(file));
}
catch
{
// could not read the file
}
}
}
else
{
removed = true; // file does not exist on disk
}
var searchContent = new SearchContent

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Configurations>Debug;Release</Configurations>
<Version>5.2.4</Version>
<Version>6.0.1</Version>
<Product>Oqtane</Product>
<Authors>Shaun Walker</Authors>
<Company>.NET Foundation</Company>
@ -11,7 +11,7 @@
<Copyright>.NET Foundation</Copyright>
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.4</PackageReleaseNotes>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.0.1</PackageReleaseNotes>
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<RootNamespace>Oqtane</RootNamespace>
@ -33,21 +33,21 @@
<EmbeddedResource Include="Scripts\MigrateTenant.sql" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="HtmlAgilityPack" Version="1.11.67" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.10">
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.0" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.0.0-preview2.24304.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.10" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.5" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.8.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.10" />
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="8.0.10" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="9.0.0" />
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="9.0.0" />
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.10" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.5" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.71" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Oqtane.Client\Oqtane.Client.csproj" />

View File

@ -235,9 +235,9 @@ namespace Oqtane.Providers
return text;
}
public Task ResetIndex()
public Task DeleteSearchContent(int siteId)
{
_searchContentRepository.DeleteAllSearchContent();
_searchContentRepository.DeleteAllSearchContent(siteId);
return Task.CompletedTask;
}
}

View File

@ -12,7 +12,7 @@ namespace Oqtane.Repository
void DeleteSearchContent(int searchContentId);
void DeleteSearchContent(string entityName, string entryId);
void DeleteSearchContent(string uniqueKey);
void DeleteAllSearchContent();
void DeleteAllSearchContent(int siteId);
SearchWord GetSearchWord(string word);
SearchWord AddSearchWord(SearchWord searchWord);

View File

@ -31,7 +31,7 @@ namespace Oqtane.Repository
.ToList()
.ForEach(l => l.IsDefault = false);
}
language.Name = ""; // stored in database but not used (SQLite limitation)
db.Language.Add(language);
db.SaveChanges();
@ -55,6 +55,7 @@ namespace Oqtane.Repository
.ForEach(l => l.IsDefault = false);
}
language.Name = ""; // stored in database but not used (SQLite limitation)
db.SaveChanges();
}

View File

@ -152,11 +152,17 @@ namespace Oqtane.Repository
}
}
public void DeleteAllSearchContent()
public void DeleteAllSearchContent(int siteId)
{
using var db = _dbContextFactory.CreateDbContext();
db.SearchContent.RemoveRange(db.SearchContent);
db.SaveChanges();
// delete in batches of 100 records
var searchContents = db.SearchContent.Where(item => item.SiteId == siteId).Take(100).ToList();
while (searchContents.Count > 0)
{
db.SearchContent.RemoveRange(searchContents);
db.SaveChanges();
searchContents = db.SearchContent.Where(item => item.SiteId == siteId).Take(100).ToList();
}
}
public SearchWord GetSearchWord(string word)

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
@ -118,7 +118,7 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ForgotPasswordEmailBody" xml:space="preserve">
<value>Dear [UserDisplayName]&lt;br&gt;&lt;br&gt;You recently requested to reset your password. Please use the link below to complete the process: &lt;b&gt;&lt;a href="[URL]"&gt;&lt;br&gt;&lt;br&gt;Click here to Reset Password&lt;/a&gt;&lt;/b&gt;&lt;br&gt;&lt;br&gt;Please note that the link is only valid for 24 hours so if you are unable to take action within that time period, you should initiate another password reset on the site.&lt;br&gt;&lt;br&gt;If you did not request to reset your password you can safely ignore this message.&lt;br&gt;&lt;br&gt;Thank You!&lt;br&gt;[SiteName] team</value>
<value>Dear [UserDisplayName]&lt;br&gt;&lt;br&gt;You recently requested to reset your password. Please use the link below to complete the process: &lt;b&gt;&lt;a href="[URL]"&gt;&lt;br&gt;&lt;br&gt;Click here to Reset Password&lt;/a&gt;&lt;/b&gt;&lt;br&gt;&lt;br&gt;Please note that the link is only valid for 24 hours so if you are unable to take action within that time period, you should initiate another password reset on the site.&lt;br&gt;&lt;br&gt;If you did not request to reset your password you can safely ignore this message.&lt;br&gt;&lt;br&gt;Thank You!&lt;br&gt;[SiteName] Team</value>
</data>
<data name="ForgotPasswordEmailSubject" xml:space="preserve">
<value>Password Reset Notification Sent For [SiteName]</value>
@ -130,7 +130,7 @@
<value>User Account Notification for [SiteName]</value>
</data>
<data name="TwoFactorEmailBody" xml:space="preserve">
<value>Dear [UserDisplayName] + ",&lt;br&gt;&lt;br&gt;You requested a secure verification code to log in to your account. Please enter the secure verification code on the site:&lt;br&gt;&lt;br&gt;&lt;b&gt;[Token] &lt;/b&gt;&lt;br&gt;&lt;br&gt;Please note that the code is only valid for 10 minutes so if you are unable to take action within that time period, you should initiate a new login on the [Alias].&lt;br&gt;&lt;br&gt;Thank You!&lt;br&gt;[SiteName] Team"</value>
<value>Dear [UserDisplayName],&lt;br&gt;&lt;br&gt;You requested a secure verification code to log in to your account. Please enter the secure verification code on the site:&lt;br&gt;&lt;br&gt;&lt;b&gt;[Token] &lt;/b&gt;&lt;br&gt;&lt;br&gt;Please note that the code is only valid for 10 minutes so if you are unable to take action within that time period, you should initiate a new login on the site.&lt;br&gt;&lt;br&gt;Thank You!&lt;br&gt;[SiteName] Team</value>
</data>
<data name="TwoFactorEmailSubject" xml:space="preserve">
<value>User Verification Code for [SiteName]</value>

View File

@ -0,0 +1,35 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
using Oqtane.Documentation;
namespace Oqtane.Services
{
[PrivateApi("Don't show in the documentation, as everything should use the Interface")]
public class ServerLocalizationCookieService : ILocalizationCookieService
{
private readonly IHttpContextAccessor _accessor;
public ServerLocalizationCookieService(IHttpContextAccessor accessor)
{
_accessor = accessor;
}
public Task SetLocalizationCookieAsync(string culture)
{
var localizationCookieValue = CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture));
_accessor.HttpContext.Response.Cookies.Append(CookieRequestCultureProvider.DefaultCookieName, localizationCookieValue, new CookieOptions
{
Path = "/",
Expires = DateTimeOffset.UtcNow.AddYears(365),
SameSite = SameSiteMode.Lax,
Secure = true, // Ensure the cookie is only sent over HTTPS
HttpOnly = false // cookie is updated using JS Interop in Interactive render mode
});
return Task.CompletedTask;
}
}
}

View File

@ -149,6 +149,12 @@ namespace Oqtane.Services
return result;
}
public async Task DeleteSearchContentsAsync(int siteId)
{
var searchProvider = GetSearchProvider(siteId);
await searchProvider.DeleteSearchContent(siteId);
}
private ISearchProvider GetSearchProvider(int siteId)
{
var providerName = GetSearchProviderSetting(siteId);

View File

@ -9,7 +9,7 @@ namespace [Owner].Module.[Module].Services
{
public class [Module]Service : ServiceBase, I[Module]Service
{
public [Module]Service(IHttpClientFactory http, SiteState siteState) : base(http, siteState) { }
public [Module]Service(HttpClient http, SiteState siteState) : base(http, siteState) { }
private string Apiurl => CreateApiUrl("[Module]");

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Version>1.0.0</Version>
<Authors>[Owner]</Authors>
<Company>[Owner]</Company>
@ -13,12 +13,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.10" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.10" />
<PackageReference Include="System.Net.Http.Json" Version="8.0.5" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.0" />
<PackageReference Include="System.Net.Http.Json" Version="9.0.0" />
</ItemGroup>
<ItemGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<AccelerateBuildsInVisualStudio>false</AccelerateBuildsInVisualStudio>
</PropertyGroup>

View File

@ -20,12 +20,12 @@
</dependencies>
</metadata>
<files>
<file src="..\Client\bin\Release\net8.0\[Owner].Module.[Module].Client.Oqtane.dll" target="lib\net8.0" />
<file src="..\Client\bin\Release\net8.0\[Owner].Module.[Module].Client.Oqtane.pdb" target="lib\net8.0" />
<file src="..\Server\bin\Release\net8.0\[Owner].Module.[Module].Server.Oqtane.dll" target="lib\net8.0" />
<file src="..\Server\bin\Release\net8.0\[Owner].Module.[Module].Server.Oqtane.pdb" target="lib\net8.0" />
<file src="..\Shared\bin\Release\net8.0\[Owner].Module.[Module].Shared.Oqtane.dll" target="lib\net8.0" />
<file src="..\Shared\bin\Release\net8.0\[Owner].Module.[Module].Shared.Oqtane.pdb" target="lib\net8.0" />
<file src="..\Client\bin\Release\net9.0\[Owner].Module.[Module].Client.Oqtane.dll" target="lib\net9.0" />
<file src="..\Client\bin\Release\net9.0\[Owner].Module.[Module].Client.Oqtane.pdb" target="lib\net9.0" />
<file src="..\Server\bin\Release\net9.0\[Owner].Module.[Module].Server.Oqtane.dll" target="lib\net9.0" />
<file src="..\Server\bin\Release\net9.0\[Owner].Module.[Module].Server.Oqtane.pdb" target="lib\net9.0" />
<file src="..\Shared\bin\Release\net9.0\[Owner].Module.[Module].Shared.Oqtane.dll" target="lib\net9.0" />
<file src="..\Shared\bin\Release\net9.0\[Owner].Module.[Module].Shared.Oqtane.pdb" target="lib\net9.0" />
<file src="..\Server\wwwroot\**\*.*" target="wwwroot" />
<file src="icon.png" target="" />
</files>

View File

@ -1,7 +1,7 @@
XCOPY "..\Client\bin\Debug\net8.0\[Owner].Module.[Module].Client.Oqtane.dll" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\net8.0\" /Y
XCOPY "..\Client\bin\Debug\net8.0\[Owner].Module.[Module].Client.Oqtane.pdb" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\net8.0\" /Y
XCOPY "..\Server\bin\Debug\net8.0\[Owner].Module.[Module].Server.Oqtane.dll" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\net8.0\" /Y
XCOPY "..\Server\bin\Debug\net8.0\[Owner].Module.[Module].Server.Oqtane.pdb" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\net8.0\" /Y
XCOPY "..\Shared\bin\Debug\net8.0\[Owner].Module.[Module].Shared.Oqtane.dll" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\net8.0\" /Y
XCOPY "..\Shared\bin\Debug\net8.0\[Owner].Module.[Module].Shared.Oqtane.pdb" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\net8.0\" /Y
XCOPY "..\Client\bin\Debug\net9.0\[Owner].Module.[Module].Client.Oqtane.dll" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\net9.0\" /Y
XCOPY "..\Client\bin\Debug\net9.0\[Owner].Module.[Module].Client.Oqtane.pdb" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\net9.0\" /Y
XCOPY "..\Server\bin\Debug\net9.0\[Owner].Module.[Module].Server.Oqtane.dll" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\net9.0\" /Y
XCOPY "..\Server\bin\Debug\net9.0\[Owner].Module.[Module].Server.Oqtane.pdb" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\net9.0\" /Y
XCOPY "..\Shared\bin\Debug\net9.0\[Owner].Module.[Module].Shared.Oqtane.dll" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\net9.0\" /Y
XCOPY "..\Shared\bin\Debug\net9.0\[Owner].Module.[Module].Shared.Oqtane.pdb" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\net9.0\" /Y
XCOPY "..\Server\wwwroot\*" "..\..\[RootFolder]\Oqtane.Server\wwwroot\" /Y /S /I

View File

@ -1,7 +1,7 @@
cp -f "../Client/bin/Debug/net8.0/[Owner].Module.[Module].Client.Oqtane.dll" "../../oqtane.framework/Oqtane.Server/bin/Debug/net8.0/"
cp -f "../Client/bin/Debug/net8.0/[Owner].Module.[Module].Client.Oqtane.pdb" "../../oqtane.framework/Oqtane.Server/bin/Debug/net8.0/"
cp -f "../Server/bin/Debug/net8.0/[Owner].Module.[Module].Server.Oqtane.dll" "../../oqtane.framework/Oqtane.Server/bin/Debug/net8.0/"
cp -f "../Server/bin/Debug/net8.0/[Owner].Module.[Module].Server.Oqtane.pdb" "../../oqtane.framework/Oqtane.Server/bin/Debug/net8.0/"
cp -f "../Shared/bin/Debug/net8.0/[Owner].Module.[Module].Shared.Oqtane.dll" "../../oqtane.framework/Oqtane.Server/bin/Debug/net8.0/"
cp -f "../Shared/bin/Debug/net8.0/[Owner].Module.[Module].Shared.Oqtane.pdb" "../../oqtane.framework/Oqtane.Server/bin/Debug/net8.0/"
cp -f "../Client/bin/Debug/net9.0/[Owner].Module.[Module].Client.Oqtane.dll" "../../oqtane.framework/Oqtane.Server/bin/Debug/net9.0/"
cp -f "../Client/bin/Debug/net9.0/[Owner].Module.[Module].Client.Oqtane.pdb" "../../oqtane.framework/Oqtane.Server/bin/Debug/net9.0/"
cp -f "../Server/bin/Debug/net9.0/[Owner].Module.[Module].Server.Oqtane.dll" "../../oqtane.framework/Oqtane.Server/bin/Debug/net9.0/"
cp -f "../Server/bin/Debug/net9.0/[Owner].Module.[Module].Server.Oqtane.pdb" "../../oqtane.framework/Oqtane.Server/bin/Debug/net9.0/"
cp -f "../Shared/bin/Debug/net9.0/[Owner].Module.[Module].Shared.Oqtane.dll" "../../oqtane.framework/Oqtane.Server/bin/Debug/net9.0/"
cp -f "../Shared/bin/Debug/net9.0/[Owner].Module.[Module].Shared.Oqtane.pdb" "../../oqtane.framework/Oqtane.Server/bin/Debug/net9.0/"
cp -rf "../Server/wwwroot/"* "../../oqtane.framework/Oqtane.Server/wwwroot/"

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
<Version>1.0.0</Version>
<Product>[Owner].Module.[Module]</Product>
@ -19,10 +19,10 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.0" />
</ItemGroup>
<ItemGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Version>1.0.0</Version>
<Product>[Owner].Module.[Module]</Product>
<Authors>[Owner]</Authors>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Version>1.0.0</Version>
<Authors>[Owner]</Authors>
<Company>[Owner]</Company>
@ -13,9 +13,9 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.10" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.0" />
</ItemGroup>
<ItemGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<AccelerateBuildsInVisualStudio>false</AccelerateBuildsInVisualStudio>
</PropertyGroup>

View File

@ -20,8 +20,8 @@
</dependencies>
</metadata>
<files>
<file src="..\Client\bin\Release\net8.0\[Owner].Theme.[Theme].Client.Oqtane.dll" target="lib\net8.0" />
<file src="..\Client\bin\Release\net8.0\[Owner].Theme.[Theme].Client.Oqtane.pdb" target="lib\net8.0" />
<file src="..\Client\bin\Release\net9.0\[Owner].Theme.[Theme].Client.Oqtane.dll" target="lib\net9.0" />
<file src="..\Client\bin\Release\net9.0\[Owner].Theme.[Theme].Client.Oqtane.pdb" target="lib\net9.0" />
<file src="..\Client\wwwroot\**\*.*" target="wwwroot" />
<file src="icon.png" target="" />
</files>

View File

@ -1,3 +1,3 @@
XCOPY "..\Client\bin\Debug\net8.0\[Owner].Theme.[Theme].Client.Oqtane.dll" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\net8.0\" /Y
XCOPY "..\Client\bin\Debug\net8.0\[Owner].Theme.[Theme].Client.Oqtane.pdb" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\net8.0\" /Y
XCOPY "..\Client\bin\Debug\net9.0\[Owner].Theme.[Theme].Client.Oqtane.dll" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\net9.0\" /Y
XCOPY "..\Client\bin\Debug\net9.0\[Owner].Theme.[Theme].Client.Oqtane.pdb" "..\..\[RootFolder]\Oqtane.Server\bin\Debug\net9.0\" /Y
XCOPY "..\Client\wwwroot\*" "..\..\[RootFolder]\Oqtane.Server\wwwroot\" /Y /S /I

View File

@ -1,3 +1,3 @@
cp -f "../Client/bin/Debug/net8.0/[Owner].Theme.[Theme].Client.Oqtane.dll" "../../oqtane.framework/Oqtane.Server/bin/Debug/net8.0/"
cp -f "../Client/bin/Debug/net8.0/[Owner].Theme.[Theme].Client.Oqtane.pdb" "../../oqtane.framework/Oqtane.Server/bin/Debug/net8.0/"
cp -f "../Client/bin/Debug/net9.0/[Owner].Theme.[Theme].Client.Oqtane.dll" "../../oqtane.framework/Oqtane.Server/bin/Debug/net9.0/"
cp -f "../Client/bin/Debug/net9.0/[Owner].Theme.[Theme].Client.Oqtane.pdb" "../../oqtane.framework/Oqtane.Server/bin/Debug/net9.0/"
cp -rf "../Server/wwwroot/"* "../../oqtane.framework/Oqtane.Server/wwwroot/"

View File

@ -417,11 +417,20 @@ Oqtane.Interop = {
}
},
scrollTo: function (top, left, behavior) {
window.scrollTo({
top: top,
left: left,
behavior: behavior
});
const modal = document.querySelector('.modal');
if (modal) {
modal.scrollTo({
top: top,
left: left,
behavior: behavior
});
} else {
window.scrollTo({
top: top,
left: left,
behavior: behavior
});
}
},
scrollToId: function (id) {
var element = document.getElementById(id);

View File

@ -11,7 +11,7 @@ namespace Oqtane.Services
Task<List<SearchResult>> GetSearchResultsAsync(SearchQuery searchQuery);
Task SaveSearchContent(SearchContent searchContent, Dictionary<string, string> siteSettings);
Task ResetIndex();
Task DeleteSearchContent(int siteId);
}
}

View File

@ -9,5 +9,7 @@ namespace Oqtane.Services
Task<SearchResults> GetSearchResultsAsync(SearchQuery searchQuery);
Task<string> SaveSearchContentsAsync(List<SearchContent> searchContents, Dictionary<string, string> siteSettings);
Task DeleteSearchContentsAsync(int siteId);
}
}

View File

@ -56,7 +56,9 @@ namespace Oqtane.Models
public string Description { get; set; }
/// <summary>
/// Deprecated - not used
/// Deprecated
/// Note that this property still exists in the database because columns cannot be dropped in SQLite
/// Therefore the property must be retained/mapped even though the framework no longer uses it
/// </summary>
public bool? IsDeleted { get; set; }

View File

@ -63,7 +63,9 @@ namespace Oqtane.Models
public bool IsSystem { get; set; }
/// <summary>
/// Deprecated - not used
/// Deprecated
/// Note that this property still exists in the database because columns cannot be dropped in SQLite
/// Therefore the property must be retained/mapped even though the framework no longer uses it
/// </summary>
public bool? IsDeleted { get; set; }

View File

@ -29,9 +29,10 @@ namespace Oqtane.Models
/// </summary>
public bool IsDefault { get; set; }
[NotMapped]
/// <summary>
/// Language Name - corresponds to <see cref="Culture.DisplayName"/>, _not_ <see cref="Culture.Name"/>
/// Note that this property still exists in the database because columns cannot be dropped in SQLite
/// Therefore the property must be retained/mapped even though the framework populates it from the Culture API
/// </summary>
public string Name { get; set; }

View File

@ -0,0 +1,67 @@
using System.Globalization;
using System;
namespace Oqtane.Models
{
/// <summary>
/// Culture information describing a Culture
/// </summary>
public class RequestCulture
{
/// <summary>
/// Creates a new <see cref="RequestCulture"/> object with its <see cref="Culture"/> and <see cref="UICulture"/>
/// properties set to the same <see cref="CultureInfo"/> value.
/// </summary>
/// <param name="culture">The <see cref="CultureInfo"/> for the request.</param>
public RequestCulture(CultureInfo culture)
: this(culture, culture)
{
}
/// <summary>
/// Creates a new <see cref="RequestCulture"/> object with its <see cref="Culture"/> and <see cref="UICulture"/>
/// properties set to the same <see cref="CultureInfo"/> value.
/// </summary>
/// <param name="culture">The culture for the request.</param>
public RequestCulture(string culture)
: this(culture, culture)
{
}
/// <summary>
/// Creates a new <see cref="RequestCulture"/> object with its <see cref="Culture"/> and <see cref="UICulture"/>
/// properties set to the respective <see cref="CultureInfo"/> values provided.
/// </summary>
/// <param name="culture">The culture for the request to be used for formatting.</param>
/// <param name="uiCulture">The culture for the request to be used for text, i.e. language.</param>
public RequestCulture(string culture, string uiCulture)
: this(new CultureInfo(culture), new CultureInfo(uiCulture))
{
}
/// <summary>
/// Creates a new <see cref="RequestCulture"/> object with its <see cref="Culture"/> and <see cref="UICulture"/>
/// properties set to the respective <see cref="CultureInfo"/> values provided.
/// </summary>
/// <param name="culture">The <see cref="CultureInfo"/> for the request to be used for formatting.</param>
/// <param name="uiCulture">The <see cref="CultureInfo"/> for the request to be used for text, i.e. language.</param>
public RequestCulture(CultureInfo culture, CultureInfo uiCulture)
{
ArgumentNullException.ThrowIfNull(culture);
ArgumentNullException.ThrowIfNull(uiCulture);
Culture = culture;
UICulture = uiCulture;
}
/// <summary>
/// Gets the <see cref="CultureInfo"/> for the request to be used for formatting.
/// </summary>
public CultureInfo Culture { get; }
/// <summary>
/// Gets the <see cref="CultureInfo"/> for the request to be used for text, i.e. language;
/// </summary>
public CultureInfo UICulture { get; }
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Oqtane.Models
{
public class UserValidateResult
{
public bool Succeeded { get; set; }
public IDictionary<string, string> Errors { get; set; } = new Dictionary<string, string>();
}
}

View File

@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<Configurations>Debug;Release</Configurations>
<Version>5.2.4</Version>
<Version>6.0.1</Version>
<Product>Oqtane</Product>
<Authors>Shaun Walker</Authors>
<Company>.NET Foundation</Company>
@ -11,7 +11,7 @@
<Copyright>.NET Foundation</Copyright>
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.4</PackageReleaseNotes>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.0.1</PackageReleaseNotes>
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<RootNamespace>Oqtane</RootNamespace>
@ -19,11 +19,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.10" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.Text.Json" Version="8.0.5" />
<PackageReference Include="System.Text.Json" Version="9.0.0" />
</ItemGroup>
</Project>

View File

@ -4,8 +4,8 @@ namespace Oqtane.Shared
{
public class Constants
{
public static readonly string Version = "5.2.4";
public const string ReleaseVersions = "1.0.0,1.0.1,1.0.2,1.0.3,1.0.4,2.0.0,2.0.1,2.0.2,2.1.0,2.2.0,2.3.0,2.3.1,3.0.0,3.0.1,3.0.2,3.0.3,3.1.0,3.1.1,3.1.2,3.1.3,3.1.4,3.2.0,3.2.1,3.3.0,3.3.1,3.4.0,3.4.1,3.4.2,3.4.3,4.0.0,4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,5.0.0,5.0.1,5.0.2,5.0.3,5.1.0,5.1.1,5.1.2,5.2.0,5.2.1,5.2.2,5.2.3,5.2.4";
public static readonly string Version = "6.0.1";
public const string ReleaseVersions = "1.0.0,1.0.1,1.0.2,1.0.3,1.0.4,2.0.0,2.0.1,2.0.2,2.1.0,2.2.0,2.3.0,2.3.1,3.0.0,3.0.1,3.0.2,3.0.3,3.1.0,3.1.1,3.1.2,3.1.3,3.1.4,3.2.0,3.2.1,3.3.0,3.3.1,3.4.0,3.4.1,3.4.2,3.4.3,4.0.0,4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,5.0.0,5.0.1,5.0.2,5.0.3,5.1.0,5.1.1,5.1.2,5.2.0,5.2.1,5.2.2,5.2.3,5.2.4,6.0.0,6.0.1";
public const string PackageId = "Oqtane.Framework";
public const string ClientId = "Oqtane.Client";
public const string UpdaterPackageId = "Oqtane.Updater";

View File

@ -0,0 +1,89 @@
using System;
using Oqtane.Models;
namespace Oqtane.Shared
{
public class CookieRequestCultureProvider
{
private const char _cookieSeparator = '|';
private const string _culturePrefix = "c=";
private const string _uiCulturePrefix = "uic=";
/// <summary>
/// Represent the default cookie name used to track the user's preferred culture information, which is ".AspNetCore.Culture".
/// </summary>
public static readonly string DefaultCookieName = ".AspNetCore.Culture";
/// <summary>
/// The name of the cookie that contains the user's preferred culture information.
/// Defaults to <see cref="DefaultCookieName"/>.
/// </summary>
public string CookieName { get; set; } = DefaultCookieName;
/// <summary>
/// Creates a string representation of a <see cref="RequestCulture"/> for placement in a cookie.
/// </summary>
/// <param name="requestCulture">The <see cref="RequestCulture"/>.</param>
/// <returns>The cookie value.</returns>
public static string MakeCookieValue(RequestCulture requestCulture)
{
ArgumentNullException.ThrowIfNull(requestCulture);
return string.Join(_cookieSeparator,
$"{_culturePrefix}{requestCulture.Culture.Name}",
$"{_uiCulturePrefix}{requestCulture.UICulture.Name}");
}
/// <summary>
/// Parses a <see cref="RequestCulture"/> from the specified cookie value.
/// Returns <c>null</c> if parsing fails.
/// </summary>
/// <param name="value">The cookie value to parse.</param>
/// <returns>The <see cref="RequestCulture"/> or <c>null</c> if parsing fails.</returns>
public static RequestCulture ParseCookieValue(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
return null;
}
Span<Range> parts = stackalloc Range[3];
var valueSpan = value.AsSpan();
if (valueSpan.Split(parts, _cookieSeparator, StringSplitOptions.RemoveEmptyEntries) != 2)
{
return null;
}
var potentialCultureName = valueSpan[parts[0]];
var potentialUICultureName = valueSpan[parts[1]];
if (!potentialCultureName.StartsWith(_culturePrefix, StringComparison.Ordinal) || !
potentialUICultureName.StartsWith(_uiCulturePrefix, StringComparison.Ordinal))
{
return null;
}
var cultureName = potentialCultureName.Slice(_culturePrefix.Length);
var uiCultureName = potentialUICultureName.Slice(_uiCulturePrefix.Length);
if (cultureName.IsEmpty && uiCultureName.IsEmpty)
{
// No values specified for either so no match
return null;
}
if (!cultureName.IsEmpty && uiCultureName.IsEmpty)
{
// Value for culture but not for UI culture so default to culture value for both
uiCultureName = cultureName;
}
else if (cultureName.IsEmpty && !uiCultureName.IsEmpty)
{
// Value for UI culture but not for culture so default to UI culture value for both
cultureName = uiCultureName;
}
return new RequestCulture(cultureName.ToString(), uiCultureName.ToString());
}
}
}

View File

@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<OutputType>Exe</OutputType>
<Version>5.2.4</Version>
<Version>6.0.1</Version>
<Product>Oqtane</Product>
<Authors>Shaun Walker</Authors>
<Company>.NET Foundation</Company>
@ -11,7 +11,7 @@
<Copyright>.NET Foundation</Copyright>
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.4</PackageReleaseNotes>
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.0.1</PackageReleaseNotes>
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
<RepositoryType>Git</RepositoryType>
<RootNamespace>Oqtane</RootNamespace>

View File

@ -1,26 +1,28 @@
# Latest Release
[5.2.3](https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.3) was released on September 23, 2024 and is a maintenance release including 55 pull requests by 8 different contributors, pushing the total number of project commits all-time to over 5800. The Oqtane framework continues to evolve at a rapid pace to meet the needs of .NET developers.
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Foqtane%2Foqtane.framework%2Fmaster%2Fazuredeploy.json)
# Oqtane Framework
![Oqtane](https://github.com/oqtane/framework/blob/master/oqtane.png?raw=true "Oqtane")
Oqtane is an open source CMS and Application Framework that provides advanced functionality for developing web, mobile, and desktop applications on .NET. It leverages Blazor to compose a fully dynamic digital experience which can be hosted on Static Blazor, Blazor Server, Blazor WebAssembly, or Blazor Hybrid (via .NET MAUI).
Oqtane is an open source Content Management System (CMS) and Application Framework that provides advanced functionality for developing web, mobile, and desktop applications on modern .NET.
Oqtane is being developed based on some fundamental principles which are outlined in the [Oqtane Philosophy](https://www.oqtane.org/blog/!/20/oqtane-philosophy).
Oqtane allows you to "Build Applications, Not Infrastructure" which means that you can focus your investment on solving your unique business challenges rather than wasting time and effort on building general infrastructure.
Please note that this project is owned by the .NET Foundation and is governed by the **[.NET Foundation Contributor Covenant Code of Conduct](https://dotnetfoundation.org/code-of-conduct)**
Oqtane is "Rocket Fuel for Blazor" as it provides powerful capabilities to accelerate your Blazor development experience, providing scalable services and a composable UI which can be hosted on Static Blazor, Blazor Server, Blazor WebAssembly, or Blazor Hybrid (via .NET MAUI).
# Getting Started (Version 5.x)
Oqtane is being developed based on some fundamental principles which are outlined in the [Oqtane Philosophy](https://www.oqtane.org/blog/!/20/oqtane-philosophy). This project is an official member of the .NET Foundation and is governed by the **[.NET Foundation Contributor Covenant Code of Conduct](https://dotnetfoundation.org/code-of-conduct)**
# Latest Release
[6.0.0](https://github.com/oqtane/oqtane.framework/releases/tag/v6.0.0) was released on November 14, 2024 and is a major release including 39 pull requests by 6 different contributors, pushing the total number of project commits all-time to over 6000. The Oqtane framework continues to evolve at a rapid pace to meet the needs of .NET developers.
[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Foqtane%2Foqtane.framework%2Fmaster%2Fazuredeploy.json)
# Getting Started (Version 6.x)
**Installing using source code from the Dev/Master branch:**
- Install **[.NET 8.0.8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0)**.
- Install **[.NET 9.0.0 SDK](https://dotnet.microsoft.com/download/dotnet/9.0)**.
- Install the latest edition (v17.9 or higher) of [Visual Studio 2022](https://visualstudio.microsoft.com/downloads) with the **ASP.NET and web development** workload enabled. Oqtane works with ALL editions of Visual Studio from Community to Enterprise. If you wish to use LocalDB for development ( not a requirement as Oqtane supports SQLite, mySQL, and PostgreSQL ) you must also install the **Data storage and processing**.
- Install the latest edition (v17.12 or higher) of [Visual Studio 2022](https://visualstudio.microsoft.com/downloads) with the **ASP.NET and web development** workload enabled. Oqtane works with ALL editions of Visual Studio from Community to Enterprise. If you wish to use LocalDB for development ( not a requirement as Oqtane supports SQLite, mySQL, and PostgreSQL ) you must also install the **Data storage and processing**.
- Clone (or download) the Oqtane Master or Dev branch source code to your local system.
@ -83,11 +85,12 @@ Connect with other developers, get support, and share ideas by joining the Oqtan
# Roadmap
This project is open source, and therefore is a work in progress...
[6.0.0](https://github.com/oqtane/oqtane.framework/releases/tag/v6.0.0) (Nov 14, 2024)
- [x] Migration to .NET 9
Backlog (TBD)
- [ ] Azure Autoscale support (ie. web farm)
- [ ] Folder Providers
- [ ] Generative AI Integration
[5.2.4](https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.4) (Oct 17, 2024)
- [x] Stabilization improvements
[5.2.3](https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.3) (Sep 23, 2024)
- [x] Stabilization improvements

15
SECURITY.md Normal file
View File

@ -0,0 +1,15 @@
# Security Policy
## Reporting a Vulnerability
We make every effort to ensure rapid and thorough analysis of reported issues and, where appropriate, provide workarounds and updated application releases to fix them. If you identify a potential security vulnerability please report it via [the GitHub feature for reporting a security vulnerability](https://github.com/oqtane/oqtane.framework/security/advisories/new).
All submitted information is viewed only by members of the Oqtane Security Team, and will not be discussed outside the Team without the permission of the person/company who reported the issue. Each confirmed issue is assigned a severity level (critical, moderate, or low) corresponding to its potential impact on an Oqtane installation.
* **Critical** means the issue can be exploited by a remote attacker to gain access to data or functionality. All critical issue security bulletins include a recommended workaround or fix that should be applied as soon as possible.
* **Moderate** means the issue can compromise data or functionality on a portal/website only if some other condition is met (e.g. a particular module or a user within a particular role is required). Moderate issue security bulletins typically include recommended actions to resolve the issue.
* **Low** means the issue is very difficult to exploit or has a limited potential impact.
Once an issue has been resolved via a public release of Oqtane, the release notes on GitHub are updated to reflect that security bulletins exist for the release. We strongly suggest using the "Watch" option on GitHub for "Releases" at a minimum to receive notifications of updated Oqtane releases.
As a general policy, Oqtane does not issue Hot Fix releases to prior versions of the software. If a remediation is possible via configuration it shall be noted as applicable in the posted bulletins.