Skip to content

Commit 99cd897

Browse files
authored
Update and cleanup (#200)
* Cleaned and commented. modified: src/BlogSettings.cs modified: src/Controllers/AccountController.cs modified: src/Controllers/BlogController.cs modified: src/Controllers/RobotsController.cs modified: src/Controllers/SharedController.cs modified: src/Models/Comment.cs modified: src/Models/LoginViewModel.cs modified: src/Models/Post.cs modified: src/PostListView.cs modified: src/Services/BlogUserServices.cs modified: src/Services/FileBlogService.cs modified: src/Services/IBlogService.cs modified: src/Services/IUserServices.cs modified: src/Services/InMemoryBlogServiceBase.cs modified: src/Services/MetaWeblogService.cs modified: src/Startup.cs * Removed auto-gen docs modified: src/BlogSettings.cs modified: src/Controllers/AccountController.cs modified: src/Controllers/BlogController.cs modified: src/Controllers/RobotsController.cs modified: src/Controllers/SharedController.cs modified: src/Models/LoginViewModel.cs modified: src/PostListView.cs modified: src/Services/FileBlogService.cs modified: src/Services/IUserServices.cs * Fix some ConfigureAwait issues introduced earlier, add some constants/resources, change index view to use IAsyncEnumerable foreach and modify controller accordingly. modified: src/Controllers/BlogController.cs modified: src/Controllers/RobotsController.cs modified: src/Models/Comment.cs modified: src/Models/Post.cs modified: src/Services/FileBlogService.cs modified: src/Services/IBlogService.cs modified: src/Services/InMemoryBlogServiceBase.cs modified: src/Services/MetaWeblogService.cs modified: src/Startup.cs modified: src/Views/Shared/_Layout.cshtml modified: src/appsettings.json * Update solution and localization files for VS 17.0 - Updated `Miniblog.Core.sln` to Visual Studio version 17.0 and added new global properties for RESX synchronization. - Created new XLIFF files for localization in `en-CA`, `en-GB`, `es-US`, `fr-CA`, and `fr-FR`, enhancing multilingual support. - Updated `Resources.Designer.cs` to reflect the new StronglyTypedResourceBuilder version. - Modified `.resx` files to include a new XML schema and updated resource entries for compatibility with the latest standards. * Update package references and resource settings Upgraded versions of several packages in `Miniblog.Core.csproj`, including `JavaScriptEngineSwitcher.V8`, `LigerShark.WebOptimizer.Core`, `Microsoft.ClearScript.V8.Native.win-x64`, and `WebMarkupMin.AspNetCoreLatest`. Changed the `CopyToOutputDirectory` property for `Properties\Resources.resx` from `Always` to `PreserveNewest`. * Refactor .NET application and update configurations - Updated `.editorconfig` for coding styles and preferences. - Refactored classes in `BlogSettings.cs`, `Constants.cs`, and `AccountController.cs` for improved readability and maintainability. - Modified `Miniblog.Core.csproj` to enable .NET analyzers and enforce code style. - Enhanced `FileBlogService.cs` and `MetaWeblogService.cs` for better handling of posts, categories, and tags. - Updated `Startup.cs` for service and middleware configuration, including output caching and authentication. - Added `workload-install.ps1` script for installing Tizen workload manifests. - General code structure improvements, including expression-bodied members and better null handling. * Remove Microsoft.CodeAnalysis.NetAnalyzers package This commit removes the `Microsoft.CodeAnalysis.NetAnalyzers` package reference from the `Miniblog.Core.csproj` file. The package was previously included with version `9.0.0` and had specific asset inclusion settings, which are no longer needed in the project. * Add log level for Microsoft.AspNetCore in settings Updated appsettings.Development.json and appsettings.json to include a new log level for Microsoft.AspNetCore, setting it to "Warning". The existing log level for Microsoft remains unchanged at "Information", and the default log level in appsettings.json remains "Warning". * Refactor app setup to use minimal hosting model Moved application configuration from Startup.cs to Program.cs, aligning with .NET 6 practices. Added services for authentication, output caching, HTML minification, and Progressive Web Apps. Removed Startup class and integrated its methods into the new builder pattern for a simplified application structure. * Enhance slug handling and input validation Updated `UpdatePost` method for better null checking and slug creation. The `CreateSlug` method now accepts a `maxLength` parameter to limit slugs to 50 characters and truncates titles as needed. The `Edit.cshtml` file enforces a maximum length of 50 characters for the slug input field. Implemented upstream PR: #195 * Add HTTP response compression support This commit introduces support for HTTP response compression in the ASP.NET Core application. It includes the necessary namespace imports, configuration for Brotli and Gzip compression providers, and enables response compression in the middleware pipeline. JSON responses are also configured to be compressed. Implemented PR: #154 * Enhance pagination and improve code clarity - Added `PostsPerPage` and `TotalPages` constants in `Constants.cs`. - Refined comments in `AddComment` method of `BlogController.cs`. - Improved pagination logic in `Category` and `Index` methods, replacing `filteredPosts` with `pagedPosts`. - Updated comments in `Post` method and added a new `Tag` method for tag-based post display. - Modified `UpdatePost` to accept a `slug` parameter for better post handling. - Enhanced comments and consistency in `SaveFilesToDisk` method. - Updated `Index.cshtml` to accurately calculate `currentPage` and `totalPages` using new view data properties. Implements PR: #149 Issue: madskristensen/MiniBlog#262 * Refactor file handling and improve performance - Streamlined `SaveFile` method with concise `using` syntax. - Added null-forgiving operators in `SavePost` for safety. - Replaced `ForEach` with `foreach` in `LoadCategories` and `LoadTags`. - Updated `Initialize` to call `LoadPosts` asynchronously. - Refactored `LoadPosts` to use PLINQ and async enumerables for parallel file loading. * Refactor FileBlogService for asynchronous initialization Updated the constructor to call an asynchronous method, `InitializeAsync`, instead of a synchronous one. This change allows for proper handling of asynchronous operations during initialization. The `LoadPosts` method is now awaited, ensuring that posts are loaded correctly before sorting the cache. * Refactor methods for asynchronous operations - Changed `GetCategories` to return `IAsyncEnumerable<string>` for asynchronous streaming. - Updated `GetPostById` and `GetPostBySlug` to be asynchronous, using `Task<Post?>` and `async` keyword. - Modified return statements to use `await Task.FromResult(...)` for better async handling. * Refactor FileBlogService for improved structure Updated FileBlogService to use constructor injection for dependencies, added SuppressMessage attributes for security, and changed folder handling to a property. Implemented async methods with yield return for better performance and ensured initialization checks are in place. Simplified IsAdmin method and improved overall readability and maintainability. * Create dotnet.yml * Update .NET version in workflow configuration Changed the `dotnet-version` in the `Setup .NET` step from `8.0.x` to `9.0.x` to utilize the latest .NET version for the workflow. * Create dependabot.yml
1 parent 3866f01 commit 99cd897

40 files changed

+3573
-1767
lines changed

.editorconfig

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,15 @@ csharp_style_var_elsewhere = true:suggestion
9191
csharp_style_var_for_built_in_types = true:suggestion
9292
csharp_style_var_when_type_is_apparent = true:suggestion
9393
csharp_using_directive_placement = inside_namespace:suggestion
94+
csharp_prefer_simple_using_statement = true:suggestion
95+
csharp_style_namespace_declarations = block_scoped:silent
96+
csharp_style_prefer_method_group_conversion = true:silent
97+
csharp_style_prefer_top_level_statements = true:silent
98+
csharp_style_prefer_primary_constructors = true:suggestion
99+
csharp_prefer_system_threading_lock = true:suggestion
100+
csharp_style_expression_bodied_lambdas = true:silent
101+
csharp_style_expression_bodied_local_functions = false:silent
102+
csharp_style_prefer_null_check_over_type_check = true:suggestion
94103

95104
[*.{cs,vb}]
96105
#### Naming styles ####
@@ -139,3 +148,22 @@ dotnet_naming_style.pascal_case.required_prefix =
139148
dotnet_naming_style.pascal_case.required_suffix =
140149
dotnet_naming_style.pascal_case.word_separator =
141150
dotnet_naming_style.pascal_case.capitalization = pascal_case
151+
dotnet_style_coalesce_expression = true:suggestion
152+
dotnet_style_null_propagation = true:suggestion
153+
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
154+
dotnet_style_prefer_auto_properties = true:suggestion
155+
dotnet_style_object_initializer = true:suggestion
156+
dotnet_style_collection_initializer = true:suggestion
157+
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
158+
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
159+
dotnet_style_prefer_conditional_expression_over_return = true:silent
160+
dotnet_style_explicit_tuple_names = true:suggestion
161+
dotnet_style_prefer_inferred_tuple_names = true:suggestion
162+
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
163+
dotnet_style_prefer_compound_assignment = true:suggestion
164+
dotnet_style_prefer_simplified_interpolation = true:suggestion
165+
dotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion
166+
dotnet_style_namespace_match_folder = true:suggestion
167+
dotnet_style_operator_placement_when_wrapping = beginning_of_line
168+
tab_width = 4
169+
indent_size = 4

.github/dependabot.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# To get started with Dependabot version updates, you'll need to specify which
2+
# package ecosystems to update and where the package manifests are located.
3+
# Please see the documentation for all configuration options:
4+
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
5+
6+
version: 2
7+
updates:
8+
- package-ecosystem: "nuget" # See documentation for possible values
9+
directory: "/" # Location of package manifests
10+
schedule:
11+
interval: "weekly"

.github/workflows/dotnet.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# This workflow will build a .NET project
2+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
3+
4+
name: .NET
5+
6+
on:
7+
push:
8+
branches: [ "master" ]
9+
pull_request:
10+
branches: [ "master" ]
11+
12+
jobs:
13+
build:
14+
15+
runs-on: ubuntu-latest
16+
17+
steps:
18+
- uses: actions/checkout@v4
19+
- name: Setup .NET
20+
uses: actions/setup-dotnet@v4
21+
with:
22+
dotnet-version: 9.0.x
23+
- name: Restore dependencies
24+
run: dotnet restore
25+
- name: Build
26+
run: dotnet build --no-restore
27+
- name: Test
28+
run: dotnet test --no-build --verbosity normal

Miniblog.Core.sln

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio Version 16
4-
VisualStudioVersion = 16.0.29806.167
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.14.36203.30 d17.14
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Miniblog.Core", "src\Miniblog.Core.csproj", "{8CE1A353-8B0D-43F1-B681-6057BAC241BC}"
77
EndProject
@@ -26,6 +26,9 @@ Global
2626
HideSolutionNode = FALSE
2727
EndGlobalSection
2828
GlobalSection(ExtensibilityGlobals) = postSolution
29+
RESX_EnableXlifSync = True
30+
RESX_AutoCreateNewLanguageFiles = True
31+
RESX_SortFileContentOnSave = True
2932
SolutionGuid = {D6EFE298-6363-41A3-92FD-78CC98AE3580}
3033
EndGlobalSection
3134
EndGlobal

src/BlogSettings.cs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1-
namespace Miniblog.Core
1+
namespace Miniblog.Core;
2+
3+
public class BlogSettings
24
{
3-
public class BlogSettings
4-
{
5-
public int CommentsCloseAfterDays { get; set; } = 10;
5+
public int CommentsCloseAfterDays { get; set; } = 10;
66

7-
public bool DisplayComments { get; set; } = true;
7+
public bool DisplayComments { get; set; } = true;
88

9-
public PostListView ListView { get; set; } = PostListView.TitlesAndExcerpts;
9+
public PostListView ListView { get; set; } = PostListView.TitlesAndExcerpts;
1010

11-
public string Owner { get; set; } = "The Owner";
11+
public string Owner { get; set; } = "The Owner";
1212

13-
public int PostsPerPage { get; set; } = 4;
14-
}
13+
public int PostsPerPage { get; set; } = 4;
1514
}

src/Constants.cs

Lines changed: 38 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,46 @@
1-
namespace Miniblog.Core
1+
namespace Miniblog.Core;
2+
3+
using System.Diagnostics.CodeAnalysis;
4+
5+
public static class Constants
26
{
3-
using System.Diagnostics.CodeAnalysis;
7+
public static readonly string AllCats = "AllCats";
8+
public static readonly string AllTags = "AllTags";
9+
public static readonly string categories = "categories";
10+
public static readonly string Dash = "-";
11+
public static readonly string Description = "Description";
12+
public static readonly string Head = "Head";
13+
public static readonly string next = "next";
14+
public static readonly string page = "page";
15+
public static readonly string PostsPerPage = "PostsPerPage";
16+
public static readonly string Preload = "Preload";
17+
public static readonly string prev = "prev";
18+
public static readonly string ReturnUrl = "ReturnUrl";
19+
public static readonly string Scripts = "Scripts";
20+
public static readonly string slug = "slug";
21+
public static readonly string Space = " ";
22+
public static readonly string tags = "tags";
23+
public static readonly string Title = "Title";
24+
public static readonly string TotalPages = "TotalPages";
25+
public static readonly string TotalPostCount = "TotalPostCount";
26+
public static readonly string ViewOption = "ViewOption";
427

5-
public static class Constants
28+
[SuppressMessage(
29+
"Design",
30+
"CA1034:Nested types should not be visible",
31+
Justification = "Constant classes are nested for easy intellisense.")]
32+
public static class Config
633
{
7-
public static readonly string AllCats = "AllCats";
8-
public static readonly string AllTags = "AllTags";
9-
public static readonly string categories = "categories";
10-
public static readonly string tags = "tags";
11-
public static readonly string Dash = "-";
12-
public static readonly string Description = "Description";
13-
public static readonly string Head = "Head";
14-
public static readonly string next = "next";
15-
public static readonly string page = "page";
16-
public static readonly string Preload = "Preload";
17-
public static readonly string prev = "prev";
18-
public static readonly string ReturnUrl = "ReturnUrl";
19-
public static readonly string Scripts = "Scripts";
20-
public static readonly string slug = "slug";
21-
public static readonly string Space = " ";
22-
public static readonly string Title = "Title";
23-
public static readonly string TotalPostCount = "TotalPostCount";
24-
public static readonly string ViewOption = "ViewOption";
25-
26-
[SuppressMessage(
27-
"Design",
28-
"CA1034:Nested types should not be visible",
29-
Justification = "Constant classes are nested for easy intellisense.")]
30-
public static class Config
34+
public static class Blog
3135
{
32-
public static class Blog
33-
{
34-
public static readonly string Name = "blog:name";
35-
}
36+
public static readonly string Name = "blog:name";
37+
}
3638

37-
public static class User
38-
{
39-
public static readonly string Password = "user:password";
40-
public static readonly string Salt = "user:salt";
41-
public static readonly string UserName = "user:username";
42-
}
39+
public static class User
40+
{
41+
public static readonly string Password = "user:password";
42+
public static readonly string Salt = "user:salt";
43+
public static readonly string UserName = "user:username";
4344
}
4445
}
4546
}
Lines changed: 44 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,60 @@
1-
namespace Miniblog.Core.Controllers
2-
{
3-
using Microsoft.AspNetCore.Authentication;
4-
using Microsoft.AspNetCore.Authentication.Cookies;
5-
using Microsoft.AspNetCore.Authorization;
6-
using Microsoft.AspNetCore.Mvc;
1+
namespace Miniblog.Core.Controllers;
2+
3+
using Microsoft.AspNetCore.Authentication;
4+
using Microsoft.AspNetCore.Authentication.Cookies;
5+
using Microsoft.AspNetCore.Authorization;
6+
using Microsoft.AspNetCore.Mvc;
77

8-
using Miniblog.Core.Models;
9-
using Miniblog.Core.Services;
8+
using Miniblog.Core.Models;
9+
using Miniblog.Core.Services;
1010

11-
using System.Diagnostics.CodeAnalysis;
12-
using System.Security.Claims;
13-
using System.Threading.Tasks;
11+
using System.Security.Claims;
12+
using System.Threading.Tasks;
1413

15-
[Authorize]
16-
public class AccountController : Controller
14+
[Authorize]
15+
public class AccountController(IUserServices userServices) : Controller
16+
{
17+
[Route("/login")]
18+
[AllowAnonymous]
19+
[HttpGet]
20+
public IActionResult Login(string? returnUrl = null)
1721
{
18-
private readonly IUserServices userServices;
22+
this.ViewData[Constants.ReturnUrl] = returnUrl;
23+
return this.View();
24+
}
1925

20-
public AccountController(IUserServices userServices) => this.userServices = userServices;
26+
[Route("/login")]
27+
[HttpPost, AllowAnonymous, ValidateAntiForgeryToken]
28+
public async Task<IActionResult> LoginAsync(string? returnUrl, LoginViewModel? model)
29+
{
30+
this.ViewData[Constants.ReturnUrl] = returnUrl;
2131

22-
[Route("/login")]
23-
[AllowAnonymous]
24-
[HttpGet]
25-
[SuppressMessage("Design", "CA1054:Uri parameters should not be strings", Justification = "MVC binding")]
26-
public IActionResult Login(string? returnUrl = null)
32+
if (model is null || model.UserName is null || model.Password is null)
2733
{
28-
this.ViewData[Constants.ReturnUrl] = returnUrl;
29-
return this.View();
34+
this.ModelState.AddModelError(string.Empty, Properties.Resources.UsernameOrPasswordIsInvalid);
35+
return this.View(nameof(Login), model);
3036
}
3137

32-
[Route("/login")]
33-
[HttpPost, AllowAnonymous, ValidateAntiForgeryToken]
34-
[SuppressMessage("Design", "CA1054:Uri parameters should not be strings", Justification = "MVC binding")]
35-
public async Task<IActionResult> LoginAsync(string? returnUrl, LoginViewModel? model)
38+
if (!this.ModelState.IsValid || !userServices.ValidateUser(model.UserName, model.Password))
3639
{
37-
this.ViewData[Constants.ReturnUrl] = returnUrl;
38-
39-
if (model is null || model.UserName is null || model.Password is null)
40-
{
41-
this.ModelState.AddModelError(string.Empty, Properties.Resources.UsernameOrPasswordIsInvalid);
42-
return this.View(nameof(Login), model);
43-
}
44-
45-
if (!this.ModelState.IsValid || !this.userServices.ValidateUser(model.UserName, model.Password))
46-
{
47-
this.ModelState.AddModelError(string.Empty, Properties.Resources.UsernameOrPasswordIsInvalid);
48-
return this.View(nameof(Login), model);
49-
}
40+
this.ModelState.AddModelError(string.Empty, Properties.Resources.UsernameOrPasswordIsInvalid);
41+
return this.View(nameof(Login), model);
42+
}
5043

51-
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
52-
identity.AddClaim(new Claim(ClaimTypes.Name, model.UserName));
44+
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
45+
identity.AddClaim(new Claim(ClaimTypes.Name, model.UserName));
5346

54-
var principle = new ClaimsPrincipal(identity);
55-
var properties = new AuthenticationProperties { IsPersistent = model.RememberMe };
56-
await this.HttpContext.SignInAsync(principle, properties).ConfigureAwait(false);
47+
var principle = new ClaimsPrincipal(identity);
48+
var properties = new AuthenticationProperties { IsPersistent = model.RememberMe };
49+
await this.HttpContext.SignInAsync(principle, properties).ConfigureAwait(false);
5750

58-
return this.LocalRedirect(returnUrl ?? "/");
59-
}
51+
return this.LocalRedirect(returnUrl ?? "/");
52+
}
6053

61-
[Route("/logout")]
62-
public async Task<IActionResult> LogOutAsync()
63-
{
64-
await this.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme).ConfigureAwait(false);
65-
return this.LocalRedirect("/");
66-
}
54+
[Route("/logout")]
55+
public async Task<IActionResult> LogOutAsync()
56+
{
57+
await this.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme).ConfigureAwait(false);
58+
return this.LocalRedirect("/");
6759
}
6860
}

0 commit comments

Comments
 (0)