Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.17.2 - Update to .NET 8 + Various bugfixes #154

Merged
merged 20 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
c7b24f5
feat(angular): Update maximumWarning and maximumError in angular.json
SakuraIsayeki Nov 6, 2023
55a3614
feat(profile): Update profile component display elements
SakuraIsayeki Nov 6, 2023
47d91a2
feat(api): update Nodsoft.WowsReplaysUnpack.ExtendedData package
SakuraIsayeki Nov 26, 2023
5942226
build(deps/api): Update target framework to .NET 8.0 + package versions
SakuraIsayeki Jan 11, 2024
b9eddf4
feat(ApiDbContext): update DataTypeMapper configuration
SakuraIsayeki Oct 12, 2023
26b41e0
build(deps/api): update `Nodsoft.WowsReplaysUnpack.ExtendedData` package
SakuraIsayeki Jan 11, 2024
44c083c
refactor: Various refactors & updates
SakuraIsayeki Jan 11, 2024
2a44118
feat!: Switch timestamps from `DateTime` to `DateTimeOffset` + Migration
SakuraIsayeki Jan 11, 2024
10129fe
fix(post/edit): Fix various validation issues
SakuraIsayeki Jan 11, 2024
be0a621
fix(replays): Fix null ref on empty chat messages list
SakuraIsayeki Jan 11, 2024
89de921
build(deps/minimap-client): Update to .NET 8.0 + Bump package references
SakuraIsayeki Jan 11, 2024
006ff2e
build(deps/api): Update dependencies
SakuraIsayeki Jan 11, 2024
daadec2
feat!: The great nullification
SakuraIsayeki Jan 12, 2024
1ece247
feat(migrations): Add Nullable context migrations
SakuraIsayeki Jan 14, 2024
55ffe69
fix(Role): Update Users property to use List instead of IEnumerable
SakuraIsayeki Jan 14, 2024
02c09fe
feat(PlayerController): Refactor SearchAccount API methods
SakuraIsayeki Jan 14, 2024
231448a
feat(PostService): Update PostService to use UTC time for UpdatedAt
SakuraIsayeki Jan 23, 2024
1a05203
build(deps/api): Update dependencies
SakuraIsayeki Jan 23, 2024
b32c393
fix(api/proffile): Fix bad property validation on profile update
SakuraIsayeki Jan 25, 2024
1430991
ci(build): update .NET version to 8.0.x
SakuraIsayeki Jan 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/dotnet-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
dotnet-version: '7.0.x'
dotnet-version: '8.0.x'
# include-prerelease: true

- name: Restore dependencies
Expand Down
12 changes: 6 additions & 6 deletions WowsKarma.Api.Minimap.Client/WowsKarma.Api.Minimap.Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>0.1</Version>
<Version>0.1.1</Version>

<Product>WOWS Karma Minimap API Client</Product>
<Authors>Sakura Akeno Isayeki</Authors>
Expand All @@ -15,11 +15,11 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="[2022,)" />
<PackageReference Include="Microsoft.Extensions.Http" Version="[6.0.0,)" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="[6.0.0,)" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="[6.32.0,7)" />
<PackageReference Include="System.Net.Http.Json" Version="[6.0.0,)" />
<PackageReference Include="JetBrains.Annotations" Version="[2023.3,)" />
<PackageReference Include="Microsoft.Extensions.Http" Version="[8.0.0,)" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="[8.0.0,)" />
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="[7.2.0,)" />
<PackageReference Include="System.Net.Http.Json" Version="[8.0.0,)" />
</ItemGroup>


Expand Down
17 changes: 8 additions & 9 deletions WowsKarma.Api/Controllers/Admin/ModActionController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@
using WowsKarma.Api.Services.Posts;
using WowsKarma.Common;


namespace WowsKarma.Api.Controllers.Admin;


