feat/Update_Controllers_to_Allow_for_Premium_Membership

This commit is contained in:
cesnimda
2026-08-03 09:17:28 +02:00
parent de937d25dc
commit c3f4a57195
187 changed files with 26062 additions and 991 deletions
+64
View File
@@ -0,0 +1,64 @@
using System.Security.Claims;
using JobTrackerApi.Models;
using Microsoft.AspNetCore.Identity;
namespace JobTrackerApi.Services;
public sealed record AiPrivacyDecision(bool ExternalProcessingAllowed, string Provider);
public sealed class AiPrivacyPolicy(IConfiguration configuration, IServiceScopeFactory scopes)
{
public const string ExternalAllowedHeader = "X-Ai-External-Allowed";
public string ExternalProvider
{
get
{
var provider = (configuration["Ai:ExternalProvider"] ?? "ollama").Trim().ToLowerInvariant();
return provider is "gemini" or "groq" ? provider : "ollama";
}
}
public bool ExternalProcessingAvailable =>
configuration.GetValue("Ai:ExternalProcessingEnabled", false)
&& ExternalProvider is "gemini" or "groq";
public async Task<AiPrivacyDecision> EvaluateAsync(string? userId, CancellationToken cancellationToken = default)
{
if (!ExternalProcessingAvailable || string.IsNullOrWhiteSpace(userId))
return new AiPrivacyDecision(false, "local");
await using var scope = scopes.CreateAsyncScope();
var users = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
var user = await users.FindByIdAsync(userId);
cancellationToken.ThrowIfCancellationRequested();
if (user is null || !user.AiEnabled || !user.ExternalAiProcessingAllowed)
return new AiPrivacyDecision(false, "local");
var isPro = AccountPlans.ForRoles(await users.GetRolesAsync(user)).Ai;
return isPro
? new AiPrivacyDecision(true, ExternalProvider)
: new AiPrivacyDecision(false, "local");
}
}
public sealed class AiPrivacyHeaderHandler(
IHttpContextAccessor httpContext,
AiPrivacyPolicy privacyPolicy) : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
if (request.RequestUri?.AbsolutePath.StartsWith("/cv/", StringComparison.OrdinalIgnoreCase) == true)
{
var userId = httpContext.HttpContext?.User.FindFirstValue(ClaimTypes.NameIdentifier)
?? httpContext.HttpContext?.User.FindFirstValue("sub");
var decision = await privacyPolicy.EvaluateAsync(userId, cancellationToken);
if (decision.ExternalProcessingAllowed)
request.Headers.TryAddWithoutValidation(AiPrivacyPolicy.ExternalAllowedHeader, "true");
}
return await base.SendAsync(request, cancellationToken);
}
}