Implement DI for backend services

This commit is contained in:
Laura Hausmann 2024-01-12 17:02:44 +01:00
parent 6ec6a43e1c
commit 80d6147757
No known key found for this signature in database
GPG key ID: D044E84C5BE01605
10 changed files with 47 additions and 32 deletions

View file

@ -12,14 +12,13 @@ namespace Iceshrimp.Backend.Controllers;
[ApiController]
[MediaTypeRouteFilter("application/activity+json", "application/ld+json")]
[Produces("application/activity+json", "application/ld+json")]
public class ActivityPubController : Controller {
public class ActivityPubController(ILogger<ActivityPubController> logger, DatabaseContext db) : Controller {
/*
[HttpGet("/notes/{id}")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Note))]
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(ErrorResponse))]
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(ErrorResponse))]
public async Task<IActionResult> GetNote(string id) {
var db = new DatabaseContext();
var note = await db.Notes.FirstOrDefaultAsync(p => p.Id == id);
if (note == null) return NotFound();
return Ok(note);
@ -29,7 +28,7 @@ public class ActivityPubController : Controller {
[HttpGet("/users/{id}")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(ASActor))]
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(ErrorResponse))]
public async Task<IActionResult> GetUser(string id, [FromServices] DatabaseContext db) {
public async Task<IActionResult> GetUser(string id) {
var user = await db.Users.FirstOrDefaultAsync(p => p.Id == id);
if (user == null) return NotFound();
var rendered = await ActivityPubUserRenderer.Render(user);

View file

@ -13,7 +13,7 @@ namespace Iceshrimp.Backend.Controllers;
[ApiController]
[Produces("application/json")]
[Route("/api/iceshrimp/v1/auth")]
public class AuthController : Controller {
public class AuthController(DatabaseContext db) : Controller {
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(AuthResponse))]
public async Task<IActionResult> GetAuthStatus() {
@ -27,7 +27,7 @@ public class AuthController : Controller {
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(ErrorResponse))]
[SuppressMessage("Performance",
"CA1862:Use the \'StringComparison\' method overloads to perform case-insensitive string comparisons")]
public async Task<IActionResult> Login([FromBody] AuthRequest request, [FromServices] DatabaseContext db) {
public async Task<IActionResult> Login([FromBody] AuthRequest request) {
var user = await db.Users.FirstOrDefaultAsync(p => p.UsernameLower == request.Username.ToLowerInvariant() &&
p.Host == null);
if (user == null) return Unauthorized();

View file

@ -4,7 +4,7 @@ using Iceshrimp.Backend.Core.Database.Tables;
namespace Iceshrimp.Backend.Controllers.Renderers.ActivityPub;
public class NoteRenderer {
public static class ActivityPubNoteRenderer {
public static NoteResponse RenderOne(Note note) {
return new NoteResponse {
Id = note.Id,

View file

@ -1,11 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Net.Mime;
using Iceshrimp.Backend.Controllers.Schemas;
using Iceshrimp.Backend.Core.Database;
using Iceshrimp.Backend.Core.Database.Tables;
using Iceshrimp.Backend.Core.Federation.Cryptography;
using Iceshrimp.Backend.Core.Helpers;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
@ -14,11 +9,10 @@ namespace Iceshrimp.Backend.Controllers;
[ApiController]
[Produces("application/json")]
[Route("/inbox")]
public class SignatureTestController : Controller {
public class SignatureTestController(ILogger<SignatureTestController> logger, DatabaseContext db) : Controller {
[HttpPost]
[Consumes(MediaTypeNames.Application.Json)]
public async Task<IActionResult> Inbox([FromServices] ILogger<SignatureTestController> logger,
[FromServices] DatabaseContext db) {
public async Task<IActionResult> Inbox() {
var sig = new HttpSignature(Request, ["(request-target)", "digest", "host", "date"]);
var key = await db.UserPublickeys.SingleOrDefaultAsync(p => p.KeyId == sig.KeyId);
var verified = key != null && sig.Verify(key.KeyPem);

View file

@ -9,11 +9,11 @@ namespace Iceshrimp.Backend.Controllers;
[ApiController]
[Produces("application/json")]
[Route("/api/iceshrimp/v1/user/{id}")]
public class UserController : Controller {
public class UserController(ILogger<UserController> logger, DatabaseContext db) : Controller {
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(UserResponse))]
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(ErrorResponse))]
public async Task<IActionResult> GetUser(string id, [FromServices] DatabaseContext db) {
public async Task<IActionResult> GetUser(string id) {
var user = await db.Users.FirstOrDefaultAsync(p => p.Id == id);
if (user == null) return NotFound();
return Ok(user);
@ -22,7 +22,7 @@ public class UserController : Controller {
[HttpGet("notes")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(TimelineResponse))]
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(ErrorResponse))]
public async Task<IActionResult> GetUserNotes(string id, [FromServices] DatabaseContext db) {
public async Task<IActionResult> GetUserNotes(string id) {
var user = await db.Users.FirstOrDefaultAsync(p => p.Id == id);
if (user == null) return NotFound();

View file

@ -2,7 +2,7 @@ using Iceshrimp.Backend.Core.Database.Tables;
namespace Iceshrimp.Backend.Core.Federation.WebFinger;
public static class UserResolver {
public class UserResolver(ILogger<UserResolver> logger) {
private static string AcctToDomain(string acct) =>
acct.StartsWith("acct:") && acct.Contains('@')
? acct[5..].Split('@')[1]
@ -15,12 +15,12 @@ public static class UserResolver {
* TODO: finish description and implement the rest
*/
public static async Task<User> Resolve(string query) {
public async Task<User> Resolve(string query) {
var finger = new WebFinger(query);
var fingerRes = await finger.Resolve();
if (fingerRes == null) throw new Exception($"Failed to WebFinger '{query}'");
if (finger.Domain != AcctToDomain(fingerRes.Subject)) {
//TODO: Logger.info("possible split domain deployment detected, repeating webfinger")
logger.LogInformation("possible split domain deployment detected, repeating webfinger");
finger = new WebFinger(fingerRes.Subject);
fingerRes = await finger.Resolve();

View file

@ -0,0 +1,21 @@
using Iceshrimp.Backend.Core.Configuration;
using Iceshrimp.Backend.Core.Services;
namespace Iceshrimp.Backend.Core.Helpers;
public static class ServiceExtensions {
public static void AddServices(this IServiceCollection services) {
services.AddScoped<UserService>();
services.AddScoped<NoteService>();
}
public static void ConfigureServices(this IServiceCollection services, IConfiguration configuration) {
//TODO: fail if config doesn't parse correctly / required things are missing
services.Configure<Config.InstanceSection>(configuration.GetSection("Instance"));
services.Configure<Config.DatabaseSection>(configuration.GetSection("Database"));
services.AddScoped<Config.InstanceSection>();
services.AddScoped<Config.DatabaseSection>();
Config.StartupConfig = configuration.Get<Config>()!;
}
}

View file

@ -1,7 +1,9 @@
using Iceshrimp.Backend.Core.Database;
namespace Iceshrimp.Backend.Core.Services;
public static class NoteService {
public static async Task CreateNote() {
public class NoteService(ILogger<NoteService> logger, DatabaseContext db) {
public async Task CreateNote() {
}
}

View file

@ -1,7 +1,10 @@
using Iceshrimp.Backend.Core.Database;
namespace Iceshrimp.Backend.Core.Services;
public static class UserService {
public static async Task CreateUser() {
public class UserService(ILogger<UserService> logger, DatabaseContext db) {
public async Task CreateUser() {
}
}

View file

@ -1,6 +1,8 @@
using Asp.Versioning;
using Iceshrimp.Backend.Core.Configuration;
using Iceshrimp.Backend.Core.Database;
using Iceshrimp.Backend.Core.Helpers;
using Iceshrimp.Backend.Core.Services;
using Vite.AspNetCore.Extensions;
var builder = WebApplication.CreateBuilder(args);
@ -22,7 +24,6 @@ builder.Services.AddApiVersioning(options => {
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddRazorPages();
//TODO: load built assets in production
builder.Services.AddViteServices(options => {
options.PackageDirectory = "../Iceshrimp.Frontend";
options.PackageManager = "yarn";
@ -32,13 +33,8 @@ builder.Services.AddViteServices(options => {
builder.Services.AddLogging(logging => logging.AddSimpleConsole(options => { options.SingleLine = true; }));
builder.Services.AddDbContext<DatabaseContext>();
//TODO: fail if config doesn't parse correctly / required things are missing
builder.Services.Configure<Config.InstanceSection>(builder.Configuration.GetSection("Instance"));
builder.Services.Configure<Config.DatabaseSection>(builder.Configuration.GetSection("Database"));
builder.Services.AddScoped<Config.InstanceSection>();
builder.Services.AddScoped<Config.DatabaseSection>();
Config.StartupConfig = builder.Configuration.Get<Config>()!;
builder.Services.AddServices();
builder.Services.ConfigureServices(builder.Configuration);
var app = builder.Build();
app.Logger.LogInformation("Initializing, please wait...");