[ApiController, Route("api/mod/action"), Authorize(Roles = ApiRoles.CM)]
public class ModActionController : ControllerBase
public sealed class ModActionController : ControllerBase
{
private readonly ModService _service;

Expand Down Expand Up @@ -40,22 +39,22 @@ public ModActionController(ModService service)
[HttpGet("list"), AllowAnonymous, ProducesResponseType(typeof(IEnumerable<PostModActionDTO>), 200), ProducesResponseType(204)]
public IActionResult List([FromQuery] Guid postId = default, [FromQuery] uint userId = default)
{
IEnumerable<PostModAction> modActions;
PostModAction[] modActions = [];

if (postId != default)
{
modActions = _service.GetPostModActions(postId).ToArray();
modActions = [.. _service.GetPostModActions(postId)];
}
else if (userId is not 0)
{
modActions = _service.GetPostModActions(userId).ToArray();
modActions = [.. _service.GetPostModActions(userId)];
}
else
{
return BadRequest("Please use a search query (Post/User).");
}

return modActions?.Count() is null or 0
return modActions is []
? base.StatusCode(204)
: base.StatusCode(200, modActions.Adapt<IEnumerable<PostModActionDTO>>());
}
Expand All @@ -73,16 +72,16 @@ public IActionResult List([FromQuery] Guid postId = default, [FromQuery] uint us
public async Task<IActionResult> Submit([FromBody] PostModActionDTO modAction,
[FromServices] PostService postService)
{
Post post = postService.GetPost(modAction.PostId);
uint modId = uint.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier));
Post post = postService.GetPost(modAction.PostId) ?? throw new InvalidOperationException("Post ID is invalid.");
uint modId = uint.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier) ?? throw new BadHttpRequestException("Missing NameIdentifier claim."));

if ((post.AuthorId == modId || post.PlayerId == modId) && !User.IsInRole(ApiRoles.Administrator))
{
return StatusCode(403, $"CMs cannot act on Posts with relation to self. This restriction is lifted for users with {ApiRoles.Administrator} role.");
}

await _service.SubmitPostModActionAsync(modAction with { ModId = modId });
return StatusCode(202);
return Accepted();
}

/// <summary>
Expand Down
23 changes: 12 additions & 11 deletions WowsKarma.Api/Controllers/Admin/PlatformBansController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
namespace WowsKarma.Api.Controllers.Admin;

[ApiController, Route("api/mod/bans"), Authorize(Roles = $"{ApiRoles.CM},{ApiRoles.Administrator}")]
public class PlatformBansController : ControllerBase
public sealed class PlatformBansController : ControllerBase
{
private readonly ModService _service;

Expand Down Expand Up @@ -39,23 +39,24 @@ public IActionResult FetchBans(uint userId, bool currentOnly)
return Ok(bans.ProjectToType<PlatformBanDTO>().AsAsyncEnumerable());
}

/// <summary>
/// Emits a new Platform Ban.
/// </summary>
/// <param name="submitted">Platform Ban to emit</param>
/// <param name="days">(Helper) Sets a temporary ban, to the number of specified days starting from UTC now.</param>
/// <response code="202">Platform Ban was successfuly submitted.</response>
/// <summary>
/// Emits a new Platform Ban.
/// </summary>
/// <param name="submitted">Platform Ban to emit</param>
/// <param name="authDb">(DI)</param>
/// <param name="days">(Helper) Sets a temporary ban, to the number of specified days starting from UTC now.</param>
/// <response code="202">Platform Ban was successfuly submitted.</response>
[HttpPost, ProducesResponseType(202)]
public async Task<IActionResult> SubmitBan([FromBody] PlatformBanDTO submitted, [FromServices] AuthDbContext authDb, [FromQuery] uint days = 0)
{
await _service.EmitPlatformBanAsync(submitted with
{
ModId = User.ToAccountListing().Id,
ModId = User.ToAccountListing()!.Id,
Reverted = false,
BannedUntil = days is 0 ? null : DateTime.UtcNow.AddDays(days)
BannedUntil = days is 0 ? null : DateTimeOffset.UtcNow.AddDays(days)
}, authDb);

return StatusCode(202);
return Accepted();
}

