format, add more query extensions

This commit is contained in:
sam 2024-05-30 16:59:40 +02:00
parent f674d059fd
commit 852036a6f7
Signed by: sam
GPG key ID: B4EF20DDE721CAA1
7 changed files with 52 additions and 8 deletions

View file

@ -13,14 +13,15 @@ public class UsersController(DatabaseContext db, UserRendererService userRendere
public async Task<IActionResult> GetUser(string userRef) public async Task<IActionResult> GetUser(string userRef)
{ {
var user = await db.ResolveUserAsync(userRef); var user = await db.ResolveUserAsync(userRef);
return Ok(await userRendererService.RenderUserAsync(user)); return Ok(await userRendererService.RenderUserAsync(user, selfUser: User));
} }
[HttpGet("@me")] [HttpGet("@me")]
[Authorize("identify")] [Authorize("identify")]
public Task<IActionResult> GetMe() public async Task<IActionResult> GetMe()
{ {
throw new NotImplementedException(); var user = await db.ResolveUserAsync(User!.Id);
return Ok(await userRendererService.RenderUserAsync(user, selfUser: User));
} }
[HttpPatch("@me")] [HttpPatch("@me")]

View file

@ -23,6 +23,48 @@ public static class DatabaseQueryExtensions
throw new ApiError.NotFound("No user with that ID or username found.", code: ErrorCode.UserNotFound); throw new ApiError.NotFound("No user with that ID or username found.", code: ErrorCode.UserNotFound);
} }
public static async Task<User> ResolveUserAsync(this DatabaseContext context, Snowflake id)
{
var user = await context.Users
.FirstOrDefaultAsync(u => u.Id == id);
if (user != null) return user;
throw new ApiError.NotFound("No user with that ID found.", code: ErrorCode.UserNotFound);
}
public static async Task<Member> ResolveMemberAsync(this DatabaseContext context, Snowflake id)
{
var member = await context.Members
.Include(m => m.User)
.FirstOrDefaultAsync(m => m.Id == id);
if (member != null) return member;
throw new ApiError.NotFound("No member with that ID found.", code: ErrorCode.MemberNotFound);
}
public static async Task<Member> ResolveMemberAsync(this DatabaseContext context, string userRef, string memberRef)
{
var user = await context.ResolveUserAsync(userRef);
return await context.ResolveMemberAsync(user.Id, memberRef);
}
public static async Task<Member> ResolveMemberAsync(this DatabaseContext context, Snowflake userId,
string memberRef)
{
Member? member;
if (Snowflake.TryParse(memberRef, out var snowflake))
{
member = await context.Members
.Include(m => m.User)
.FirstOrDefaultAsync(m => m.Id == snowflake && m.UserId == userId);
if (member != null) return member;
}
member = await context.Members
.Include(m => m.User)
.FirstOrDefaultAsync(m => m.Name == memberRef && m.UserId == userId);
if (member != null) return member;
throw new ApiError.NotFound("No member with that ID or name found.", code: ErrorCode.MemberNotFound);
}
public static async Task<Application> GetFrontendApplicationAsync(this DatabaseContext context) public static async Task<Application> GetFrontendApplicationAsync(this DatabaseContext context)
{ {
var app = await context.Applications.FirstOrDefaultAsync(a => a.Id == new Snowflake(0)); var app = await context.Applications.FirstOrDefaultAsync(a => a.Id == new Snowflake(0));

View file

@ -131,7 +131,7 @@ namespace Foxnouns.Backend.Database.Migrations
name: "ix_auth_methods_user_id", name: "ix_auth_methods_user_id",
table: "auth_methods", table: "auth_methods",
column: "user_id"); column: "user_id");
// EF Core doesn't support creating indexes on arbitrary expressions, so we have to create it manually. // EF Core doesn't support creating indexes on arbitrary expressions, so we have to create it manually.
// Due to historical reasons (I made a mistake while writing the initial migration for the Go version) // Due to historical reasons (I made a mistake while writing the initial migration for the Go version)
// only members have case-insensitive names. // only members have case-insensitive names.

View file

@ -8,7 +8,7 @@ public class AuthMethod : BaseModel
public Snowflake UserId { get; init; } public Snowflake UserId { get; init; }
public User User { get; init; } = null!; public User User { get; init; } = null!;
public Snowflake? FediverseApplicationId { get; init; } public Snowflake? FediverseApplicationId { get; init; }
public FediverseApplication? FediverseApplication { get; init; } public FediverseApplication? FediverseApplication { get; init; }
} }

View file

@ -75,4 +75,5 @@ public enum ErrorCode
AuthenticationError, AuthenticationError,
GenericApiError, GenericApiError,
UserNotFound, UserNotFound,
MemberNotFound,
} }

View file

@ -110,7 +110,7 @@ public static class WebApplicationExtensions
pendingMigrations.Count); pendingMigrations.Count);
Environment.Exit(1); Environment.Exit(1);
} }
logger.Information("Initializing frontend OAuth application"); logger.Information("Initializing frontend OAuth application");
_ = await db.GetFrontendApplicationAsync(); _ = await db.GetFrontendApplicationAsync();
} }

View file

@ -16,13 +16,13 @@ public static class OauthUtils
/// <summary> /// <summary>
/// All scopes endpoints can be secured by. This does *not* include the catch-all token scopes. /// All scopes endpoints can be secured by. This does *not* include the catch-all token scopes.
/// </summary> /// </summary>
public static readonly string[] Scopes = ["identify", ..UserScopes, ..MemberScopes]; public static readonly string[] Scopes = ["identify", .. UserScopes, .. MemberScopes];
/// <summary> /// <summary>
/// All scopes that can be granted to applications and tokens. Includes the catch-all token scopes, /// All scopes that can be granted to applications and tokens. Includes the catch-all token scopes,
/// except for "*" which is only granted to the frontend. /// except for "*" which is only granted to the frontend.
/// </summary> /// </summary>
public static readonly string[] ApplicationScopes = [..Scopes, "user", "member"]; public static readonly string[] ApplicationScopes = [.. Scopes, "user", "member"];
public static string[] ExpandScopes(this string[] scopes) public static string[] ExpandScopes(this string[] scopes)
{ {