Migrate MarkSession Functions, SearchByCve, AnalyzeRule/GatherRule services to DAL

- MarkSessionFailedFunction, MarkSessionSucceededFunction → ISessionRepository + IMaintenanceRepository
- SearchSessionsByCveFunction → ISessionRepository
- AnalyzeRuleService, GatherRuleService → IRuleRepository
- ImeLogPatternService → IRuleRepository

https://claude.ai/code/session_01NHWJfPaa8TQHuPzMD7gG63
This commit is contained in:
Claude
2026-03-27 06:30:14 +00:00
parent 5b4e4238f3
commit 2c83bca248
7 changed files with 81 additions and 71 deletions
@@ -1,6 +1,6 @@
using System.Net;
using AutopilotMonitor.Functions.Helpers;
using AutopilotMonitor.Functions.Services;
using AutopilotMonitor.Shared.DataAccess;
using AutopilotMonitor.Shared.Models;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
@@ -12,14 +12,17 @@ namespace AutopilotMonitor.Functions.Functions.Sessions
public class MarkSessionFailedFunction
{
private readonly ILogger<MarkSessionFailedFunction> _logger;
private readonly TableStorageService _storageService;
private readonly ISessionRepository _sessionRepo;
private readonly IMaintenanceRepository _maintenanceRepo;
public MarkSessionFailedFunction(
ILogger<MarkSessionFailedFunction> logger,
TableStorageService storageService)
ISessionRepository sessionRepo,
IMaintenanceRepository maintenanceRepo)
{
_logger = logger;
_storageService = storageService;
_sessionRepo = sessionRepo;
_maintenanceRepo = maintenanceRepo;
}
[Function("MarkSessionFailed")]
@@ -38,7 +41,7 @@ namespace AutopilotMonitor.Functions.Functions.Sessions
_logger.LogInformation($"Marking session {sessionId} as failed for tenant {tenantId} by user {userIdentifier}");
// Update session status to Failed with manual failure reason
var success = await _storageService.UpdateSessionStatusAsync(
var success = await _sessionRepo.UpdateSessionStatusAsync(
tenantId,
sessionId,
SessionStatus.Failed,
@@ -49,7 +52,7 @@ namespace AutopilotMonitor.Functions.Functions.Sessions
if (success)
{
// Log audit entry with actual user identifier
await _storageService.LogAuditEntryAsync(
await _maintenanceRepo.LogAuditEntryAsync(
tenantId,
"UPDATE",
"Session",
@@ -63,7 +66,7 @@ namespace AutopilotMonitor.Functions.Functions.Sessions
);
// Retrieve updated session data to include in SignalR message
var updatedSession = await _storageService.GetSessionAsync(tenantId, sessionId);
var updatedSession = await _sessionRepo.GetSessionAsync(tenantId, sessionId);
_logger.LogInformation($"Successfully marked session {sessionId} as failed");
var response = req.CreateResponse(HttpStatusCode.OK);
@@ -1,6 +1,6 @@
using System.Net;
using AutopilotMonitor.Functions.Helpers;
using AutopilotMonitor.Functions.Services;
using AutopilotMonitor.Shared.DataAccess;
using AutopilotMonitor.Shared.Models;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
@@ -12,14 +12,17 @@ namespace AutopilotMonitor.Functions.Functions.Sessions
public class MarkSessionSucceededFunction
{
private readonly ILogger<MarkSessionSucceededFunction> _logger;
private readonly TableStorageService _storageService;
private readonly ISessionRepository _sessionRepo;
private readonly IMaintenanceRepository _maintenanceRepo;
public MarkSessionSucceededFunction(
ILogger<MarkSessionSucceededFunction> logger,
TableStorageService storageService)
ISessionRepository sessionRepo,
IMaintenanceRepository maintenanceRepo)
{
_logger = logger;
_storageService = storageService;
_sessionRepo = sessionRepo;
_maintenanceRepo = maintenanceRepo;
}
[Function("MarkSessionSucceeded")]
@@ -38,7 +41,7 @@ namespace AutopilotMonitor.Functions.Functions.Sessions
_logger.LogInformation($"Marking session {sessionId} as succeeded for tenant {tenantId} by user {userIdentifier}");
// Update session status to Succeeded with manual reason
var success = await _storageService.UpdateSessionStatusAsync(
var success = await _sessionRepo.UpdateSessionStatusAsync(
tenantId,
sessionId,
SessionStatus.Succeeded,
@@ -49,7 +52,7 @@ namespace AutopilotMonitor.Functions.Functions.Sessions
if (success)
{
// Log audit entry with actual user identifier
await _storageService.LogAuditEntryAsync(
await _maintenanceRepo.LogAuditEntryAsync(
tenantId,
"UPDATE",
"Session",
@@ -63,7 +66,7 @@ namespace AutopilotMonitor.Functions.Functions.Sessions
);
// Retrieve updated session data to include in SignalR message
var updatedSession = await _storageService.GetSessionAsync(tenantId, sessionId);
var updatedSession = await _sessionRepo.GetSessionAsync(tenantId, sessionId);
_logger.LogInformation($"Successfully marked session {sessionId} as succeeded");
var response = req.CreateResponse(HttpStatusCode.OK);
@@ -1,6 +1,7 @@
using System.Net;
using AutopilotMonitor.Functions.Security;
using AutopilotMonitor.Functions.Services;
using AutopilotMonitor.Shared.DataAccess;
using AutopilotMonitor.Shared.Models;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
@@ -56,7 +56,7 @@ public class SearchSessionsByCveFunction
var overallRisk = query["overallRisk"];
var limit = int.TryParse(query["limit"], out var lim) ? Math.Min(lim, 100) : 50;
var sessions = await _storageService.SearchSessionsByCveAsync(tenantId, cveId, minCvssScore, overallRisk, limit);
var sessions = await _sessionRepo.SearchSessionsByCveAsync(tenantId, cveId, minCvssScore, overallRisk, limit);
var response = req.CreateResponse(HttpStatusCode.OK);
await response.WriteAsJsonAsync(new
@@ -1,3 +1,4 @@
using AutopilotMonitor.Shared.DataAccess;
using AutopilotMonitor.Shared.Models;
using Microsoft.Extensions.Logging;
@@ -12,13 +13,13 @@ namespace AutopilotMonitor.Functions.Services
/// </summary>
public class AnalyzeRuleService
{
private readonly TableStorageService _storageService;
private readonly IRuleRepository _ruleRepo;
private readonly ILogger<AnalyzeRuleService> _logger;
private bool _seeded = false;
public AnalyzeRuleService(TableStorageService storageService, ILogger<AnalyzeRuleService> logger)
public AnalyzeRuleService(IRuleRepository ruleRepo, ILogger<AnalyzeRuleService> logger)
{
_storageService = storageService;
_ruleRepo = ruleRepo;
_logger = logger;
}
@@ -39,14 +40,14 @@ namespace AutopilotMonitor.Functions.Services
await EnsureBuiltInRulesSeededAsync();
// Global rules: built-in + community (single source of truth for definitions)
var globalRules = await _storageService.GetAnalyzeRulesAsync("global");
var globalRules = await _ruleRepo.GetAnalyzeRulesAsync("global");
// Tenant rules: only custom rules (IsBuiltIn=false, IsCommunity=false)
var tenantRules = await _storageService.GetAnalyzeRulesAsync(tenantId);
var tenantRules = await _ruleRepo.GetAnalyzeRulesAsync(tenantId);
var customRules = tenantRules.Where(r => !r.IsBuiltIn && !r.IsCommunity).ToList();
// Per-tenant enabled/disabled states for global rules
var ruleStates = await _storageService.GetRuleStatesAsync(tenantId);
var ruleStates = await _ruleRepo.GetRuleStatesAsync(tenantId);
var mergedRules = new List<AnalyzeRule>();
@@ -73,7 +74,7 @@ namespace AutopilotMonitor.Functions.Services
rule.IsCommunity = false;
rule.CreatedAt = DateTime.UtcNow;
rule.UpdatedAt = DateTime.UtcNow;
return await _storageService.StoreAnalyzeRuleAsync(rule, tenantId);
return await _ruleRepo.StoreAnalyzeRuleAsync(rule, tenantId);
}
/// <summary>
@@ -85,11 +86,11 @@ namespace AutopilotMonitor.Functions.Services
{
if (rule.IsBuiltIn || rule.IsCommunity)
{
return await _storageService.StoreRuleStateAsync(tenantId, rule.RuleId, rule.Enabled);
return await _ruleRepo.StoreRuleStateAsync(tenantId, rule.RuleId, rule.Enabled);
}
rule.UpdatedAt = DateTime.UtcNow;
return await _storageService.StoreAnalyzeRuleAsync(rule, tenantId);
return await _ruleRepo.StoreAnalyzeRuleAsync(rule, tenantId);
}
/// <summary>
@@ -101,10 +102,10 @@ namespace AutopilotMonitor.Functions.Services
{
if (rule.IsBuiltIn || rule.IsCommunity)
{
return await _storageService.DeleteRuleStateAsync(tenantId, rule.RuleId);
return await _ruleRepo.DeleteRuleStateAsync(tenantId, rule.RuleId);
}
return await _storageService.DeleteAnalyzeRuleAsync(tenantId, rule.RuleId);
return await _ruleRepo.DeleteAnalyzeRuleAsync(tenantId, rule.RuleId);
}
/// <summary>
@@ -116,12 +117,12 @@ namespace AutopilotMonitor.Functions.Services
{
_logger.LogInformation("Reseeding built-in analyze rules (full re-import)...");
var existingGlobalRules = await _storageService.GetAnalyzeRulesAsync("global");
var existingGlobalRules = await _ruleRepo.GetAnalyzeRulesAsync("global");
var deleted = 0;
foreach (var rule in existingGlobalRules.Where(r => r.IsBuiltIn))
{
await _storageService.DeleteAnalyzeRuleAsync("global", rule.RuleId);
await _ruleRepo.DeleteAnalyzeRuleAsync("global", rule.RuleId);
deleted++;
}
_logger.LogInformation($"Deleted {deleted} old global built-in analyze rules");
@@ -129,7 +130,7 @@ namespace AutopilotMonitor.Functions.Services
var builtInRules = BuiltInAnalyzeRules.GetAll();
foreach (var rule in builtInRules)
{
await _storageService.StoreAnalyzeRuleAsync(rule, "global");
await _ruleRepo.StoreAnalyzeRuleAsync(rule, "global");
}
_logger.LogInformation($"Written {builtInRules.Count} built-in analyze rules from code");
@@ -146,7 +147,7 @@ namespace AutopilotMonitor.Functions.Services
{
if (_seeded) return;
var existingRules = await _storageService.GetAnalyzeRulesAsync("global");
var existingRules = await _ruleRepo.GetAnalyzeRulesAsync("global");
var builtInRules = BuiltInAnalyzeRules.GetAll();
if (existingRules.Count == 0)
@@ -154,7 +155,7 @@ namespace AutopilotMonitor.Functions.Services
_logger.LogInformation("Seeding built-in analyze rules...");
foreach (var rule in builtInRules)
{
await _storageService.StoreAnalyzeRuleAsync(rule, "global");
await _ruleRepo.StoreAnalyzeRuleAsync(rule, "global");
}
_logger.LogInformation($"Seeded {builtInRules.Count} built-in analyze rules");
}
@@ -173,14 +174,14 @@ namespace AutopilotMonitor.Functions.Services
|| existing.Severity != rule.Severity
|| existing.Trigger != rule.Trigger)
{
await _storageService.StoreAnalyzeRuleAsync(rule, "global");
await _ruleRepo.StoreAnalyzeRuleAsync(rule, "global");
updated++;
}
}
else
{
// New built-in rule added in code
await _storageService.StoreAnalyzeRuleAsync(rule, "global");
await _ruleRepo.StoreAnalyzeRuleAsync(rule, "global");
updated++;
}
}
@@ -1,3 +1,4 @@
using AutopilotMonitor.Shared.DataAccess;
using AutopilotMonitor.Shared.Models;
using Microsoft.Extensions.Logging;
using System.Linq;
@@ -13,13 +14,13 @@ namespace AutopilotMonitor.Functions.Services
/// </summary>
public class GatherRuleService
{
private readonly TableStorageService _storageService;
private readonly IRuleRepository _ruleRepo;
private readonly ILogger<GatherRuleService> _logger;
private bool _seeded = false;
public GatherRuleService(TableStorageService storageService, ILogger<GatherRuleService> logger)
public GatherRuleService(IRuleRepository ruleRepo, ILogger<GatherRuleService> logger)
{
_storageService = storageService;
_ruleRepo = ruleRepo;
_logger = logger;
}
@@ -40,14 +41,14 @@ namespace AutopilotMonitor.Functions.Services
await EnsureBuiltInRulesSeededAsync();
// Global rules: built-in + community (single source of truth for definitions)
var globalRules = await _storageService.GetGatherRulesAsync("global");
var globalRules = await _ruleRepo.GetGatherRulesAsync("global");
// Tenant rules: only custom rules (IsBuiltIn=false, IsCommunity=false)
var tenantRules = await _storageService.GetGatherRulesAsync(tenantId);
var tenantRules = await _ruleRepo.GetGatherRulesAsync(tenantId);
var customRules = tenantRules.Where(r => !r.IsBuiltIn && !r.IsCommunity).ToList();
// Per-tenant enabled/disabled states for global rules
var ruleStates = await _storageService.GetRuleStatesAsync(tenantId);
var ruleStates = await _ruleRepo.GetRuleStatesAsync(tenantId);
var mergedRules = new List<GatherRule>();
@@ -74,7 +75,7 @@ namespace AutopilotMonitor.Functions.Services
rule.IsCommunity = false;
rule.CreatedAt = DateTime.UtcNow;
rule.UpdatedAt = DateTime.UtcNow;
return await _storageService.StoreGatherRuleAsync(rule, tenantId);
return await _ruleRepo.StoreGatherRuleAsync(rule, tenantId);
}
/// <summary>
@@ -89,13 +90,13 @@ namespace AutopilotMonitor.Functions.Services
{
// Always check global rules for type determination — the incoming payload
// may not include isBuiltIn/isCommunity (e.g. toggle requests).
var globalRules = await _storageService.GetGatherRulesAsync("global");
var globalRules = await _ruleRepo.GetGatherRulesAsync("global");
var globalRule = globalRules.FirstOrDefault(r => r.RuleId == rule.RuleId);
if (globalRule != null && (globalRule.IsBuiltIn || globalRule.IsCommunity))
{
// Built-in/community rule: only persist enabled state per tenant
return await _storageService.StoreRuleStateAsync(tenantId, rule.RuleId, rule.Enabled);
return await _ruleRepo.StoreRuleStateAsync(tenantId, rule.RuleId, rule.Enabled);
}
// Ensure custom rules keep correct flags (the incoming payload may
@@ -103,7 +104,7 @@ namespace AutopilotMonitor.Functions.Services
rule.IsBuiltIn = false;
rule.IsCommunity = false;
rule.UpdatedAt = DateTime.UtcNow;
return await _storageService.StoreGatherRuleAsync(rule, tenantId);
return await _ruleRepo.StoreGatherRuleAsync(rule, tenantId);
}
/// <summary>
@@ -115,10 +116,10 @@ namespace AutopilotMonitor.Functions.Services
{
if (rule.IsBuiltIn || rule.IsCommunity)
{
return await _storageService.DeleteRuleStateAsync(tenantId, rule.RuleId);
return await _ruleRepo.DeleteRuleStateAsync(tenantId, rule.RuleId);
}
return await _storageService.DeleteGatherRuleAsync(tenantId, rule.RuleId);
return await _ruleRepo.DeleteGatherRuleAsync(tenantId, rule.RuleId);
}
/// <summary>
@@ -130,12 +131,12 @@ namespace AutopilotMonitor.Functions.Services
{
_logger.LogInformation("Reseeding built-in gather rules (full re-import)...");
var existingGlobalRules = await _storageService.GetGatherRulesAsync("global");
var existingGlobalRules = await _ruleRepo.GetGatherRulesAsync("global");
var deleted = 0;
foreach (var rule in existingGlobalRules.Where(r => r.IsBuiltIn))
{
await _storageService.DeleteGatherRuleAsync("global", rule.RuleId);
await _ruleRepo.DeleteGatherRuleAsync("global", rule.RuleId);
deleted++;
}
_logger.LogInformation($"Deleted {deleted} old global built-in gather rules");
@@ -143,7 +144,7 @@ namespace AutopilotMonitor.Functions.Services
var builtInRules = BuiltInGatherRules.GetAll();
foreach (var rule in builtInRules)
{
await _storageService.StoreGatherRuleAsync(rule, "global");
await _ruleRepo.StoreGatherRuleAsync(rule, "global");
}
_logger.LogInformation($"Written {builtInRules.Count} built-in gather rules from code");
@@ -160,7 +161,7 @@ namespace AutopilotMonitor.Functions.Services
{
if (_seeded) return;
var existingRules = await _storageService.GetGatherRulesAsync("global");
var existingRules = await _ruleRepo.GetGatherRulesAsync("global");
var builtInRules = BuiltInGatherRules.GetAll();
if (existingRules.Count == 0)
@@ -168,7 +169,7 @@ namespace AutopilotMonitor.Functions.Services
_logger.LogInformation("Seeding built-in gather rules...");
foreach (var rule in builtInRules)
{
await _storageService.StoreGatherRuleAsync(rule, "global");
await _ruleRepo.StoreGatherRuleAsync(rule, "global");
}
_logger.LogInformation($"Seeded {builtInRules.Count} built-in gather rules");
}
@@ -189,14 +190,14 @@ namespace AutopilotMonitor.Functions.Services
|| existing.Trigger != rule.Trigger
|| existing.TriggerPhase != rule.TriggerPhase)
{
await _storageService.StoreGatherRuleAsync(rule, "global");
await _ruleRepo.StoreGatherRuleAsync(rule, "global");
updated++;
}
}
else
{
// New built-in rule added in code
await _storageService.StoreGatherRuleAsync(rule, "global");
await _ruleRepo.StoreGatherRuleAsync(rule, "global");
updated++;
}
}
@@ -1,3 +1,4 @@
using AutopilotMonitor.Shared.DataAccess;
using AutopilotMonitor.Shared.Models;
using Microsoft.Extensions.Logging;
using System.Linq;
@@ -10,13 +11,13 @@ namespace AutopilotMonitor.Functions.Services
/// </summary>
public class ImeLogPatternService
{
private readonly TableStorageService _storageService;
private readonly IRuleRepository _ruleRepo;
private readonly ILogger<ImeLogPatternService> _logger;
private bool _seeded = false;
public ImeLogPatternService(TableStorageService storageService, ILogger<ImeLogPatternService> logger)
public ImeLogPatternService(IRuleRepository ruleRepo, ILogger<ImeLogPatternService> logger)
{
_storageService = storageService;
_ruleRepo = ruleRepo;
_logger = logger;
}
@@ -28,8 +29,8 @@ namespace AutopilotMonitor.Functions.Services
{
await EnsureBuiltInPatternsSeededAsync();
var globalPatterns = await _storageService.GetImeLogPatternsAsync("global");
var tenantPatterns = await _storageService.GetImeLogPatternsAsync(tenantId);
var globalPatterns = await _ruleRepo.GetImeLogPatternsAsync("global");
var tenantPatterns = await _ruleRepo.GetImeLogPatternsAsync(tenantId);
var tenantOverrides = tenantPatterns.ToDictionary(p => p.PatternId, p => p);
@@ -63,8 +64,8 @@ namespace AutopilotMonitor.Functions.Services
{
await EnsureBuiltInPatternsSeededAsync();
var globalPatterns = await _storageService.GetImeLogPatternsAsync("global");
var tenantPatterns = await _storageService.GetImeLogPatternsAsync(tenantId);
var globalPatterns = await _ruleRepo.GetImeLogPatternsAsync("global");
var tenantPatterns = await _ruleRepo.GetImeLogPatternsAsync(tenantId);
var tenantOverrides = tenantPatterns.ToDictionary(p => p.PatternId, p => p);
var mergedPatterns = new List<ImeLogPattern>();
@@ -96,7 +97,7 @@ namespace AutopilotMonitor.Functions.Services
public async Task<bool> CreatePatternAsync(string tenantId, ImeLogPattern pattern)
{
pattern.IsBuiltIn = false;
return await _storageService.StoreImeLogPatternAsync(pattern, tenantId);
return await _ruleRepo.StoreImeLogPatternAsync(pattern, tenantId);
}
/// <summary>
@@ -105,7 +106,7 @@ namespace AutopilotMonitor.Functions.Services
/// </summary>
public async Task<bool> UpdatePatternAsync(string tenantId, ImeLogPattern pattern)
{
return await _storageService.StoreImeLogPatternAsync(pattern, tenantId);
return await _ruleRepo.StoreImeLogPatternAsync(pattern, tenantId);
}
/// <summary>
@@ -115,7 +116,7 @@ namespace AutopilotMonitor.Functions.Services
public async Task<bool> UpdateGlobalPatternAsync(ImeLogPattern pattern)
{
pattern.IsBuiltIn = true;
return await _storageService.StoreImeLogPatternAsync(pattern, "global");
return await _ruleRepo.StoreImeLogPatternAsync(pattern, "global");
}
/// <summary>
@@ -123,7 +124,7 @@ namespace AutopilotMonitor.Functions.Services
/// </summary>
public async Task<bool> DeletePatternAsync(string tenantId, string patternId)
{
return await _storageService.DeleteImeLogPatternAsync(tenantId, patternId);
return await _ruleRepo.DeleteImeLogPatternAsync(tenantId, patternId);
}
/// <summary>
@@ -132,7 +133,7 @@ namespace AutopilotMonitor.Functions.Services
public async Task<bool> DeleteGlobalPatternAsync(string patternId)
{
_seeded = false;
return await _storageService.DeleteImeLogPatternAsync("global", patternId);
return await _ruleRepo.DeleteImeLogPatternAsync("global", patternId);
}
/// <summary>
@@ -143,12 +144,12 @@ namespace AutopilotMonitor.Functions.Services
{
_logger.LogInformation("Reseeding built-in IME log patterns (full re-import)...");
var existingGlobalPatterns = await _storageService.GetImeLogPatternsAsync("global");
var existingGlobalPatterns = await _ruleRepo.GetImeLogPatternsAsync("global");
var deleted = 0;
foreach (var pattern in existingGlobalPatterns.Where(p => p.IsBuiltIn))
{
await _storageService.DeleteImeLogPatternAsync("global", pattern.PatternId);
await _ruleRepo.DeleteImeLogPatternAsync("global", pattern.PatternId);
deleted++;
}
_logger.LogInformation($"Deleted {deleted} old global built-in IME log patterns");
@@ -157,7 +158,7 @@ namespace AutopilotMonitor.Functions.Services
foreach (var pattern in builtInPatterns)
{
pattern.IsBuiltIn = true;
await _storageService.StoreImeLogPatternAsync(pattern, "global");
await _ruleRepo.StoreImeLogPatternAsync(pattern, "global");
}
_logger.LogInformation($"Written {builtInPatterns.Count} built-in IME log patterns from code");
@@ -174,7 +175,7 @@ namespace AutopilotMonitor.Functions.Services
{
if (_seeded) return;
var existingPatterns = await _storageService.GetImeLogPatternsAsync("global");
var existingPatterns = await _ruleRepo.GetImeLogPatternsAsync("global");
var builtInPatterns = BuiltInImeLogPatterns.GetAll();
if (existingPatterns.Count == 0)
@@ -183,7 +184,7 @@ namespace AutopilotMonitor.Functions.Services
foreach (var pattern in builtInPatterns)
{
pattern.IsBuiltIn = true;
await _storageService.StoreImeLogPatternAsync(pattern, "global");
await _ruleRepo.StoreImeLogPatternAsync(pattern, "global");
}
_logger.LogInformation($"Seeded {builtInPatterns.Count} built-in IME log patterns");
}
@@ -200,13 +201,13 @@ namespace AutopilotMonitor.Functions.Services
if (existing.Pattern != pattern.Pattern || existing.Action != pattern.Action
|| existing.Category != pattern.Category || existing.Description != pattern.Description)
{
await _storageService.StoreImeLogPatternAsync(pattern, "global");
await _ruleRepo.StoreImeLogPatternAsync(pattern, "global");
updated++;
}
}
else
{
await _storageService.StoreImeLogPatternAsync(pattern, "global");
await _ruleRepo.StoreImeLogPatternAsync(pattern, "global");
updated++;
}
}