.NET 7 + Spring Cleaning (#1677)

* Updated to net7.0

* Updated GA to .net 7

* Updated System.IO.Abstractions to use New factory.

* Converted Regex into SourceGenerator in Parser.

* Updated more regex to source generators.

* Enabled Nullability and more regex changes throughout codebase.

* Parser is 100% GeneratedRegexified

* Lots of nullability code

* Enabled nullability for all repositories.

* Fixed another unit test

* Refactored some code around and took care of some todos.

* Updating code for nullability and cleaning up methods that aren't used anymore. Refctored all uses of Parser.Normalize() to use new extension

* More nullability exercises. 500 warnings to go.

* Fixed a bug where custom file uploads for entities wouldn't save in webP.

* Nullability is done for all DTOs

* Fixed all unit tests and nullability for the project. Only OPDS is left which will be done with an upcoming OPDS enhancement.

* Use localization in book service after validating

* Code smells

* Switched to preview build of swashbuckle for .net7 support

* Fixed up merge issues

* Disable emulate comic book when on single page reader

* Fixed a regression where double page renderer wouldn't layout the images correctly

* Updated to swashbuckle which support .net 7

* Fixed a bad GA action

* Some code cleanup

* More code smells

* Took care of most of nullable issues

* Fixed a broken test due to having more than one test run in parallel

* I'm really not sure why the unit tests are failing or are so extremely slow on .net 7

* Updated all dependencies

* Fixed up build and removed hardcoded framework from build scripts. (this merge removes Regex Source generators). Unit tests are completely busted.

* Unit tests and code cleanup. Needs shakeout now.

* Adjusted Series model since a few fields are not-nullable. Removed dead imports on the project.

* Refactored to use Builder pattern for all unit tests.

* Switched nullability down to warnings. It wasn't possible to switch due to constraint issues in DB Migration.
This commit is contained in:
Joe Milazzo 2023-03-05 14:55:13 -06:00 committed by GitHub
parent 76fe3fd64a
commit 5d1dd7b3f0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
283 changed files with 4221 additions and 4593 deletions

View file

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Web;
using API.Constants;
using API.Data;
using API.Data.Repositories;
@ -23,7 +22,6 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace API.Controllers;
@ -213,10 +211,13 @@ public class AccountController : BaseApiController
var dto = _mapper.Map<UserDto>(user);
dto.Token = await _tokenService.CreateToken(user);
dto.RefreshToken = await _tokenService.CreateRefreshToken(user);
var pref = await _unitOfWork.UserRepository.GetPreferencesAsync(user.UserName);
var pref = await _unitOfWork.UserRepository.GetPreferencesAsync(user.UserName!);
if (pref == null) return Ok(dto);
pref.Theme ??= await _unitOfWork.SiteThemeRepository.GetDefaultTheme();
dto.Preferences = _mapper.Map<UserPreferencesDto>(pref);
return dto;
return Ok(dto);
}
/// <summary>
@ -248,7 +249,7 @@ public class AccountController : BaseApiController
.GetFields(BindingFlags.Public | BindingFlags.Static)
.Where(f => f.FieldType == typeof(string))
.ToDictionary(f => f.Name,
f => (string) f.GetValue(null)).Values.ToList();
f => (string) f.GetValue(null)!).Values.ToList();
}
@ -260,6 +261,7 @@ public class AccountController : BaseApiController
public async Task<ActionResult<string>> ResetApiKey()
{
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
if (user == null) return Unauthorized();
user.ApiKey = HashUtil.ApiKey();
@ -281,7 +283,7 @@ public class AccountController : BaseApiController
/// <param name="dto"></param>
/// <returns>Returns just if the email was sent or server isn't reachable</returns>
[HttpPost("update/email")]
public async Task<ActionResult> UpdateEmail(UpdateEmailDto dto)
public async Task<ActionResult> UpdateEmail(UpdateEmailDto? dto)
{
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
if (user == null) return Unauthorized("You do not have permission");
@ -297,7 +299,7 @@ public class AccountController : BaseApiController
}
// Validate no other users exist with this email
if (user.Email.Equals(dto.Email)) return Ok("Nothing to do");
if (user.Email!.Equals(dto.Email)) return Ok("Nothing to do");
// Check if email is used by another user
var existingUserEmail = await _unitOfWork.UserRepository.GetUserByEmailAsync(dto.Email);
@ -335,7 +337,7 @@ public class AccountController : BaseApiController
{
EmailAddress = string.IsNullOrEmpty(user.Email) ? dto.Email : user.Email,
InstallId = BuildInfo.Version.ToString(),
InvitingUser = (await _unitOfWork.UserRepository.GetAdminUsersAsync()).First().UserName,
InvitingUser = (await _unitOfWork.UserRepository.GetAdminUsersAsync()).First().UserName!,
ServerConfirmationLink = emailLink
});
}
@ -357,7 +359,7 @@ public class AccountController : BaseApiController
}
await _eventHub.SendMessageToAsync(MessageFactory.UserUpdate, MessageFactory.UserUpdateEvent(user.Id, user.UserName), user.Id);
await _eventHub.SendMessageToAsync(MessageFactory.UserUpdate, MessageFactory.UserUpdateEvent(user.Id, user.UserName!), user.Id);
return Ok();
}
@ -367,9 +369,9 @@ public class AccountController : BaseApiController
{
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
if (user == null) return Unauthorized("You do not have permission");
if (dto == null) return BadRequest("Invalid payload");
var isAdmin = await _unitOfWork.UserRepository.IsUserAdminAsync(user);
if (!await _accountService.HasChangeRestrictionRole(user)) return BadRequest("You do not have permission");
user.AgeRestriction = isAdmin ? AgeRating.NotApplicable : dto.AgeRating;
user.AgeRestrictionIncludeUnknowns = isAdmin || dto.IncludeUnknowns;
@ -387,7 +389,7 @@ public class AccountController : BaseApiController
return BadRequest("There was an error updating the age restriction");
}
await _eventHub.SendMessageToAsync(MessageFactory.UserUpdate, MessageFactory.UserUpdateEvent(user.Id, user.UserName), user.Id);
await _eventHub.SendMessageToAsync(MessageFactory.UserUpdate, MessageFactory.UserUpdateEvent(user.Id, user.UserName!), user.Id);
return Ok();
}
@ -402,13 +404,14 @@ public class AccountController : BaseApiController
public async Task<ActionResult> UpdateAccount(UpdateUserDto dto)
{
var adminUser = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
if (adminUser == null) return Unauthorized();
if (!await _unitOfWork.UserRepository.IsUserAdminAsync(adminUser)) return Unauthorized("You do not have permission");
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(dto.UserId);
if (user == null) return BadRequest("User does not exist");
// Check if username is changing
if (!user.UserName.Equals(dto.Username))
if (!user.UserName!.Equals(dto.Username))
{
// Validate username change
var errors = await _accountService.ValidateUsername(dto.Username);
@ -488,12 +491,13 @@ public class AccountController : BaseApiController
public async Task<ActionResult<string>> GetInviteUrl(int userId, bool withBaseUrl)
{
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(userId);
if (user == null) return Unauthorized();
if (user.EmailConfirmed)
return BadRequest("User is already confirmed");
if (string.IsNullOrEmpty(user.ConfirmationToken))
return BadRequest("Manual setup is unable to be completed. Please cancel and recreate the invite.");
return await _accountService.GenerateEmailLink(Request, user.ConfirmationToken, "confirm-email", user.Email, withBaseUrl);
return await _accountService.GenerateEmailLink(Request, user.ConfirmationToken, "confirm-email", user.Email!, withBaseUrl);
}
@ -520,23 +524,14 @@ public class AccountController : BaseApiController
if (emailValidationErrors.Any())
{
var invitedUser = await _unitOfWork.UserRepository.GetUserByEmailAsync(dto.Email);
if (await _userManager.IsEmailConfirmedAsync(invitedUser))
return BadRequest($"User is already registered as {invitedUser.UserName}");
if (await _userManager.IsEmailConfirmedAsync(invitedUser!))
return BadRequest($"User is already registered as {invitedUser!.UserName}");
return BadRequest("User is already invited under this email and has yet to accepted invite.");
}
}
// Create a new user
var user = new AppUser()
{
UserName = dto.Email,
Email = dto.Email,
ApiKey = HashUtil.ApiKey(),
UserPreferences = new AppUserPreferences
{
Theme = await _unitOfWork.SiteThemeRepository.GetDefaultTheme()
}
};
var user = DbFactory.AppUser(dto.Email, dto.Email, await _unitOfWork.SiteThemeRepository.GetDefaultTheme());
try
{
@ -612,7 +607,7 @@ public class AccountController : BaseApiController
await _emailService.SendConfirmationEmail(new ConfirmationEmailDto()
{
EmailAddress = dto.Email,
InvitingUser = adminUser.UserName,
InvitingUser = adminUser.UserName!,
ServerConfirmationLink = emailLink
});
}
@ -680,14 +675,14 @@ public class AccountController : BaseApiController
await _unitOfWork.CommitAsync();
user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(user.UserName,
AppUserIncludes.UserPreferences);
user = (await _unitOfWork.UserRepository.GetUserByUsernameAsync(user.UserName,
AppUserIncludes.UserPreferences))!;
// Perform Login code
return new UserDto
{
Username = user.UserName,
Email = user.Email,
Username = user.UserName!,
Email = user.Email!,
Token = await _tokenService.CreateToken(user),
RefreshToken = await _tokenService.CreateRefreshToken(user),
ApiKey = user.ApiKey,
@ -731,7 +726,7 @@ public class AccountController : BaseApiController
// For the user's connected devices to pull the new information in
await _eventHub.SendMessageToAsync(MessageFactory.UserUpdate,
MessageFactory.UserUpdateEvent(user.Id, user.UserName), user.Id);
MessageFactory.UserUpdateEvent(user.Id, user.UserName!), user.Id);
// Perform Login code
return Ok();
@ -832,14 +827,14 @@ public class AccountController : BaseApiController
await _unitOfWork.CommitAsync();
user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(user.UserName,
user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(user.UserName!,
AppUserIncludes.UserPreferences);
// Perform Login code
return new UserDto
{
Username = user.UserName,
Email = user.Email,
Username = user!.UserName!,
Email = user.Email!,
Token = await _tokenService.CreateToken(user),
RefreshToken = await _tokenService.CreateRefreshToken(user),
ApiKey = user.ApiKey,
@ -873,8 +868,8 @@ public class AccountController : BaseApiController
{
await _emailService.SendMigrationEmail(new EmailMigrationDto()
{
EmailAddress = user.Email,
Username = user.UserName,
EmailAddress = user.Email!,
Username = user.UserName!,
ServerConfirmationLink = emailLink,
InstallId = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallId)).Value
});
@ -908,8 +903,8 @@ public class AccountController : BaseApiController
if (emailValidationErrors.Any())
{
var invitedUser = await _unitOfWork.UserRepository.GetUserByEmailAsync(dto.Email);
if (await _userManager.IsEmailConfirmedAsync(invitedUser))
return BadRequest($"User is already registered as {invitedUser.UserName}");
if (await _userManager.IsEmailConfirmedAsync(invitedUser!))
return BadRequest($"User is already registered as {invitedUser!.UserName}");
_logger.LogInformation("A user is attempting to login, but hasn't accepted email invite");
return BadRequest("User is already invited under this email and has yet to accepted invite.");