using k8s.Models; using MagMan.Core; using MagMan.Core.DTO; using MagMan.Core.Services; using MagMan.Data.Admin.DbModels; using MagMan.Data.Admin.Services; using MagMan.Data.Tenant.DbModels; using MagMan.Data.Tenant.Services; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using NLog; using System.Linq; namespace MagMan.UI.Controllers { [Route("api/[controller]")] [ApiController] public class ResourcesController : ControllerBase { #region Public Constructors public ResourcesController(MTAdminService MTDataService, TenantService TDataService, MessageService messageService) { MTAdmService = MTDataService; TService = TDataService; MService = messageService; // json serializer... FIX errore loop circolare https://www.ryadel.com/en/jsonserializationexception-self-referencing-loop-detected-error-fix-entity-framework-asp-net-core/ JSSettings = new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }; Log.Info("Avviata classe ResourcesController"); } #endregion Public Constructors #region Public Methods /// /// Controllo status Alive /// GET: api/Resources/alive /// /// [HttpGet("alive")] public string alive() { //Log.Debug("Chiamata alive"); return $"OK"; } /// /// Processa una chiamata POST per la verifica di un oggetto di TRACKING risorse progetto (RestPayload.Resources) /// PUT: api/Resources/check/00000000-0000-0000-0000-000000000000 /// /// token comunicazione /// /// restituisce diversi valori secondo esito: ND/EQUAL/CHANGED, dove | ND = non definito / /// non calcolato | EQUAL = il set inviato èidentico all'ultimo registrato (in termini di /// numero barre impiegate complessivo e per singolo tipo, check da CloudId barre) | CHANGED /// = il set inviato è differente (per tipo/numero/mix di barre) /// [HttpPost("check/{id}")] public async Task check(string id, [FromBody] RestPayload.Resources projectData) { string answ = "ND"; bool isEqual = false; // verifico ci sia valore if (!string.IsNullOrEmpty(id) && projectData != null) { // in primis recupero codice chiave da token... int nKey = await MTAdmService.MainKeyByToken(id); if (nKey > 0) { // nel projData ho le info x gestire aggiornamento PER INTERO int ProjCloudId = projectData.ProjCloudId; // proseguo solo se ho un Id valido if (ProjCloudId > 0) { // inizio dal num risorse DTO... se vuoto è sempre FALSE int numResDTO = 0; if (projectData.ResourceList == null || projectData.ResourceList.Count == 0) { // confermo che NON corrisponde isEqual = false; } else { numResDTO = projectData.ResourceList.Count; // recupero ultimo set ricevuto... var lastRecPlan = TService.ReqPlanGetLast(nKey, ProjCloudId, Enums.ProjResState.Estimated); // se non corrisponde ProjId --> false if (lastRecPlan == null || lastRecPlan.ProjDbId != ProjCloudId) { // confermo che NON corrisponde isEqual = false; } // altrimenti verifico contenuto come barre else { // ora recupero risorse associate alla registrazione ricevuta... var lastResList = await TService.ResourcesGetByProject(nKey, ProjCloudId, true, false); // se lista vuota if (lastResList == null || lastResList.Count == 0) { // confermo che NON corrisponde isEqual = false; } else { //...o se num tot != numResDto --> false if (lastResList.Count != numResDTO) { // confermo che NON corrisponde isEqual = false; } else { // altrimenti check CloudId barre + quantità x equality... // inizio convertendo List listRes = projectData.ResourceList.Select(x => TService.ResourceFromDto(x, lastRecPlan.RequestId)).ToList(); // dato x scontato che ho stesso numero di barre --> // confronto 1-1 per quantità... genero i 2 set Dictionary list2check = projectData.ResourceList.ToDictionary(x => x.RawItemCloudId, x => x.Qty); Dictionary listSaved = lastResList.ToDictionary(x => x.RawItemId, x => x.Qty); // comparazione finale! isEqual = DictComparer(list2check, listSaved); //isEqual= list2check.Count == listSaved.Count && !list2check.Except(listSaved).Any(); } } } } } } answ = isEqual ? "EQUAL" : "CHANGED"; } return answ; } // GET api/Resources/5 [HttpGet] public async Task> Get() { // se non ho chiave --> vuoto! List ListRecords = new List(); await Task.Delay(100); return ListRecords; } /// /// Elenco Macchine dato RestToken /// /// Rest Token cliente /// ID progetto /// true = ultima stima attiva / false = consumi effettivi /// // GET api/Resources/2cba60c7-7be4-40b1-aa0d-52e7c71fc1a7 [HttpGet("{id}")] public async Task> Get(string id, int projDbId, bool isEstim) { List ListRecords = new List(); // verifico ci sia valore if (!string.IsNullOrEmpty(id)) { // in primis recupero codice chiave da token... int nKey = await MTAdmService.MainKeyByToken(id); //ListRecords = await TService.ResourcesGetByProject(nKey, projDbId, isEstim, false); ListRecords = await TService.ResourcesExpGetByProject(nKey, projDbId, isEstim, false); } return ListRecords; } /// /// Processa una chiamata POST per l'invio di un oggetto di TRACKING risorse progetto (RestPayload.Resources) /// PUT: api/Resources/track/00000000-0000-0000-0000-000000000000 /// /// token comunicazione /// [HttpPost("track/{id}")] public async Task track(string id, [FromBody] RestPayload.Resources projectData) { string answ = "ND"; bool fatto = false; // verifico ci sia valore if (!string.IsNullOrEmpty(id) && projectData != null) { // in primis recupero codice chiave da token... int nKey = await MTAdmService.MainKeyByToken(id); if (nKey > 0) { // nel projData ho le info x gestire aggiornamento PER INTERO int ProjCloudId = projectData.ProjCloudId; // proseguo solo se ho un Id valido if (ProjCloudId > 0) { // recupero info del progetto con cui registrare le note var projRec = await TService.ProjectGetById(nKey, ProjCloudId); // in primis registro il record RequestPlan... var recPlan = new RequestPlanModel() { DtRequest = projectData.DtReq, IsActive = true, ReqState = projectData.ReqState, ProjDbId = ProjCloudId }; // registro richiesta prima dei movimenti... int RequestPlanId = await TService.ReqPlanUpdate(nKey, recPlan); // per ogni riga risorsa registro le info relative... if (projectData.ResourceList != null) { List listRes = projectData.ResourceList.Select(x => TService.ResourceFromDto(x, RequestPlanId)).ToList(); try { string prDesc = $"K{nKey}"; if (projRec != null) { prDesc += $" | P.{ProjCloudId} | {projRec.ProjDescription} ({projRec.Machine})"; } // rivedere SIA consumi che gestione stime... await TService.ResourceUpdate(nKey, RequestPlanId, projectData.ResourceList, projectData.ReqState, prDesc); fatto = true; } catch (Exception exc) { Log.Error($"ResourceController.upsert | Errore in fase salvataggio ResourceDto{Environment.NewLine}{exc}"); fatto = false; } } // resetto cache redis await MTAdmService.FlushRedisCache(); // broadcast update via redis, indico nKey + projCloudIdx update puntuale MService.QueUpdRes.sendMessage($"{nKey}|{ProjCloudId}"); // broadcast update via redis, indico nKey x update puntuale MService.QueUpdProj.sendMessage($"{nKey}"); } } } answ = fatto ? "OK" : "NO"; return answ; } #endregion Public Methods #region Private Fields private static JsonSerializerSettings? JSSettings; /// /// Classe per logging /// private static NLog.Logger Log = LogManager.GetCurrentClassLogger(); #endregion Private Fields #region Private Properties private MessageService MService { get; set; } = null!; private MTAdminService MTAdmService { get; set; } = null!; private TenantService TService { get; set; } = null!; #endregion Private Properties #region Private Methods /// /// Utility method comparatore dizionari /// /// /// /// private bool DictComparer(Dictionary dict1, Dictionary dict2) { // Test for equality. bool isEqual = false; if (dict1.Count == dict2.Count) // Require isEqual count. { isEqual = true; foreach (var pair in dict1) { int value; if (dict2.TryGetValue(pair.Key, out value)) { // Require value be isEqual. if (value != pair.Value) { isEqual = false; break; } } else { // Require key be present. isEqual = false; break; } } } return isEqual; } #endregion Private Methods } }