91 lines
4.0 KiB
C#
91 lines
4.0 KiB
C#
using HuntingAppApi.Models;
|
|
using HuntingAppApi.Services;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Npgsql;
|
|
using NpgsqlTypes;
|
|
|
|
namespace HuntingAppApi.Controllers;
|
|
|
|
[ApiController]
|
|
[Route("api/auth")]
|
|
public sealed class AuthController(NpgsqlDataSource dataSource, ExternalTokenValidator validator, JwtTokenService jwt) : ControllerBase
|
|
{
|
|
[HttpPost("external-login")]
|
|
public async Task<ActionResult<LoginResponse>> ExternalLogin([FromBody] ExternalLoginRequest request, CancellationToken ct)
|
|
{
|
|
var external = await validator.ValidateAsync(request.Provider, request.IdToken, ct);
|
|
|
|
await using var conn = await dataSource.OpenConnectionAsync(ct);
|
|
await using var tx = await conn.BeginTransactionAsync(ct);
|
|
|
|
Guid? userId = null;
|
|
string displayName = external.DisplayName;
|
|
string? email = external.Email;
|
|
|
|
await using (var find = new NpgsqlCommand("""
|
|
SELECT u.id, u.display_name, u.email
|
|
FROM user_identity i
|
|
JOIN app_user u ON u.id = i.user_id
|
|
WHERE i.provider = @provider AND i.provider_subject = @subject
|
|
""", conn, tx))
|
|
{
|
|
find.Parameters.AddWithValue("provider", external.Provider);
|
|
find.Parameters.AddWithValue("subject", external.Subject);
|
|
await using var r = await find.ExecuteReaderAsync(ct);
|
|
if (await r.ReadAsync(ct))
|
|
{
|
|
userId = r.GetGuid(0);
|
|
displayName = r.GetString(1);
|
|
email = r.IsDBNull(2) ? null : r.GetString(2);
|
|
}
|
|
}
|
|
|
|
if (userId is null)
|
|
{
|
|
userId = Guid.NewGuid();
|
|
await using var createUser = new NpgsqlCommand("""
|
|
INSERT INTO app_user (id, display_name, email, avatar_url)
|
|
VALUES (@id, @display_name, @email, @avatar_url)
|
|
""", conn, tx);
|
|
createUser.Parameters.AddWithValue("id", userId.Value);
|
|
createUser.Parameters.AddWithValue("display_name", displayName);
|
|
createUser.Parameters.AddWithValue("email", (object?)email ?? DBNull.Value);
|
|
createUser.Parameters.AddWithValue("avatar_url", (object?)external.AvatarUrl ?? DBNull.Value);
|
|
await createUser.ExecuteNonQueryAsync(ct);
|
|
|
|
await using var createIdentity = new NpgsqlCommand("""
|
|
INSERT INTO user_identity (user_id, provider, provider_subject, email, email_verified, display_name, avatar_url)
|
|
VALUES (@user_id, @provider, @subject, @email, @email_verified, @display_name, @avatar_url)
|
|
""", conn, tx);
|
|
createIdentity.Parameters.AddWithValue("user_id", userId.Value);
|
|
createIdentity.Parameters.AddWithValue("provider", external.Provider);
|
|
createIdentity.Parameters.AddWithValue("subject", external.Subject);
|
|
createIdentity.Parameters.AddWithValue("email", (object?)email ?? DBNull.Value);
|
|
createIdentity.Parameters.AddWithValue("email_verified", external.EmailVerified);
|
|
createIdentity.Parameters.AddWithValue("display_name", displayName);
|
|
createIdentity.Parameters.AddWithValue("avatar_url", (object?)external.AvatarUrl ?? DBNull.Value);
|
|
await createIdentity.ExecuteNonQueryAsync(ct);
|
|
}
|
|
else
|
|
{
|
|
await using var updateLogin = new NpgsqlCommand("""
|
|
UPDATE user_identity SET last_login_at = now()
|
|
WHERE provider = @provider AND provider_subject = @subject
|
|
""", conn, tx);
|
|
updateLogin.Parameters.AddWithValue("provider", external.Provider);
|
|
updateLogin.Parameters.AddWithValue("subject", external.Subject);
|
|
await updateLogin.ExecuteNonQueryAsync(ct);
|
|
}
|
|
|
|
await tx.CommitAsync(ct);
|
|
|
|
return Ok(new LoginResponse
|
|
{
|
|
UserId = userId.Value,
|
|
DisplayName = displayName,
|
|
Email = email,
|
|
Token = jwt.CreateToken(userId.Value, displayName, email)
|
|
});
|
|
}
|
|
}
|