Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Nullinside.Api.Shared.Support;
namespace Nullinside.Api.Common.Twitch.Support;

/// <summary>
/// Enumerates the types of errors when authenticating with twitch.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.3")
.HasAnnotation("ProductVersion", "8.0.8")
.HasAnnotation("Relational:MaxIdentifierLength", 64);

modelBuilder.Entity("Nullinside.Api.Model.Ddl.DockerDeployments", b =>
Expand Down
16 changes: 0 additions & 16 deletions src/Nullinside.Api.Model/NullinsideContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,22 +66,6 @@ public NullinsideContext(DbContextOptions<NullinsideContext> options) : base(opt
/// </summary>
public DbSet<TwitchUserChatLogs> TwitchUserChatLogs { get; set; } = null!;

/// <summary>
/// Configures the default database connection.
/// </summary>
/// <param name="optionsBuilder">The database configuration options.</param>
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
string? server = Environment.GetEnvironmentVariable("MYSQL_SERVER");
string? username = Environment.GetEnvironmentVariable("MYSQL_USERNAME");
string? password = Environment.GetEnvironmentVariable("MYSQL_PASSWORD");
optionsBuilder.UseMySQL(
$"server={server};database=nullinside;user={username};password={password};AllowUserVariables=true;",
builder => {
builder.CommandTimeout(60 * 5);
builder.EnableRetryOnFailure(3);
});
}

/// <summary>
/// Dynamically finds all <seealso cref="ITableModel" /> classes and generates tables from their definitions.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Nullinside.Api.Model;
/// references more than once solution with a DbContext in it. This factory is lazy loaded by the CLI automatically
/// simply by implementing the IDesignTimeDbContextFactory interface.
/// </summary>
public class NullinsideContextFactory : IDesignTimeDbContextFactory<NullinsideContext> {
public class NullinsideDesignTimeDbContextFactory : IDesignTimeDbContextFactory<NullinsideContext> {
/// <summary>
/// Creates a new database context.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion src/Nullinside.Api.Model/Shared/UserHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static class UserHelpers {
/// <param name="twitchUsername">The username of the user on twitch.</param>
/// <param name="twitchId">The id of the user on twitch.</param>
/// <returns>The bearer token if successful, null otherwise.</returns>
public static async Task<string?> GetTokenAndSaveToDatabase(INullinsideContext dbContext, string email,
public static async Task<string?> GenerateTokenAndSaveToDatabase(INullinsideContext dbContext, string email,
CancellationToken token = new(), string? authToken = null, string? refreshToken = null, DateTime? expires = null,
string? twitchUsername = null, string? twitchId = null) {
string bearerToken = AuthUtils.GenerateBearerToken();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;

using Nullinside.Api.Model;
using Nullinside.Api.Model.Ddl;
using Nullinside.Api.Model.Shared;

namespace Nullinside.Api.Tests.Nullinside.Api.Model.Shared;

public class UserHelpersTests {
private INullinsideContext _db;

[SetUp]
public void Setup() {
// Create an in-memory database to fake the SQL queries. Note that we generate a random GUID for the name
// here. If you use the same name more than once you'll get collisions between tests.
DbContextOptions<NullinsideContext> contextOptions = new DbContextOptionsBuilder<NullinsideContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.ConfigureWarnings(b => b.Ignore(InMemoryEventId.TransactionIgnoredWarning))
.Options;
_db = new NullinsideContext(contextOptions);
}

[TearDown]
public async Task TearDown() {
await _db.DisposeAsync();
}

/// <summary>
/// The case where a user is generating a new token to replace their existing one.
/// </summary>
[Test]
public async Task GenerateTokenForExistingUser() {
_db.Users.Add(
new User {
Email = "email"
}
);
await _db.SaveChangesAsync();

// Verify there is only one user
Assert.That(_db.Users.Count(), Is.EqualTo(1));

// Generate a new token
string? token = await UserHelpers.GenerateTokenAndSaveToDatabase(_db, "email");
Assert.That(token, Is.Not.Null);

// Verify we still only have one user
Assert.That(_db.Users.Count(), Is.EqualTo(1));
Assert.That(_db.Users.First().Token, Is.EqualTo(token));
}

/// <summary>
/// The case where a user is getting a token for the first time. A new user should be created. The existing user
/// should be untouched.
/// </summary>
[Test]
public async Task GenerateTokenForNewUser() {
_db.Users.Add(
new User {
Email = "email2"
}
);
await _db.SaveChangesAsync();

// Verify there is only one user
Assert.That(_db.Users.Count(), Is.EqualTo(1));

// Generate a new token
string? token = await UserHelpers.GenerateTokenAndSaveToDatabase(_db, "email");
Assert.That(token, Is.Not.Null);

// Verify we have a new user
Assert.That(_db.Users.Count(), Is.EqualTo(2));
Assert.That(_db.Users.FirstOrDefault(u => u.Email == "email")?.Token, Is.EqualTo(token));

// Verfy the old user is untouched
Assert.That(_db.Users.FirstOrDefault(u => u.Email == "email2")?.Token, Is.Null);
}

/// <summary>
/// Unexpected database errors should result in a null being returned.
/// </summary>
[Test]
public async Task HandleUnexpectedErrors() {
// Force an error to occur.
string? token = await UserHelpers.GenerateTokenAndSaveToDatabase(null!, "email");
Assert.That(token, Is.Null);
}
}
21 changes: 18 additions & 3 deletions src/Nullinside.Api.Tests/Nullinside.Api.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="NUnit" Version="4.2.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.8"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1"/>
<PackageReference Include="Moq" Version="4.20.72"/>
<PackageReference Include="NUnit" Version="4.2.2"/>
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0"/>
<PackageReference Include="NUnit.Analyzers" Version="4.3.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand All @@ -27,4 +29,17 @@
</PackageReference>
</ItemGroup>

<ItemGroup>
<Folder Include="Nullinside.Api.Common.AspNetCore\"/>
<Folder Include="Nullinside.Api.Common\"/>
<Folder Include="Nullinside.Api\"/>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Nullinside.Api.Common.AspNetCore\Nullinside.Api.Common.AspNetCore.csproj"/>
<ProjectReference Include="..\Nullinside.Api.Common\Nullinside.Api.Common.csproj"/>
<ProjectReference Include="..\Nullinside.Api.Model\Nullinside.Api.Model.csproj"/>
<ProjectReference Include="..\Nullinside.Api\Nullinside.Api.csproj"/>
</ItemGroup>

</Project>
12 changes: 0 additions & 12 deletions src/Nullinside.Api.Tests/UnitTest1.cs

This file was deleted.

4 changes: 2 additions & 2 deletions src/Nullinside.Api/Controllers/UserController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public async Task<IActionResult> Login([FromForm] GoogleOpenIdToken creds, Cance
return Redirect($"{siteUrl}/user/login?error=1");
}

string? bearerToken = await UserHelpers.GetTokenAndSaveToDatabase(_dbContext, credentials.Email, token);
string? bearerToken = await UserHelpers.GenerateTokenAndSaveToDatabase(_dbContext, credentials.Email, token);
if (string.IsNullOrWhiteSpace(bearerToken)) {
return Redirect($"{siteUrl}/user/login?error=2");
}
Expand Down Expand Up @@ -107,7 +107,7 @@ public async Task<IActionResult> TwitchLogin([FromQuery] string code, [FromServi
return Redirect($"{siteUrl}/user/login?error=4");
}

string? bearerToken = await UserHelpers.GetTokenAndSaveToDatabase(_dbContext, email, token);
string? bearerToken = await UserHelpers.GenerateTokenAndSaveToDatabase(_dbContext, email, token);
if (string.IsNullOrWhiteSpace(bearerToken)) {
return Redirect($"{siteUrl}/user/login?error=2");
}
Expand Down
Loading