using System.Net;
using AutopilotMonitor.Functions.Helpers;
using AutopilotMonitor.Functions.Services;
using AutopilotMonitor.Shared.Models;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace AutopilotMonitor.Functions.Functions.Rules
{
///
/// CRUD API for managing gather rules (portal-facing, JWT auth)
///
public class GatherRulesFunction
{
private readonly ILogger _logger;
private readonly GatherRuleService _ruleService;
public GatherRulesFunction(
ILogger logger,
GatherRuleService ruleService)
{
_logger = logger;
_ruleService = ruleService;
}
[Function("GetGatherRules")]
public async Task GetRules(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "rules/gather")] HttpRequestData req)
{
// Authentication + MemberRead authorization enforced by PolicyEnforcementMiddleware
var tenantId = TenantHelper.GetTenantId(req);
var rules = await _ruleService.GetAllRulesForTenantAsync(tenantId);
var response = req.CreateResponse(HttpStatusCode.OK);
await response.WriteAsJsonAsync(new { success = true, rules });
return response;
}
[Function("CreateGatherRule")]
public async Task CreateRule(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "rules/gather")] HttpRequestData req)
{
// Authentication + TenantAdminOrGA authorization enforced by PolicyEnforcementMiddleware
var tenantId = TenantHelper.GetTenantId(req);
if (req.Headers.TryGetValues("Content-Length", out var clValues)
&& long.TryParse(clValues.FirstOrDefault(), out var contentLength)
&& contentLength > 1_048_576) // 1 MB limit
{
var badRequest = req.CreateResponse(HttpStatusCode.BadRequest);
await badRequest.WriteAsJsonAsync(new { success = false, message = "Request body too large" });
return badRequest;
}
var body = await new StreamReader(req.Body).ReadToEndAsync();
var rule = JsonConvert.DeserializeObject(body);
if (rule == null || string.IsNullOrEmpty(rule.RuleId))
{
var badRequest = req.CreateResponse(HttpStatusCode.BadRequest);
await badRequest.WriteAsJsonAsync(new { success = false, message = "Invalid rule data" });
return badRequest;
}
var success = await _ruleService.CreateRuleAsync(tenantId, rule);
var response = req.CreateResponse(success ? HttpStatusCode.Created : HttpStatusCode.InternalServerError);
await response.WriteAsJsonAsync(new { success, message = success ? "Rule created" : "Failed to create rule" });
return response;
}
[Function("UpdateGatherRule")]
public async Task UpdateRule(
[HttpTrigger(AuthorizationLevel.Anonymous, "put", Route = "rules/gather/{ruleId}")] HttpRequestData req,
string ruleId)
{
// Authentication + TenantAdminOrGA authorization enforced by PolicyEnforcementMiddleware
var tenantId = TenantHelper.GetTenantId(req);
if (req.Headers.TryGetValues("Content-Length", out var clValues2)
&& long.TryParse(clValues2.FirstOrDefault(), out var contentLength2)
&& contentLength2 > 1_048_576) // 1 MB limit
{
var badRequest = req.CreateResponse(HttpStatusCode.BadRequest);
await badRequest.WriteAsJsonAsync(new { success = false, message = "Request body too large" });
return badRequest;
}
var body = await new StreamReader(req.Body).ReadToEndAsync();
var rule = JsonConvert.DeserializeObject(body);
if (rule == null)
{
var badRequest = req.CreateResponse(HttpStatusCode.BadRequest);
await badRequest.WriteAsJsonAsync(new { success = false, message = "Invalid rule data" });
return badRequest;
}
rule.RuleId = ruleId;
var success = await _ruleService.UpdateRuleAsync(tenantId, rule);
var response = req.CreateResponse(success ? HttpStatusCode.OK : HttpStatusCode.InternalServerError);
await response.WriteAsJsonAsync(new { success, message = success ? "Rule updated" : "Failed to update rule" });
return response;
}
[Function("DeleteGatherRule")]
public async Task DeleteRule(
[HttpTrigger(AuthorizationLevel.Anonymous, "delete", Route = "rules/gather/{ruleId}")] HttpRequestData req,
string ruleId)
{
// Authentication + TenantAdminOrGA authorization enforced by PolicyEnforcementMiddleware
var tenantId = TenantHelper.GetTenantId(req);
// Load the rule to determine its type (built-in/community vs. custom)
var rules = await _ruleService.GetAllRulesForTenantAsync(tenantId);
var rule = rules.FirstOrDefault(r => r.RuleId == ruleId);
if (rule == null)
{
var notFound = req.CreateResponse(HttpStatusCode.NotFound);
await notFound.WriteAsJsonAsync(new { success = false, message = "Rule not found" });
return notFound;
}
var success = await _ruleService.DeleteRuleAsync(tenantId, rule);
var response = req.CreateResponse(success ? HttpStatusCode.OK : HttpStatusCode.InternalServerError);
await response.WriteAsJsonAsync(new { success, message = success ? "Rule deleted" : "Failed to delete rule" });
return response;
}
}
}