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
3 changes: 2 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
README.md
sparkly-server.test
2 changes: 1 addition & 1 deletion Migrations/20251113212512_Init.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Migrations/20251113212512_Init.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#nullable disable

namespace sparkly_server.Migrations
namespace sparkly_server.Services.Users.Migrations
{
/// <inheritdoc />
public partial class Init : Migration
Expand Down
2 changes: 1 addition & 1 deletion Migrations/20251114220854_Username.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Migrations/20251114220854_Username.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#nullable disable

namespace sparkly_server.Migrations
namespace sparkly_server.Services.Users.Migrations
{
/// <inheritdoc />
public partial class Username : Migration
Expand Down
2 changes: 1 addition & 1 deletion Migrations/20251114234534_RefreshToken.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Migrations/20251114234534_RefreshToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#nullable disable

namespace sparkly_server.Migrations
namespace sparkly_server.Services.Users.Migrations
{
/// <inheritdoc />
public partial class RefreshToken : Migration
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Migrations/20251119102854_Default_value_for_visibility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#nullable disable

namespace sparkly_server.Migrations
namespace sparkly_server.Services.Users.Migrations
{
/// <inheritdoc />
public partial class Default_value_for_visibility : Migration
Expand Down
2 changes: 1 addition & 1 deletion Migrations/20251119191413_Members_project.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Migrations/20251119191413_Members_project.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#nullable disable

namespace sparkly_server.Migrations
namespace sparkly_server.Services.Users.Migrations
{
/// <inheritdoc />
public partial class Members_project : Migration
Expand Down
2 changes: 1 addition & 1 deletion Migrations/AppDbContextModelSnapshot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

#nullable disable

namespace sparkly_server.Migrations
namespace sparkly_server.Services.Users.Migrations
{
[DbContext(typeof(AppDbContext))]
partial class AppDbContextModelSnapshot : ModelSnapshot
Expand Down
5 changes: 2 additions & 3 deletions Program.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Scalar.AspNetCore;
using sparkly_server.Enum;
using sparkly_server.Infrastructure;
using sparkly_server.Services.Auth;
using sparkly_server.Services.Users;
using sparkly_server.Services.UserServices;
using sparkly_server.Services.Projects;
using Scalar.AspNetCore;
using sparkly_server.Services.Users;
using System.Text;

var builder = WebApplication.CreateBuilder(args);
Expand Down
6 changes: 6 additions & 0 deletions sparkly-server.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,10 @@
<Content Include=".github\workflows\ci.yml" />
</ItemGroup>

<ItemGroup>
<Compile Remove="sparkly-server.test\HealthzTest.cs" />
<Compile Remove="sparkly-server.test\TestWebAppliactionFactory.cs" />
<Compile Remove="sparkly-server.test\UserTest.cs" />
</ItemGroup>

</Project>
5 changes: 3 additions & 2 deletions sparkly-server.test/HealthzTest.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Net;
using Sparkly.Tests.Infrastructure;
using System.Net;

namespace sparkly_server.test;
namespace sparkly_server.Services.Users.test;

public class HealthzTest : IClassFixture<TestWebApplicationFactory>
{
Expand Down
21 changes: 20 additions & 1 deletion sparkly-server.test/TestWebAppliactionFactory.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using sparkly_server.Infrastructure;

namespace sparkly_server.test;
namespace Sparkly.Tests.Infrastructure;

public class TestWebApplicationFactory : WebApplicationFactory<Program>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.UseEnvironment("Testing");

builder.ConfigureAppConfiguration((config) =>
{
var settings = new Dictionary<string, string?>
{
["SPARKLY_JWT_KEY"] = "this-is-very-long-test-jwt-key-123456",
["SPARKLY_JWT_ISSUER"] = "sparkly-test-issuer"
};

config.AddInMemoryCollection(settings);
});

builder.ConfigureServices(services =>
{
Expand All @@ -26,6 +38,13 @@ protected override void ConfigureWebHost(IWebHostBuilder builder)
{
options.UseInMemoryDatabase("sparkly-tests");
});

var sp = services.BuildServiceProvider();

using var scope = sp.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
db.Database.EnsureDeleted();
db.Database.EnsureCreated();
});
}
}
101 changes: 101 additions & 0 deletions sparkly-server.test/UserTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
using Microsoft.Extensions.DependencyInjection;
using sparkly_server.DTO.Auth;
using sparkly_server.Infrastructure;
using Sparkly.Tests.Infrastructure;
using System.Text;
using System.Text.Json;

namespace sparkly_server.Services.Users.test
{
public class UserTest : IClassFixture<TestWebApplicationFactory>, IAsyncLifetime
{
private readonly HttpClient _client;
private readonly TestWebApplicationFactory _factory;

public UserTest(TestWebApplicationFactory factory)
{
_factory = factory;
_client = factory.CreateClient();
}

public async Task InitializeAsync()
{
using var scope = _factory.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();

db.Users.RemoveRange(db.Users);
db.Projects.RemoveRange(db.Projects);
await db.SaveChangesAsync();
}

public Task DisposeAsync() => Task.CompletedTask;

private async Task RegisterTestUserAsync(string userName, string email, string password)
{
var payload = new RegisterRequest(Username: userName, Email: email, Password: password);

var content = new StringContent(
JsonSerializer.Serialize(payload),
Encoding.UTF8,
"application/json"
);

var response = await _client.PostAsync("/api/v1/auth/register", content);
response.EnsureSuccessStatusCode();
}

[Fact]
public async Task User_CanBeCreated()
{
var userName = $"user_{Guid.NewGuid():N}";
var email = $"{Guid.NewGuid():N}@example.com";
var password = "UserPassword";

await RegisterTestUserAsync(userName, email, password);
}

[Fact]
public async Task User_CanLoginByEmail()
{
var userName = $"user_{Guid.NewGuid():N}";
var email = $"{Guid.NewGuid():N}@example.com";
var password = "UserPassword";

await RegisterTestUserAsync(userName, email, password);

var payload = new LoginRequest(Identifier: email, Password: password);

var content = new StringContent(
JsonSerializer.Serialize(payload),
Encoding.UTF8,
"application/json"
);

var response = await _client.PostAsync("/api/v1/auth/login", content);

response.EnsureSuccessStatusCode();
}

[Fact]
public async Task User_CanLoginByUsername()
{
var userName = $"user_{Guid.NewGuid():N}";
var email = $"{Guid.NewGuid():N}@example.com";
var password = "UserPassword";

await RegisterTestUserAsync(userName, email, password);

var payload = new LoginRequest(Identifier: userName, Password: password);

var content = new StringContent(
JsonSerializer.Serialize(payload),
Encoding.UTF8,
"application/json"
);

var response = await _client.PostAsync("/api/v1/auth/login", content);

response.EnsureSuccessStatusCode();
}
}
}
1 change: 1 addition & 0 deletions sparkly-server.test/sparkly-server.test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<NoWarn>$(NoWarn);MSB3026</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions src/Controllers/User/AuthController.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using sparkly_server.DTO;
using sparkly_server.DTO.Auth;
using sparkly_server.Services.Auth;
using sparkly_server.Services.Users;

namespace sparkly_server.Controllers
namespace sparkly_server.Controllers.User
{
[ApiController]
[Route("api/v1/auth")]
Expand Down
3 changes: 1 addition & 2 deletions src/Controllers/User/ProfileController.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using sparkly_server.Infrastructure;
using sparkly_server.Services.Auth;
using sparkly_server.Services.Users;

namespace sparkly_server.Controllers
namespace sparkly_server.Controllers.User
{
[Authorize]
[ApiController]
Expand Down
2 changes: 1 addition & 1 deletion src/DTO/Auth/Auth.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace sparkly_server.DTO
namespace sparkly_server.DTO.Auth
{
public record RegisterRequest(string Username, string Email, string Password);
public record LoginRequest(string Identifier, string Password);
Expand Down
2 changes: 2 additions & 0 deletions src/Domain/Auth/RefreshToken.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using sparkly_server.Domain.Users;

namespace sparkly_server.Domain.Auth
{
public class RefreshToken
Expand Down
11 changes: 6 additions & 5 deletions src/Domain/Projects/Project.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
using sparkly_server.Enum;
using sparkly_server.Domain.Users;
using sparkly_server.Enum;

namespace sparkly_server.Domain.Projects
{
public class Project
{
public Guid Id { get; private set; }
public string ProjectName { get; private set; }
public string Description { get; private set; }
public string Slug { get; private set; }
public string ProjectName { get; private set; } = string.Empty;
public string Description { get; private set; } = string.Empty;
public string Slug { get; private set; } = string.Empty;
public DateTime CreatedAt { get; private set; }
public Guid OwnerId { get; private set; }
private readonly List<string> _tags = new();
Expand Down Expand Up @@ -152,7 +153,7 @@ public void RemoveMember(User user)
if (user is null)
throw new ArgumentNullException(nameof(user));

if (_members.Any(m => m.Id == user.Id))
if (!_members.Any(m => m.Id == user.Id))
return;

_members.Remove(user);
Expand Down
2 changes: 1 addition & 1 deletion src/Domain/Users/User.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using sparkly_server.Domain.Auth;
using sparkly_server.Domain.Projects;

namespace sparkly_server.Domain
namespace sparkly_server.Domain.Users
{
public class User
{
Expand Down
2 changes: 1 addition & 1 deletion src/Infrastructure/AppDbContext.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Microsoft.EntityFrameworkCore;
using sparkly_server.Domain;
using sparkly_server.Domain.Auth;
using sparkly_server.Domain.Projects;
using sparkly_server.Domain.Users;
using sparkly_server.Enum;

namespace sparkly_server.Infrastructure
Expand Down
4 changes: 2 additions & 2 deletions src/Services/Auth/AuthService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public async Task<AuthResult> RefreshAsync(string refreshToken, CancellationToke
{
if (string.IsNullOrWhiteSpace(refreshToken))
{
return null;
return null!;
}

var entity = await _db.RefreshTokens
Expand All @@ -64,7 +64,7 @@ public async Task<AuthResult> RefreshAsync(string refreshToken, CancellationToke

if (entity is null || !entity.IsActive)
{
return null;
return null!;
}

var user = entity.User;
Expand Down
Loading