/// <summary>
Expand All @@ -64,7 +65,7 @@ await _service.EmitPlatformBanAsync(submitted with
/// <param name="id">ID of Platform Ban to revert.</param>
/// <response code="200">Platform Ban was successfully reverted.</response>
[HttpDelete("{id:guid}"), ProducesResponseType(200)]
public async Task<IActionResult> RevertBan([FromQuery] Guid id)
public async Task<IActionResult> RevertBan(Guid id)
{
await _service.RevertPlatformBanAsync(id);

Expand Down
43 changes: 20 additions & 23 deletions WowsKarma.Api/Controllers/AuthController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,32 @@
using Microsoft.AspNetCore.Mvc;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.AspNetCore.Http;
using WowsKarma.Api.Infrastructure.Attributes;
using WowsKarma.Api.Services.Authentication;
using WowsKarma.Api.Services.Authentication.Jwt;
using WowsKarma.Api.Services.Authentication.Wargaming;
using WowsKarma.Common;


namespace WowsKarma.Api.Controllers;


/// <summary>
/// Provides API Authentication endpoints.
/// </summary>
[ApiController, Route("api/[controller]"), ETag(false)]
public class AuthController : ControllerBase
public sealed class AuthController : ControllerBase
{
private readonly IConfiguration config;
private readonly UserService userService;
private readonly WargamingAuthService wargamingAuthService;
private readonly JwtService jwtService;
private readonly IConfiguration _config;
private readonly UserService _userService;
private readonly WargamingAuthService _wargamingAuthService;
private readonly JwtService _jwtService;


public AuthController(IConfiguration config, UserService userService, WargamingAuthService wargamingAuthService, JwtService jwtService)
{
this.config = config;
this.userService = userService;
this.wargamingAuthService = wargamingAuthService;
this.jwtService = jwtService;
_config = config;
_userService = userService;
_wargamingAuthService = wargamingAuthService;
_jwtService = jwtService;
}

/// <summary>
Expand All @@ -57,33 +54,33 @@ public AuthController(IConfiguration config, UserService userService, WargamingA
[HttpGet("wg-callback"), ProducesResponseType(302), ProducesResponseType(200), ProducesResponseType(403)]
public async Task<IActionResult> WgAuthCallback()
{
bool valid = await wargamingAuthService.VerifyIdentity(Request);
bool valid = await _wargamingAuthService.VerifyIdentity(Request);

if (!valid)
{
return StatusCode(403);
}

JwtSecurityToken token = await userService.CreateTokenAsync(WargamingIdentity.FromUri(new(Request.Query["openid.identity"].FirstOrDefault()
JwtSecurityToken token = await _userService.CreateTokenAsync(WargamingIdentity.FromUri(new(Request.Query["openid.identity"].FirstOrDefault()
?? throw new BadHttpRequestException("Missing OpenID identity"))));

Response.Cookies.Append(
config[$"Api:{Startup.ApiRegion.ToRegionString()}:CookieName"],
jwtService.TokenHandler.WriteToken(token),
_config[$"Api:{Startup.ApiRegion.ToRegionString()}:CookieName"] ?? throw new ApplicationException("Missing Api:{region}:CookieName in configuration."),
_jwtService.TokenHandler.WriteToken(token),
new()
{
Domain = config[$"Api:{Startup.ApiRegion.ToRegionString()}:CookieDomain"],
Domain = _config[$"Api:{Startup.ApiRegion.ToRegionString()}:CookieDomain"],
HttpOnly = false,
IsEssential = true,
#if RELEASE
Secure = true,
Secure = true,
#endif
Expires = DateTime.UtcNow.AddDays(7)
});

return Request.Query["redirectUri"].FirstOrDefault() is { } redirectUri
? Redirect(redirectUri)
: StatusCode(200);
: Ok();
}

/// <summary>
Expand All @@ -94,8 +91,8 @@ public async Task<IActionResult> WgAuthCallback()
[HttpPost("renew-seed"), Authorize, ProducesResponseType(200), ProducesResponseType(401)]
public async Task<IActionResult> RenewSeed()
{
await userService.RenewSeedTokenAsync(uint.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)));
return StatusCode(200);
await _userService.RenewSeedTokenAsync(uint.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier) ?? throw new BadHttpRequestException("Missing NameIdentifier claim.")));
return Ok();
}

/// <summary>
Expand All @@ -106,7 +103,7 @@ public async Task<IActionResult> RenewSeed()
[HttpGet("refresh-token"), Authorize, ProducesResponseType(typeof(string), 200), ProducesResponseType(401)]
public async Task<IActionResult> RefreshToken()
{
JwtSecurityToken token = await userService.CreateTokenAsync(new(User.Claims));
return StatusCode(200, jwtService.TokenHandler.WriteToken(token));
JwtSecurityToken token = await _userService.CreateTokenAsync(new(User.Claims));
return StatusCode(200, _jwtService.TokenHandler.WriteToken(token));
}
}
17 changes: 7 additions & 10 deletions WowsKarma.Api/Controllers/ClanController.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.ComponentModel.DataAnnotations;
using System.Threading;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using WowsKarma.Api.Services;
Expand All @@ -8,7 +7,7 @@
namespace WowsKarma.Api.Controllers;

[ApiController, Route("api/[controller]")]
public class ClanController : ControllerBase
public sealed class ClanController : ControllerBase
{
private readonly ClanService _clanService;

Expand All @@ -34,14 +33,12 @@ public ClanController(ClanService clanService)
/// <param name="ct"></param>
/// <returns>Clan Info, with members (if selected)</returns>
[HttpGet("{clanId}"), ProducesResponseType(typeof(ClanProfileDTO), 200), ProducesResponseType(typeof(ClanProfileFullDTO), 200)]
public async Task<ClanProfileDTO> GetClan(uint clanId, bool includeMembers = true, CancellationToken ct = default)
{
Clan clan = await _clanService.GetClanAsync(clanId, includeMembers, ct);

return includeMembers
? clan.Adapt<ClanProfileFullDTO>()
: clan.Adapt<ClanProfileDTO>();
}
public async Task<ClanProfileDTO?> GetClan(uint clanId, bool includeMembers = true, CancellationToken ct = default)
=> await _clanService.GetClanAsync(clanId, includeMembers, ct) is { } clan
? includeMembers
? clan.Adapt<ClanProfileFullDTO>()
: clan.Adapt<ClanProfileDTO>()
: null;

/// <summary>
/// Searches all clans relevant to a given search string.
Expand Down
18 changes: 6 additions & 12 deletions WowsKarma.Api/Controllers/PlayerController.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.ComponentModel.DataAnnotations;
using System.Threading;
using Hangfire;
using Mapster;
using WowsKarma.Api.Services;
using WowsKarma.Common;


namespace WowsKarma.Api.Controllers;

[ApiController, Route("api/[controller]")]
public class PlayerController : ControllerBase
public sealed class PlayerController : ControllerBase
{
private readonly PlayerService _playerService;

Expand All @@ -36,14 +34,10 @@ public PlayerController(PlayerService playerService)
/// <response code="200">Account listings for given search query</response>
/// <response code="204">No results found for given search query</response>
[HttpGet("search/{query}"), ProducesResponseType(typeof(IEnumerable<AccountListingDTO>), 200), ProducesResponseType(204)]
public async Task<IActionResult> SearchAccount([StringLength(100, MinimumLength = 3), RegularExpression(@"^[a-zA-Z0-9_]*$")] string query)
{
IEnumerable<AccountListingDTO> accounts = await _playerService.ListPlayersAsync(query);

return accounts is null
? NoContent()
: Ok(accounts);
}
public async Task<IActionResult> SearchAccount([StringLength(100, MinimumLength = 3), RegularExpression(@"^[a-zA-Z0-9_]*$")] string query)
=> await _playerService.ListPlayersAsync(query) is { Length: not 0 } accounts
? Ok(accounts)
: NoContent();

/// <summary>
/// Fetches the player profile for a given Account ID.
Expand All @@ -63,7 +57,7 @@ public async Task<IActionResult> GetAccount(uint id, bool includeClanInfo = true
Player playerProfile = await _playerService.GetPlayerAsync(id, false, includeClanInfo);

return playerProfile is null
? NoContent()
? NotFound()
: Ok(playerProfile.Adapt<PlayerProfileDTO>());
}

Expand Down
Loading
Loading