using System.Text; using System.Text.Json; using MesaFabApproval.Shared.Models; using Microsoft.Extensions.Caching.Memory; namespace MesaFabApproval.Client.Services; public interface IApprovalService { Task GetRoleIdForRoleName(string roleName); Task> GetSubRolesForSubRoleName(string subRoleName, int roleId); Task> GetApprovalGroupMembers(int subRoleId); Task CreateApproval(Approval approval); Task UpdateApproval(Approval approval); Task Approve(Approval approval); Task Deny(Approval approval); Task> GetApprovalsForIssueId(int issueId, bool bypassCache); Task> GetApprovalsForUserId(int userId, bool bypassCache); } public class ApprovalService : IApprovalService { private readonly IMemoryCache _cache; private readonly IHttpClientFactory _httpClientFactory; public ApprovalService(IMemoryCache cache, IHttpClientFactory httpClientFactory) { _cache = cache ?? throw new ArgumentNullException("IMemoryCache not injected"); _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException("IHttpClientFactory not injected"); } public async Task CreateApproval(Approval approval) { if (approval is null) throw new ArgumentNullException("approval cannot be null"); HttpClient httpClient = _httpClientFactory.CreateClient("API"); HttpRequestMessage requestMessage = new(HttpMethod.Post, "approval"); requestMessage.Content = new StringContent(JsonSerializer.Serialize(approval), Encoding.UTF8, "application/json"); HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); if (!responseMessage.IsSuccessStatusCode) { throw new Exception($"Unable to create approval, because {responseMessage.ReasonPhrase}"); } await GetApprovalsForIssueId(approval.IssueID, true); await GetApprovalsForUserId(approval.UserID, true); } public async Task> GetApprovalsForIssueId(int issueId, bool bypassCache) { if (issueId <= 0) throw new ArgumentException($"{issueId} is not a valid issue ID"); IEnumerable? approvals = null; if (!bypassCache) approvals = _cache.Get>($"approvals{issueId}"); if (approvals is null) { HttpClient httpClient = _httpClientFactory.CreateClient("API"); HttpRequestMessage requestMessage = new(HttpMethod.Get, $"approval/issue?issueId={issueId}&bypassCache={bypassCache}"); HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); if (responseMessage.IsSuccessStatusCode) { string responseContent = await responseMessage.Content.ReadAsStringAsync(); JsonSerializerOptions jsonSerializerOptions = new() { PropertyNameCaseInsensitive = true }; approvals = JsonSerializer.Deserialize>(responseContent, jsonSerializerOptions) ?? throw new Exception("Unable to parse approvals from API response"); _cache.Set($"approvals{issueId}", approvals, DateTimeOffset.Now.AddMinutes(15)); } else { throw new Exception($"Unable to get approvals, because {responseMessage.ReasonPhrase}"); } } foreach (Approval approval in approvals) { if (approval.ItemStatus < 0) approval.StatusMessage = "Denied"; if (approval.ItemStatus == 0) approval.StatusMessage = "Assigned"; if (approval.ItemStatus > 0) approval.StatusMessage = "Approved"; } return approvals; } public async Task> GetApprovalsForUserId(int userId, bool bypassCache) { if (userId <= 0) throw new ArgumentException($"{userId} is not a valid user ID"); IEnumerable? approvals = null; if (!bypassCache) approvals = _cache.Get>($"approvals{userId}"); if (approvals is null) { HttpClient httpClient = _httpClientFactory.CreateClient("API"); HttpRequestMessage requestMessage = new(HttpMethod.Get, $"approval/user?userId={userId}&bypassCache={bypassCache}"); HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); if (responseMessage.IsSuccessStatusCode) { string responseContent = await responseMessage.Content.ReadAsStringAsync(); JsonSerializerOptions jsonSerializerOptions = new() { PropertyNameCaseInsensitive = true }; approvals = JsonSerializer.Deserialize>(responseContent, jsonSerializerOptions) ?? throw new Exception("Unable to parse approvals from API response"); _cache.Set($"approvals{userId}", approvals, DateTimeOffset.Now.AddMinutes(15)); } else { throw new Exception($"Unable to get approvals, because {responseMessage.ReasonPhrase}"); } } foreach (Approval approval in approvals) { if (approval.ItemStatus < 0) approval.StatusMessage = "Denied"; if (approval.ItemStatus == 0) approval.StatusMessage = "Assigned"; if (approval.ItemStatus > 0) approval.StatusMessage = "Approved"; } return approvals; } public async Task UpdateApproval(Approval approval) { if (approval is null) throw new ArgumentNullException("approval cannot be null"); HttpClient httpClient = _httpClientFactory.CreateClient("API"); HttpRequestMessage requestMessage = new(HttpMethod.Put, "approval"); requestMessage.Content = new StringContent(JsonSerializer.Serialize(approval), Encoding.UTF8, "application/json"); HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); if (!responseMessage.IsSuccessStatusCode) { throw new Exception($"Unable to update approval, because {responseMessage.ReasonPhrase}"); } await GetApprovalsForIssueId(approval.IssueID, true); await GetApprovalsForUserId(approval.UserID, true); } public async Task Approve(Approval approval) { if (approval is null) throw new ArgumentNullException("approval cannot be null"); HttpClient httpClient = _httpClientFactory.CreateClient("API"); HttpRequestMessage requestMessage = new(HttpMethod.Put, "approval/approve"); requestMessage.Content = new StringContent(JsonSerializer.Serialize(approval), Encoding.UTF8, "application/json"); HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); if (!responseMessage.IsSuccessStatusCode) { throw new Exception($"Approval failed, because {responseMessage.ReasonPhrase}"); } await GetApprovalsForIssueId(approval.IssueID, true); await GetApprovalsForUserId(approval.UserID, true); } public async Task Deny(Approval approval) { if (approval is null) throw new ArgumentNullException("approval cannot be null"); HttpClient httpClient = _httpClientFactory.CreateClient("API"); HttpRequestMessage requestMessage = new(HttpMethod.Put, "approval/deny"); requestMessage.Content = new StringContent(JsonSerializer.Serialize(approval), Encoding.UTF8, "application/json"); HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); if (!responseMessage.IsSuccessStatusCode) { throw new Exception($"Denial failed, because {responseMessage.ReasonPhrase}"); } } public async Task GetRoleIdForRoleName(string roleName) { if (string.IsNullOrWhiteSpace(roleName)) throw new ArgumentException("role name cannot be null or empty"); int roleId = _cache.Get($"roleId{roleName}"); if (roleId <= 0) { HttpClient httpClient = _httpClientFactory.CreateClient("API"); HttpRequestMessage requestMessage = new(HttpMethod.Get, $"approval/roleId?roleName={roleName}"); HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); if (responseMessage.IsSuccessStatusCode) { string responseContent = await responseMessage.Content.ReadAsStringAsync(); JsonSerializerOptions jsonSerializerOptions = new() { PropertyNameCaseInsensitive = true }; roleId = JsonSerializer.Deserialize(responseContent, jsonSerializerOptions); if (roleId <= 0) throw new Exception($"unable to find role ID for {roleName}"); _cache.Set($"roleId{roleName}", roleId, DateTimeOffset.Now.AddMinutes(15)); } else { throw new Exception($"Unable to get role ID, because {responseMessage.ReasonPhrase}"); } } return roleId; } public async Task> GetSubRolesForSubRoleName(string subRoleName, int roleId) { if (string.IsNullOrWhiteSpace(subRoleName)) throw new ArgumentException("role name cannot be null or empty"); if (roleId <= 0) throw new ArgumentException($"{roleId} is not a valid role ID"); IEnumerable? subRoles = _cache.Get>($"subRoles{subRoleName}"); if (subRoles is null || subRoles.Count() <= 0) { HttpClient httpClient = _httpClientFactory.CreateClient("API"); HttpRequestMessage requestMessage = new(HttpMethod.Get, $"approval/subRoles?subRoleName={subRoleName}&roleId={roleId}"); HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); if (responseMessage.IsSuccessStatusCode) { string responseContent = await responseMessage.Content.ReadAsStringAsync(); JsonSerializerOptions jsonSerializerOptions = new() { PropertyNameCaseInsensitive = true }; subRoles = JsonSerializer.Deserialize>(responseContent, jsonSerializerOptions) ?? throw new Exception("Unable to parse sub roles from API response"); if (subRoles is not null && subRoles.Count() > 0) { _cache.Set($"subRoles{subRoleName}", subRoles, DateTimeOffset.Now.AddMinutes(15)); } else { throw new Exception($"unable to find sub roles for {subRoleName}"); } } else { throw new Exception($"Unable to get sub roles, because {responseMessage.ReasonPhrase}"); } } return subRoles; } public async Task> GetApprovalGroupMembers(int subRoleId) { if (subRoleId <= 0) throw new ArgumentException($"{subRoleId} is not a valid sub role ID"); IEnumerable? members = _cache.Get>($"approvalMembers{subRoleId}"); if (members is null) { HttpClient httpClient = _httpClientFactory.CreateClient("API"); HttpRequestMessage requestMessage = new(HttpMethod.Get, $"approval/members?subRoleId={subRoleId}"); HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage); if (responseMessage.IsSuccessStatusCode) { string responseContent = await responseMessage.Content.ReadAsStringAsync(); JsonSerializerOptions jsonSerializerOptions = new() { PropertyNameCaseInsensitive = true }; members = JsonSerializer.Deserialize>(responseContent, jsonSerializerOptions) ?? throw new Exception("Unable to parse users from API response"); if (members is null || members.Count() <= 0) throw new Exception($"unable to find group members for sub role {subRoleId}"); _cache.Set($"approvalMembers{subRoleId}", members, DateTimeOffset.Now.AddMinutes(15)); } else { throw new Exception($"Unable to get group members, because {responseMessage.ReasonPhrase}"); } } return members; } }