diff --git a/Core/Core.csproj b/Core/Core.csproj index dbc1517..f208d30 100644 --- a/Core/Core.csproj +++ b/Core/Core.csproj @@ -1,7 +1,7 @@ - net6.0 + net5.0 diff --git a/Core/SampleStats.cs b/Core/SampleStats.cs new file mode 100644 index 0000000..236b7e7 --- /dev/null +++ b/Core/SampleStats.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Core +{ + public class SampleStats + { + public string Name { get; set; } = "NA"; + public DateTime DtFirst { get; set; } = DateTime.Now; + public DateTime DtLast { get; set; } = DateTime.Now; + public List VList { get; set; } = new List(); + } +} diff --git a/Core/SupportRequest.cs b/Core/SupportRequest.cs index 1582ace..cab22a3 100644 --- a/Core/SupportRequest.cs +++ b/Core/SupportRequest.cs @@ -14,6 +14,7 @@ namespace Core public string CodImp { get; set; } = ""; public string CodInst { get; set; } = ""; public string ContactEmail { get; set; } = ""; + public string ContactName { get; set; } = ""; public string ContactPhone { get; set; } = ""; public int idxSubLic { get; set; } = 0; diff --git a/LiMan.Api/Controllers/ApplicazioneController.cs b/LiMan.Api/Controllers/ApplicazioneController.cs index fd1d71c..3d3c86e 100644 --- a/LiMan.Api/Controllers/ApplicazioneController.cs +++ b/LiMan.Api/Controllers/ApplicazioneController.cs @@ -33,7 +33,7 @@ namespace LiMan.APi.Controllers /// public ApplicazioneController(ApiDataService DataService) { - _DataService = DataService; + dataService = DataService; Log.Info("Avviata classe ApplicazioneController"); } @@ -44,7 +44,7 @@ namespace LiMan.APi.Controllers /// /// Dataservice x accesso DB /// - protected ApiDataService _DataService { get; set; } + protected ApiDataService dataService { get; set; } #endregion Protected Properties @@ -60,7 +60,8 @@ namespace LiMan.APi.Controllers [HttpGet("{id}")] public async Task> Get(string id, string CodApp) { - var result = await _DataService.ApplicativiSearch(id, CodApp, true); + var result = await dataService.ApplicativiSearch(id, CodApp, true); + await dataService.recordCall(id, CodApp, $"GET:api/applicazione"); return result; } diff --git a/LiMan.Api/Controllers/AttivazioniController.cs b/LiMan.Api/Controllers/AttivazioniController.cs index 124307f..a349357 100644 --- a/LiMan.Api/Controllers/AttivazioniController.cs +++ b/LiMan.Api/Controllers/AttivazioniController.cs @@ -34,7 +34,7 @@ namespace LiMan.APi.Controllers /// public AttivazioniController(ApiDataService DataService) { - _DataService = DataService; + dataService = DataService; Log.Info("Avviata classe AttivazioniController"); } @@ -45,7 +45,7 @@ namespace LiMan.APi.Controllers /// /// Dataservice x accesso DB /// - protected ApiDataService _DataService { get; set; } + protected ApiDataService dataService { get; set; } #endregion Protected Properties @@ -58,7 +58,13 @@ namespace LiMan.APi.Controllers [HttpDelete()] public async Task Delete([FromBody] UserLicenseRequest CurrRequest) { - bool done = await _DataService.AttivazioniDelete(CurrRequest.MasterKey, CurrRequest.ParamDict); + bool done = await dataService.AttivazioniDelete(CurrRequest.MasterKey, CurrRequest.ParamDict); + // se ho qualcosa da loggare... + foreach (var item in CurrRequest.ParamDict) + { + // registro 1 riga x ogni record... + await dataService.recordCall(CurrRequest.MasterKey, $"DELETE:api/attivazioni:{item.Key}|{item.Value}"); + } return done; } @@ -72,8 +78,9 @@ namespace LiMan.APi.Controllers public async Task> Get(string chiave) { List result = new List(); - var dbResult = await _DataService.AttivazioniByMasterKey(chiave, false); + var dbResult = await dataService.AttivazioniByMasterKey(chiave, false); result = (dbResult != null) ? dbResult : result; + await dataService.recordCall(chiave, $"GET:api/attivazioni:{chiave}"); return result; } @@ -88,9 +95,14 @@ namespace LiMan.APi.Controllers List currData = new List(); // eseguo tentativo generazione attivazioni da licenza... - bool done = await _DataService.AttivazioniTryAdd(CurrRequest.MasterKey, CurrRequest.ParamDict, 60); - currData = await _DataService.AttivazioniByMasterKey(CurrRequest.MasterKey, false); - + bool done = await dataService.AttivazioniTryAdd(CurrRequest.MasterKey, CurrRequest.ParamDict, 60); + currData = await dataService.AttivazioniByMasterKey(CurrRequest.MasterKey, false); + // se ho qualcosa da loggare... + foreach (var item in CurrRequest.ParamDict) + { + // registro 1 riga x ogni record... + await dataService.recordCall(CurrRequest.MasterKey, $"POST:api/attivazioni:{item.Key}|{item.Value}"); + } return currData; } @@ -98,16 +110,21 @@ namespace LiMan.APi.Controllers /// Richiesta di refresh delle key associate ai CodImpiego da una lista di chiavi di licenza sub /// /// Obj Richiesta con licenza MASTER + Elenco codici impiego (key) + valori in formato dizionari - // POST api/attivazioni + // POST api/attivazioni/refreshKey [HttpPost("refreshKey")] public async Task> refreshKey([FromBody] UserLicenseRequest CurrRequest) { List currData = new List(); // eseguo tentativo generazione attivazioni da licenza... - bool done = await _DataService.AttivazioniTryRefresh(CurrRequest.MasterKey, CurrRequest.ParamDict); - currData = await _DataService.AttivazioniByMasterKey(CurrRequest.MasterKey, false); - + bool done = await dataService.AttivazioniTryRefresh(CurrRequest.MasterKey, CurrRequest.ParamDict); + currData = await dataService.AttivazioniByMasterKey(CurrRequest.MasterKey, false); + // se ho qualcosa da loggare... + foreach (var item in CurrRequest.ParamDict) + { + // registro 1 riga x ogni record... + await dataService.recordCall(CurrRequest.MasterKey, $"POST:api/attivazioni/refreshKey:{item.Key}__{item.Value}"); + } return currData; } @@ -115,11 +132,12 @@ namespace LiMan.APi.Controllers /// Eliminazione di TUTTE le attivazioni SCADUTE /// /// Licenza MASTER - // DELETE api/attivazioni/5 + // DELETE api/attivazioni/resetAvail [HttpDelete("resetAvail")] public async Task ResetAvail(string chiave) { - bool done = await _DataService.AttivazioniResetAvail(chiave); + bool done = await dataService.AttivazioniResetAvail(chiave); + await dataService.recordCall(chiave, $"DELETE:api/attivazioni/resetAvail:{chiave}"); return done; } @@ -127,27 +145,19 @@ namespace LiMan.APi.Controllers /// Verifica recupero un record di sub licenza /// /// Licenza MASTER - /// Codice univoco impiego licenza + /// Codice univoco impiego licenza /// // GET api/attivazioni/verifica/5 [HttpGet("verifica")] - public async Task VerificaImpiego(string chiave, string CodImpiego) + public async Task VerificaImpiego(string chiave, string codImpiego) { DB.DTO.AttivazioneDTO result = new DB.DTO.AttivazioneDTO(); - var dbResult = await _DataService.AttivazioneSearch(chiave, CodImpiego, false); + var dbResult = await dataService.AttivazioneSearch(chiave, codImpiego, false); result = (dbResult != null) ? dbResult : result; + await dataService.recordCall(chiave, $"GET:api/attivazioni/verifica:{chiave}__{codImpiego}"); return result; } #endregion Public Methods - -#if false - // PUT api/attivazioni/5 - [HttpPut("{id}")] - public void Put(int id, [FromBody] string value) - { - } - -#endif } } \ No newline at end of file diff --git a/LiMan.Api/Controllers/InstallazioniController.cs b/LiMan.Api/Controllers/InstallazioniController.cs index 5cd7312..46c8c08 100644 --- a/LiMan.Api/Controllers/InstallazioniController.cs +++ b/LiMan.Api/Controllers/InstallazioniController.cs @@ -33,7 +33,7 @@ namespace LiMan.APi.Controllers /// public InstallazioniController(ApiDataService DataService) { - _DataService = DataService; + dataService = DataService; Log.Info("Avviata classe InstallazioniController"); } @@ -44,7 +44,7 @@ namespace LiMan.APi.Controllers /// /// Dataservice x accesso DB /// - protected ApiDataService _DataService { get; set; } + protected ApiDataService dataService { get; set; } #endregion Protected Properties @@ -59,9 +59,9 @@ namespace LiMan.APi.Controllers [HttpGet("{id}")] public async Task> Get(string id) { - var result = await _DataService.LicenzeByCliente(id); + var result = await dataService.LicenzeByCliente(id); var listaApp = result.Select(x => x.CodApp).ToList(); - + await dataService.recordCall(id, "*", "GET:api/installazioni"); return listaApp; } diff --git a/LiMan.Api/Controllers/LicenzaController.cs b/LiMan.Api/Controllers/LicenzaController.cs index bb7ba4e..f86e8f6 100644 --- a/LiMan.Api/Controllers/LicenzaController.cs +++ b/LiMan.Api/Controllers/LicenzaController.cs @@ -34,7 +34,7 @@ namespace LiMan.APi.Controllers /// public LicenzaController(ApiDataService DataService) { - _DataService = DataService; + dataService = DataService; Log.Info("Avviata classe LicenzaController"); } @@ -45,7 +45,7 @@ namespace LiMan.APi.Controllers /// /// Dataservice x accesso DB /// - protected ApiDataService _DataService { get; set; } + protected ApiDataService dataService { get; set; } #endregion Protected Properties @@ -62,8 +62,8 @@ namespace LiMan.APi.Controllers [HttpGet("{id}")] public async Task> Get(string id, string CodApp, string Chiave) { - var result = await _DataService.LicenzeSearch(id, CodApp, Chiave, false); - + var result = await dataService.LicenzeSearch(id, CodApp, Chiave, false); + await dataService.recordCall(id, CodApp, $"GET:api/licenza:{Chiave}"); return result; } @@ -76,20 +76,21 @@ namespace LiMan.APi.Controllers [HttpPost()] public async Task> Get([FromBody] LicenseCoord AppInfo) { - var result = await _DataService.LicenzeSearch(AppInfo.CodInst, AppInfo.CodApp, AppInfo.MasterKey, false); - + var result = await dataService.LicenzeSearch(AppInfo.CodInst, AppInfo.CodApp, AppInfo.MasterKey, false); + await dataService.recordCall(AppInfo.CodInst, AppInfo.CodApp, $"POST:api/licenza:{AppInfo.MasterKey}"); return result; } + /// POST api/licenza/refreshPayload /// /// Effettua refresh del payload calcolato ed aggiorna record ed infine lo restituisce /// /// Info licenza in formato LicenseCoord - // POST api/attivazioni/refreshPayload [HttpPost("refreshPayload")] public async Task RefreshPayload([FromBody] LicenseCoord AppInfo) { - var done = await _DataService.LicenzaRefreshPayload(AppInfo); + var done = await dataService.LicenzaRefreshPayload(AppInfo); + await dataService.recordCall(AppInfo.CodInst, AppInfo.CodApp, $"POST:api/licenza/refreshPayload:{AppInfo.MasterKey}"); return done; } diff --git a/LiMan.Api/Controllers/TicketController.cs b/LiMan.Api/Controllers/TicketController.cs index aa50816..2c41eae 100644 --- a/LiMan.Api/Controllers/TicketController.cs +++ b/LiMan.Api/Controllers/TicketController.cs @@ -34,7 +34,7 @@ namespace LiMan.APi.Controllers /// public TicketController(ApiDataService DataService) { - _DataService = DataService; + dataService = DataService; Log.Info("Avviata classe TicketController"); } @@ -45,7 +45,7 @@ namespace LiMan.APi.Controllers /// /// Dataservice x accesso DB /// - protected ApiDataService _DataService { get; set; } + protected ApiDataService dataService { get; set; } #endregion Protected Properties @@ -62,8 +62,8 @@ namespace LiMan.APi.Controllers [HttpGet("{id}")] public async Task> Get(string id, string CodApp, string Chiave) { - var result = await _DataService.TicketByCliente(id, CodApp, Chiave); - + var result = await dataService.TicketByCliente(id, CodApp, Chiave); + await dataService.recordCall(id, CodApp, $"GET:api/ticket:{Chiave}"); return result; } @@ -80,11 +80,11 @@ namespace LiMan.APi.Controllers if (CurrRequest.IsValid) { // registro richiesta - var insRes = await _DataService.TicketAdd(CurrRequest); + var insRes = await dataService.TicketAdd(CurrRequest); } // restituisco richieste aperte - result = await _DataService.TicketByCliente(CurrRequest.CodInst, CurrRequest.CodApp, CurrRequest.MasterKey); - + result = await dataService.TicketByCliente(CurrRequest.CodInst, CurrRequest.CodApp, CurrRequest.MasterKey); + await dataService.recordCall(CurrRequest.CodInst, CurrRequest.CodApp, $"POST:api/ticket/sendReq:{CurrRequest.MasterKey}"); return result; } diff --git a/LiMan.Api/Data/ApiDataService.cs b/LiMan.Api/Data/ApiDataService.cs index 05274d4..24278a7 100644 --- a/LiMan.Api/Data/ApiDataService.cs +++ b/LiMan.Api/Data/ApiDataService.cs @@ -1,13 +1,19 @@ using Core; +using LiMan.DB.DBModels; +using Microsoft.AspNetCore.Identity.UI.Services; +using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; +using Newtonsoft.Json; using NLog; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Text; using System.Threading.Tasks; using static LiMan.DB.Enum; +using StackExchange.Redis.Extensions.Core.Abstractions; namespace LiMan.APi.Data { @@ -16,21 +22,57 @@ namespace LiMan.APi.Data /// public class ApiDataService : IDisposable { + #region Public Fields + + /// + /// Classe Accesso metodi DB + /// + public static LiMan.DB.Controllers.DbController dbController; + + #endregion Public Fields + + #region Protected Fields + + /// + /// TTL da 1 h x cache Redis + /// + protected const int hourTTL = 60 * 60; + + /// + /// Chiave redis x statistiche in acquisizione + /// + protected const string rKeySampleStats = "LiMan.UI:SampleStats:Curr"; + + /// + /// Chiave redis x statistiche in acquisizione + /// + protected const string rKeySampleVars = "LiMan.UI:SampleStats:Vars"; + + #endregion Protected Fields + #region Private Fields private static IConfiguration _configuration; private static ILogger _logger; - private static NLog.Logger Log = LogManager.GetCurrentClassLogger(); + private readonly IEmailSender _emailSender; + + //private readonly IDistributedCache distributedCache; + private readonly IRedisCacheClient _redisCacheClient; + + /// + /// Durata assoluta massima della cache IN SECONDI + /// + private int chAbsExp = 60 * 5; + + /// + /// Durata della cache IN SECONDI in modalità inattiva (non acceduta) prima di venire rimossa + /// NON estende oltre il tempo massimo di validità della cache (chAbsExp) + /// + private int chSliExp = 60 * 2; #endregion Private Fields - #region Public Fields - - public static LiMan.DB.Controllers.DbController dbController; - - #endregion Public Fields - #region Public Constructors /// @@ -38,10 +80,18 @@ namespace LiMan.APi.Data /// /// /// - public ApiDataService(IConfiguration configuration, ILogger logger) + /// + /// + /// + public ApiDataService(IConfiguration configuration, ILogger logger, IEmailSender emailSender, IRedisCacheClient redisCacheClient) + //public ApiDataService(IConfiguration configuration, ILogger logger, IDistributedCache distributedCache, IEmailSender emailSender, IRedisCacheClient redisCacheClient) { _logger = logger; _configuration = configuration; + _emailSender = emailSender; + _redisCacheClient = redisCacheClient; + //this.distributedCache = distributedCache; + // conf DB string connStrDB = _configuration.GetConnectionString("LiMan.DB"); if (string.IsNullOrEmpty(connStrDB)) @@ -57,24 +107,6 @@ namespace LiMan.APi.Data #endregion Public Constructors - #region Internal Methods - - /// - /// Effettua refresh del payload della licenza dato info + enigma generato dal client - /// - /// - /// - internal async Task LicenzaRefreshPayload(LicenseCoord appInfo) - { - // chiamo metodo x ricalcolare payload dato enigma - bool done = await dbController.LicenseUpdatePayload(appInfo.CodInst, appInfo.CodApp, appInfo.MasterKey, appInfo.Enigma); - // ora recupero i dati - var licList = await LicenzeSearch(appInfo.CodInst, appInfo.CodApp, appInfo.MasterKey, false); - return licList.FirstOrDefault(); - } - - #endregion Internal Methods - #region Public Methods /// @@ -269,6 +301,71 @@ namespace LiMan.APi.Data dbController.Dispose(); } + /// + /// Elenco licenze dato cliente + /// + /// Chiave Licenza x ricerca + /// + public async Task LicenzaByMasterKey(string chiave) + { + LicenzaModel dbResult = new LicenzaModel(); + string cacheKey = $"DATA:Licenze:ListByKey:{chiave}"; +#if false + string rawData; + var redisDataList = await distributedCache.GetAsync(cacheKey); + if (redisDataList != null) + { + rawData = Encoding.UTF8.GetString(redisDataList); + dbResult = JsonConvert.DeserializeObject(rawData); + } + else + { + Stopwatch stopWatch = new Stopwatch(); + stopWatch.Start(); + dbResult = dbController.LicenzaByKey(chiave); + rawData = JsonConvert.SerializeObject(dbResult); + redisDataList = Encoding.UTF8.GetBytes(rawData); + await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt(5)); + stopWatch.Stop(); + TimeSpan ts = stopWatch.Elapsed; + Log.Trace($"Effettuata lettura da DB per LicenzaByMasterKey: {ts.TotalMilliseconds} ms"); + } +#endif + + string rawData = await getRSV(cacheKey); + if (!string.IsNullOrEmpty(rawData)) + { + dbResult = JsonConvert.DeserializeObject(rawData); + } + else + { + Stopwatch stopWatch = new Stopwatch(); + stopWatch.Start(); + dbResult = dbController.LicenzaByKey(chiave); + rawData = JsonConvert.SerializeObject(dbResult); + await setRSV(cacheKey, rawData, hourTTL); + stopWatch.Stop(); + TimeSpan ts = stopWatch.Elapsed; + Log.Trace($"Effettuata lettura da DB per LicenzaByMasterKey: {ts.TotalMilliseconds} ms"); + } + + return await Task.FromResult(dbResult); + } + + /// + /// Effettua refresh del payload della licenza dato info + enigma generato dal client + /// + /// + /// + public async Task LicenzaRefreshPayload(LicenseCoord appInfo) + { + // chiamo metodo x ricalcolare payload dato enigma + bool done = await dbController.LicenseUpdatePayload(appInfo.CodInst, appInfo.CodApp, appInfo.MasterKey, appInfo.Enigma); + // ora recupero i dati + var licList = await LicenzeSearch(appInfo.CodInst, appInfo.CodApp, appInfo.MasterKey, false); + return licList.FirstOrDefault(); + } + /// /// Elenco licenze dato cliente /// @@ -310,6 +407,101 @@ namespace LiMan.APi.Data return await Task.FromResult(dbResult); } + /// + /// Effettua registrazione chiamata verificando se vada messa sul DB o in redis... + /// + /// + /// + /// + public async Task recordCall(string codInst, string codApp, string targetUrl) + { + bool fatto = false; + + // in primis recupero statistiche (e nel mentre eventualmente salvo su DB) + SampleStats currStats = await getCurrStats(); + + // preparo chiave x dato da loggare + string currKey = $"{rKeySampleVars}:{codInst}:{codApp}:{targetUrl}"; + + // verifico presenza contatore corrente altrimenti aggiungo e salvo... + if (!currStats.VList.Contains(currKey)) + { + currStats.VList.Add(currKey); + // salvo! + await setCurrStats(currStats); + } + // incremento valore contatore corrente + await redCountIncr(currKey); + + return fatto; + } + + /// + /// Effettua registrazione da codice chiave... + /// + /// + /// + public async Task recordCall(string chiave, string targetUrl) + { + // valutare se cache key --> lic... + var currLic = await LicenzaByMasterKey(chiave); + var fatto = await recordCall(currLic.CodInst, currLic.CodApp, targetUrl); + return fatto; + } + + /// + /// Registro su DB le statistiche delle chiavi in elenco, resettando i vari contatori quando fatto + /// + /// Elenco key nel formato {rKeySampleVars}:{codInst}:{codApp}:{targetUrl} + public async Task saveStatsToDb(List keyList) + { + bool fatto = false; + // ciclo x eseguire 1:1 + foreach (var item in keyList) + { + // scompongo key... senza url di base + string[] valStr = item.Replace($"{rKeySampleVars}:", "").Split(":"); + if (valStr.Length > 2) + { + LogCallModel newRec = new LogCallModel() + { + CodInst = valStr[0], + CodApp = valStr[1], + TargetUrl = valStr[2], + DataRif = DateTime.Now, + NumCall = 1 + }; + fatto = await dbController.LogCallUpsert(newRec); + if (fatto) + { + await redCountClear(item); + } + } + } + return fatto; + } + + /// + /// Invio email richiesta + /// + /// + /// + /// + /// + public async Task SendEmail(string destEmail, string oggetto, string corpo) + { + bool answ = false; + try + { + await _emailSender.SendEmailAsync(destEmail, oggetto, corpo); + answ = true; + } + catch + { } + + return answ; + } + /// /// Esegue aggiunta Ticket richeisto + restitusice aperti x cliente /// @@ -376,6 +568,147 @@ namespace LiMan.APi.Data #endregion Public Methods + #region Protected Methods + + /// + /// Recupera statistiche correnti + /// + /// + protected async Task getCurrStats() + { + DateTime adesso = DateTime.Now; + SampleStats answ = new SampleStats() + { + Name = "ApiStats" + }; + // in primis check data/ora prima/ultima scrittura del set... (2 date, lista chiavi gestite) + string rawData = await getRSV(rKeySampleStats); + if (rawData != null) + { + answ = JsonConvert.DeserializeObject(rawData); + // aggiorno ultimo controllo e salvo... + answ.DtLast = adesso; + // salvo! + await setCurrStats(answ); + } + // controllo se scadute... + if (adesso.Subtract(answ.DtFirst).TotalMinutes > 60) + { + // se scaduto --> registrazione set sul DB (async), resettando i vari contatori... + bool salvato = await saveStatsToDb(answ.VList); + // inizio NUOVO set vuoto con record corrente + answ = new SampleStats() + { + Name = "ApiStats" + }; + // salvo! + await setCurrStats(answ); + } + // restituisco record! + return answ; + } + + /// + /// Recupero chiave da redis + /// + /// + /// + protected async Task getRSV(string rKey) + { + string answ = await _redisCacheClient.GetDbFromConfiguration().GetAsync(rKey); + return answ; + } + + /// + /// Resetta contatore x la chiave redis indicata... + /// + /// + protected async Task redCountClear(string rKey) + { + bool answ = false; + int currCount = 0; + answ = await setRSV(rKey, currCount, 2 * hourTTL); + return answ; + } + + /// + /// Incrementa contatore x la chiave redis indicata... + /// + /// + protected async Task redCountIncr(string rKey) + { + bool answ = false; + int currCount = 0; + string rawVal = await getRSV(rKey); + if (!string.IsNullOrEmpty(rawVal)) + { + int.TryParse(rawVal, out currCount); + } + currCount++; + answ = await setRSV(rKey, currCount, 2 * hourTTL); + return answ; + } + + /// + /// Salva statistiche correnti + /// + /// + protected async Task setCurrStats(SampleStats newVal) + { + bool answ = false; + string rawData = JsonConvert.SerializeObject(newVal); + answ = await setRSV(rKeySampleStats, rawData, 24 * hourTTL); + return answ; + } + + /// + /// Salvataggio chiave in redis + /// + /// + /// + /// + /// + protected async Task setRSV(string rKey, string rVal, int ttlSec) + { + bool fatto = false; + await _redisCacheClient.GetDbFromConfiguration().AddAsync(rKey, rVal, DateTimeOffset.Now.AddSeconds(ttlSec)); + fatto = true; + return fatto; + } + + /// + /// Salvataggio chiave in redis + /// + /// + /// + /// + /// + protected async Task setRSV(string rKey, int rValInt, int ttlSec) + { + bool fatto = false; + await _redisCacheClient.GetDbFromConfiguration().AddAsync(rKey, rValInt, DateTimeOffset.Now.AddSeconds(ttlSec)); + fatto = true; + return fatto; + } + + #endregion Protected Methods + + #region Private Methods + + /// + /// Parametri per generare opzioni cache + /// + /// Fattore di moltiplica cache (se 1 --> 2 e 5 min) + /// + private DistributedCacheEntryOptions cacheOpt(int multFact) + { + var numSecAbsExp = multFact <= 0 ? chAbsExp : chAbsExp * multFact; + var numSecSliExp = multFact <= 0 ? chSliExp : chSliExp * multFact; + return new DistributedCacheEntryOptions().SetAbsoluteExpiration(DateTime.Now.AddSeconds(numSecAbsExp)).SetSlidingExpiration(TimeSpan.FromSeconds(numSecSliExp)); + } + + #endregion Private Methods + #if false /// /// Elenco ticket dato licenza (limitato a maxRec) diff --git a/LiMan.Api/LiMan.APi.csproj b/LiMan.Api/LiMan.APi.csproj index 08c163a..61666c4 100644 --- a/LiMan.Api/LiMan.APi.csproj +++ b/LiMan.Api/LiMan.APi.csproj @@ -1,7 +1,7 @@  - net6.0 + net5.0 @@ -16,8 +16,12 @@ + + + + diff --git a/LiMan.Api/LiMan.APi.xml b/LiMan.Api/LiMan.APi.xml index 52caca2..024eacb 100644 --- a/LiMan.Api/LiMan.APi.xml +++ b/LiMan.Api/LiMan.APi.xml @@ -20,7 +20,7 @@ - + Dataservice x accesso DB @@ -50,7 +50,7 @@ - + Dataservice x accesso DB @@ -90,7 +90,7 @@ Verifica recupero un record di sub licenza Licenza MASTER - Codice univoco impiego licenza + Codice univoco impiego licenza @@ -109,7 +109,7 @@ - + Dataservice x accesso DB @@ -138,7 +138,7 @@ - + Dataservice x accesso DB @@ -162,6 +162,7 @@ + POST api/licenza/refreshPayload Effettua refresh del payload calcolato ed aggiorna record ed infine lo restituisce @@ -183,7 +184,7 @@ - + Dataservice x accesso DB @@ -209,18 +210,62 @@ Classe astrazione accesso dati - + + + Durata assoluta massima della cache IN SECONDI + + + + + Durata della cache IN SECONDI in modalità inattiva (non acceduta) prima di venire rimossa + NON estende oltre il tempo massimo di validità della cache (chAbsExp) + + + + + Classe Accesso metodi DB + + + + + Recupero chiave da redis + + + + + + + Salvataggio chiave in redis + + + + + + + + + Salvataggio chiave in redis + + + + + + + Init classe + + + - + - Effettua refresh del payload della licenza dato info + enigma generato dal client + Parametri per generare opzioni cache - + Fattore di moltiplica cache (se 1 --> 2 e 5 min) @@ -296,6 +341,20 @@ Dispose classe + + + Elenco licenze dato cliente + + Chiave Licenza x ricerca + + + + + Effettua refresh del payload della licenza dato info + enigma generato dal client + + + + Elenco licenze dato cliente @@ -313,6 +372,75 @@ Indica se nascondere i dati sensibili + + + Chiave redis x statistiche in acquisizione + + + + + Chiave redis x statistiche in acquisizione + + + + + Recupera statistiche correnti + + + + + + TTL da 1 h x cache Redis + + + + + Salva statistiche correnti + + + + + + Incrementa contatore x la chiave redis indicata... + + + + + + Resetta contatore x la chiave redis indicata... + + + + + + Effettua registrazione chiamata verificando se vada messa sul DB o in redis... + + + + + + + + Registro su DB le statistiche delle chiavi in elenco, resettando i vari contatori quando fatto + + Elenco key nel formato {rKeySampleVars}:{codInst}:{codApp}:{targetUrl} + + + + Effettua registrazione da codice chiave... + + + + + + + Invio email richiesta + + + + + + Esegue aggiunta Ticket richeisto + restitusice aperti x cliente diff --git a/LiMan.Api/Properties/PublishProfiles/IIS01.pubxml b/LiMan.Api/Properties/PublishProfiles/IIS01.pubxml index 74819e0..187f479 100644 --- a/LiMan.Api/Properties/PublishProfiles/IIS01.pubxml +++ b/LiMan.Api/Properties/PublishProfiles/IIS01.pubxml @@ -23,6 +23,6 @@ by editing this MSBuild file. In order to learn more about this please visit htt True jenkins <_SavePWD>True - net6.0 + net5.0 \ No newline at end of file diff --git a/LiMan.Api/Properties/PublishProfiles/IIS02.pubxml b/LiMan.Api/Properties/PublishProfiles/IIS02.pubxml index c5c0433..6f49e68 100644 --- a/LiMan.Api/Properties/PublishProfiles/IIS02.pubxml +++ b/LiMan.Api/Properties/PublishProfiles/IIS02.pubxml @@ -23,6 +23,6 @@ by editing this MSBuild file. In order to learn more about this please visit htt True jenkins <_SavePWD>True - net6.0 + net5.0 \ No newline at end of file diff --git a/LiMan.Api/Properties/PublishProfiles/W2019-IIS-DEV.pubxml b/LiMan.Api/Properties/PublishProfiles/W2019-IIS-DEV.pubxml index c60784c..25b5587 100644 --- a/LiMan.Api/Properties/PublishProfiles/W2019-IIS-DEV.pubxml +++ b/LiMan.Api/Properties/PublishProfiles/W2019-IIS-DEV.pubxml @@ -22,7 +22,7 @@ by editing this MSBuild file. In order to learn more about this please visit htt True jenkins <_SavePWD>True - net6.0 + net5.0 false \ No newline at end of file diff --git a/LiMan.Api/Startup.cs b/LiMan.Api/Startup.cs index 495c66b..02b0fdd 100644 --- a/LiMan.Api/Startup.cs +++ b/LiMan.Api/Startup.cs @@ -1,19 +1,17 @@ using LiMan.APi.Data; +using LiMan.DB; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.HttpsPolicy; -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Identity.UI.Services; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; using Microsoft.OpenApi.Models; +using StackExchange.Redis.Extensions.Core.Configuration; +using StackExchange.Redis.Extensions.Newtonsoft; using System; -using System.Collections.Generic; using System.IO; -using System.Linq; using System.Reflection; -using System.Threading.Tasks; namespace LiMan.Serv { @@ -77,6 +75,28 @@ namespace LiMan.Serv c.IncludeXmlComments(xmlPath); }); + // abilitazione x email management con MailKit + services.AddTransient(); + services.Configure(options => + { + options.Host_Address = Configuration["ExternalProviders:MailKit:SMTP:Address"]; + options.Host_Port = Convert.ToInt32(Configuration["ExternalProviders:MailKit:SMTP:Port"]); + options.Host_Username = Configuration["ExternalProviders:MailKit:SMTP:Account"]; + options.Host_Password = Configuration["ExternalProviders:MailKit:SMTP:Password"]; + options.Sender_EMail = Configuration["ExternalProviders:MailKit:SMTP:SenderEmail"]; + options.Sender_Name = Configuration["ExternalProviders:MailKit:SMTP:SenderName"]; + }); + + //services.AddStackExchangeRedisCache(options => + //{ + // options.Configuration = Configuration.GetConnectionString("Redis"); + //}); + + services.AddStackExchangeRedisExtensions((options) => + { + return Configuration.GetSection("Redis").Get(); + }); + services.AddSingleton(); } diff --git a/LiMan.Api/appsettings.json b/LiMan.Api/appsettings.json index 51ed134..77041ab 100644 --- a/LiMan.Api/appsettings.json +++ b/LiMan.Api/appsettings.json @@ -1,15 +1,45 @@ { - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information" - } - }, - "AllowedHosts": "*", - "ConnectionStrings": { - "LiMan.GLS": "Server=SQLSTEAM;Database=SteamWare_Auth;User ID=sa;Password=keyhammer;integrated security=False;MultipleActiveResultSets=True;App=LiMan.API;", - "LiMan.DB": "Server=SQLSTEAM;Database=LiMan.DB;User ID=sa;Password=keyhammer;integrated security=False;MultipleActiveResultSets=True;App=LiMan.API;", - "Redis": "localhost:6379" + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" } + }, + "AllowedHosts": "*", + "ConnectionStrings": { + "LiMan.GLS": "Server=SQLSTEAM;Database=SteamWare_Auth;User ID=sa;Password=keyhammer;integrated security=False;MultipleActiveResultSets=True;App=LiMan.API;", + "LiMan.DB": "Server=SQLSTEAM;Database=LiMan.DB;User ID=sa;Password=keyhammer;integrated security=False;MultipleActiveResultSets=True;App=LiMan.API;", + "Redis": "localhost:6379,DefaultDatabase=13" + }, + "ExternalProviders": { + "MailKit": { + "SMTP": { + "Address": "smtp.gmail.com", + "Port": "465", + "Account": "steamwarebot@gmail.com", + "Password": "drmfsls16", + "SenderEmail": "steamwarebot@gmail.com", + "SenderName": "Steamware Email BOT" + } + } + }, + "MailDest": { + "Admin": "samuele@steamware.net", + "ProcOp": "ceo@steamware.net" + }, + "Redis": { + "Password": "", + "AllowAdmin": false, + "Ssl": false, + "ConnectTimeout": 6000, + "ConnectRetry": 2, + "Hosts": [ + { + "Host": "localhost", + "Port": "6379" + } + ], + "Database": 14 + } } \ No newline at end of file diff --git a/LiMan.DB/Controllers/DbController.cs b/LiMan.DB/Controllers/DbController.cs index 63b7e2c..d108ec5 100644 --- a/LiMan.DB/Controllers/DbController.cs +++ b/LiMan.DB/Controllers/DbController.cs @@ -53,7 +53,7 @@ namespace LiMan.DB.Controllers // calcolo DTO Attivazione var itemsTgt = localDbCtx .DbSetSubLicenze - .Where(x => x.CodImpiego == item.Key && x.Chiave == item.Value && x.LicenzaNav.Chiave == MasterKey && x.VetoUnlock < oggi) + .Where(x => x.CodImpiego == item.Key && x.Chiave == item.Value && x.LicenzaNav.Chiave == MasterKey && x.VetoUnlock <= oggi) .ToList(); // se trovate aggiungo ad elenco... if (itemsTgt != null && itemsTgt.Count > 0) @@ -653,6 +653,80 @@ namespace LiMan.DB.Controllers return Task.FromResult(fatto); } + public LicenzaModel LicenzaByKey(string MasterKey) + { + LicenzaModel dbResult = new LicenzaModel(); + using (LMDbContext localDbCtx = new LMDbContext(_configuration)) + { + DateTime oggi = DateTime.Today; + dbResult = localDbCtx + .DbSetLicenze + .Where(x => x.Chiave == MasterKey) + .FirstOrDefault(); + } + return dbResult; + } + + /// + /// Elenco LOG chiamate all'API dato filtro + limite record + /// + /// + /// + /// + /// + /// + public List LogCallGetFilt(string CodApp, string CodInst, DateTime DateMax, int maxNumRec = 360) + { + List dbResult = new List(); + using (LMDbContext localDbCtx = new LMDbContext(_configuration)) + { + // recupero lista... + dbResult = localDbCtx + .DbSetLogCall + .Where(x => x.CodApp == CodApp && x.CodInst == CodInst && x.DataRif <= DateMax) + .OrderByDescending(x => x.DataRif) + .Take(maxNumRec) + .ToList(); + } + return dbResult; + } + + /// + /// Update/insert record Loc chiamate API + /// + /// + /// + public async Task LogCallUpsert(LogCallModel currRequest) + { + bool fatto = false; + using (LMDbContext localDbCtx = new LMDbContext(_configuration)) + { + // cerco record esistente... + var currRec = localDbCtx + .DbSetLogCall + .Where(x => x.CodApp == currRequest.CodApp && x.CodInst == currRequest.CodInst && x.DataRif == currRequest.DataRif && x.TargetUrl == currRequest.TargetUrl) + .FirstOrDefault(); + if (currRec != null) + { + // se trovo aggiorno + currRec.NumCall = currRequest.NumCall; + } + else + { + //altrimenti aggiungo + localDbCtx + .DbSetLogCall + .Add(currRequest); + } + + // salvo + await localDbCtx.SaveChangesAsync(); + + fatto = true; + } + return fatto; + } + /// /// Annulla modifiche su una specifica entity (cancel update) /// diff --git a/LiMan.DB/DBModels/LogCallModel.cs b/LiMan.DB/DBModels/LogCallModel.cs new file mode 100644 index 0000000..cbc751d --- /dev/null +++ b/LiMan.DB/DBModels/LogCallModel.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using static LiMan.DB.Enum; + +#nullable disable + +namespace LiMan.DB.DBModels +{ + // + // This is here so CodeMaid doesn't reorganize this document + // + //[Index(nameof(Installazione), nameof(Active), nameof(DiskStatus))] + [Table("LogCall")] + public partial class LogCallModel + { + #region Public Properties + + public DateTime DataRif { get; set; } + public string CodInst { get; set; } + public string CodApp { get; set; } + public string TargetUrl { get; set; } + public int NumCall { get; set; } = 0; + + + #endregion Public Properties + } +} \ No newline at end of file diff --git a/LiMan.DB/LMDbContext.cs b/LiMan.DB/LMDbContext.cs index 15d535c..27a1305 100644 --- a/LiMan.DB/LMDbContext.cs +++ b/LiMan.DB/LMDbContext.cs @@ -49,23 +49,17 @@ namespace LiMan.DB #region Public Properties public virtual DbSet DbSetApp { get; set; } - public virtual DbSet DbSetInst { get; set; } - public virtual DbSet DbSetLicenze { get; set; } - + public virtual DbSet DbSetLogCall { get; set; } public virtual DbSet DbSetLogLicenze { get; set; } public virtual DbSet DbSetSubLicenze { get; set; } - public virtual DbSet DbSetTicket { get; set; } #endregion Public Properties - - #region Private Methods - + partial void OnModelCreatingPartial(ModelBuilder modelBuilder); - #endregion Private Methods #region Protected Methods @@ -89,6 +83,11 @@ namespace LiMan.DB { modelBuilder.HasAnnotation("Relational:Collation", "SQL_Latin1_General_CP1_CI_AS"); + modelBuilder.Entity(entity => + { + entity.HasKey(e => new { e.DataRif, e.CodInst, e.CodApp, e.TargetUrl }); + }); + OnModelCreatingPartial(modelBuilder); } diff --git a/LiMan.DB/LiMan.DB.csproj b/LiMan.DB/LiMan.DB.csproj index fb5bd7e..dae6bfc 100644 --- a/LiMan.DB/LiMan.DB.csproj +++ b/LiMan.DB/LiMan.DB.csproj @@ -1,14 +1,13 @@  - net6.0 + net5.0 - - - - + + + diff --git a/LiMan.DB/MailKitEmailSender.cs b/LiMan.DB/MailKitEmailSender.cs new file mode 100644 index 0000000..53cdba5 --- /dev/null +++ b/LiMan.DB/MailKitEmailSender.cs @@ -0,0 +1,65 @@ +using MailKit.Net.Smtp; +using Microsoft.AspNetCore.Identity.UI.Services; +using Microsoft.Extensions.Options; +using MimeKit; +using MimeKit.Text; +using System.Threading.Tasks; + +namespace LiMan.DB +{ + /// + /// Implementazione interfaccia email con pacchetto MailKIT + /// + /// https://www.ryadel.com/en/asp-net-core-send-email-messages-smtp-mailkit/ + /// + public class MailKitEmailSender : IEmailSender + { + #region Public Constructors + + public MailKitEmailSender(IOptions options) + { + this.Options = options.Value; + } + + #endregion Public Constructors + + #region Public Properties + + public MailKitEmailSenderOptions Options { get; set; } + + #endregion Public Properties + + #region Public Methods + + public Task Execute(string to, string subject, string message) + { + // create message + var email = new MimeMessage(); + email.Sender = MailboxAddress.Parse(Options.Sender_EMail); + if (!string.IsNullOrEmpty(Options.Sender_Name)) + email.Sender.Name = Options.Sender_Name; + email.From.Add(email.Sender); + email.To.Add(MailboxAddress.Parse(to)); + email.Subject = subject; + email.Body = new TextPart(TextFormat.Html) { Text = message }; + + // send email + using (var smtp = new SmtpClient()) + { + smtp.Connect(Options.Host_Address, Options.Host_Port, Options.Host_SecureSocketOptions); + smtp.Authenticate(Options.Host_Username, Options.Host_Password); + smtp.Send(email); + smtp.Disconnect(true); + } + + return Task.FromResult(true); + } + + public Task SendEmailAsync(string email, string subject, string message) + { + return Execute(email, subject, message); + } + + #endregion Public Methods + } +} \ No newline at end of file diff --git a/LiMan.DB/MailKitEmailSenderOptions.cs b/LiMan.DB/MailKitEmailSenderOptions.cs new file mode 100644 index 0000000..43de307 --- /dev/null +++ b/LiMan.DB/MailKitEmailSenderOptions.cs @@ -0,0 +1,36 @@ +using MailKit.Security; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LiMan.DB +{ + public class MailKitEmailSenderOptions + { + #region Public Constructors + + public MailKitEmailSenderOptions() + { + Host_SecureSocketOptions = SecureSocketOptions.Auto; + } + + #endregion Public Constructors + + #region Public Properties + + public string Host_Address { get; set; } + + public string Host_Password { get; set; } + public int Host_Port { get; set; } + + public SecureSocketOptions Host_SecureSocketOptions { get; set; } + public string Host_Username { get; set; } + public string Sender_EMail { get; set; } + + public string Sender_Name { get; set; } + + #endregion Public Properties + } +} \ No newline at end of file diff --git a/LiMan.DB/Migrations/20211117101539_AddLogCalls.Designer.cs b/LiMan.DB/Migrations/20211117101539_AddLogCalls.Designer.cs new file mode 100644 index 0000000..d107d63 --- /dev/null +++ b/LiMan.DB/Migrations/20211117101539_AddLogCalls.Designer.cs @@ -0,0 +1,331 @@ +// +using System; +using LiMan.DB; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace LiMan.DB.Migrations +{ + [DbContext(typeof(LMDbContext))] + [Migration("20211117101539_AddLogCalls")] + partial class AddLogCalls + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Relational:Collation", "SQL_Latin1_General_CP1_CI_AS") + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("ProductVersion", "5.0.10") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("LiMan.DB.DBModels.ApplicativoModel", b => + { + b.Property("CodApp") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Descrizione") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.HasKey("CodApp"); + + b.ToTable("Applicativi"); + }); + + modelBuilder.Entity("LiMan.DB.DBModels.InstallazioneModel", b => + { + b.Property("CodInst") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Cliente") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Contatto") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Descrizione") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.Property("Email") + .HasMaxLength(250) + .HasColumnType("nvarchar(250)"); + + b.HasKey("CodInst"); + + b.ToTable("Installazioni"); + }); + + modelBuilder.Entity("LiMan.DB.DBModels.LicenzaModel", b => + { + b.Property("IdxLic") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Chiave") + .HasColumnType("nvarchar(max)"); + + b.Property("CodApp") + .HasColumnType("nvarchar(50)"); + + b.Property("CodInst") + .HasColumnType("nvarchar(50)"); + + b.Property("DataEnigma") + .HasColumnType("datetime2"); + + b.Property("Descrizione") + .HasColumnType("nvarchar(max)"); + + b.Property("Enigma") + .HasColumnType("nvarchar(max)"); + + b.Property("Locked") + .HasColumnType("bit"); + + b.Property("NumLicenze") + .HasColumnType("int"); + + b.Property("Payload") + .HasColumnType("nvarchar(max)"); + + b.Property("Scadenza") + .HasColumnType("datetime2"); + + b.Property("Tipo") + .HasColumnType("int"); + + b.HasKey("IdxLic"); + + b.HasIndex("CodApp"); + + b.HasIndex("CodInst"); + + b.ToTable("Licenze"); + }); + + modelBuilder.Entity("LiMan.DB.DBModels.LogCallModel", b => + { + b.Property("DataRif") + .HasColumnType("datetime2"); + + b.Property("CodInst") + .HasColumnType("nvarchar(450)"); + + b.Property("CodApp") + .HasColumnType("nvarchar(450)"); + + b.Property("TargetUrl") + .HasColumnType("nvarchar(450)"); + + b.Property("NumCall") + .HasColumnType("int"); + + b.HasKey("DataRif", "CodInst", "CodApp", "TargetUrl"); + + b.ToTable("LogCall"); + }); + + modelBuilder.Entity("LiMan.DB.DBModels.LogLicenzaModel", b => + { + b.Property("IdxLogLic") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Chiave") + .HasColumnType("nvarchar(max)"); + + b.Property("CodApp") + .HasColumnType("nvarchar(50)"); + + b.Property("CodInst") + .HasColumnType("nvarchar(50)"); + + b.Property("Descrizione") + .HasColumnType("nvarchar(max)"); + + b.Property("IdxLic") + .HasColumnType("int"); + + b.Property("NumLicenze") + .HasColumnType("int"); + + b.Property("Scadenza") + .HasColumnType("datetime2"); + + b.Property("Tipo") + .HasColumnType("int"); + + b.HasKey("IdxLogLic"); + + b.HasIndex("CodApp"); + + b.HasIndex("CodInst"); + + b.HasIndex("IdxLic"); + + b.ToTable("LogLicenze"); + }); + + modelBuilder.Entity("LiMan.DB.DBModels.SubLicenzaModel", b => + { + b.Property("IdxSubLic") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Chiave") + .HasColumnType("nvarchar(max)"); + + b.Property("CodImpiego") + .HasColumnType("nvarchar(max)"); + + b.Property("IdxLic") + .HasColumnType("int"); + + b.Property("Tipo") + .HasColumnType("int"); + + b.Property("VetoUnlock") + .HasColumnType("datetime2"); + + b.HasKey("IdxSubLic"); + + b.HasIndex("IdxLic"); + + b.ToTable("SubLicenze"); + }); + + modelBuilder.Entity("LiMan.DB.DBModels.TicketModel", b => + { + b.Property("IdxTicket") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("CodImpiego") + .HasColumnType("nvarchar(max)"); + + b.Property("ContactEmail") + .HasColumnType("nvarchar(max)"); + + b.Property("ContactName") + .HasColumnType("nvarchar(max)"); + + b.Property("ContactPhone") + .HasColumnType("nvarchar(max)"); + + b.Property("DtReq") + .HasColumnType("datetime2"); + + b.Property("IdxLic") + .HasColumnType("int"); + + b.Property("IdxSubLic") + .HasColumnType("int"); + + b.Property("ReqBody") + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("SupplAnsw") + .HasColumnType("nvarchar(max)"); + + b.Property("SupplEmail") + .HasColumnType("nvarchar(max)"); + + b.Property("SupplUserCode") + .HasColumnType("nvarchar(max)"); + + b.Property("Tipo") + .HasColumnType("int"); + + b.HasKey("IdxTicket"); + + b.HasIndex("IdxLic"); + + b.ToTable("TicketLog"); + }); + + modelBuilder.Entity("LiMan.DB.DBModels.LicenzaModel", b => + { + b.HasOne("LiMan.DB.DBModels.ApplicativoModel", "ApplicativoNav") + .WithMany() + .HasForeignKey("CodApp"); + + b.HasOne("LiMan.DB.DBModels.InstallazioneModel", "InstallazioneNav") + .WithMany() + .HasForeignKey("CodInst"); + + b.Navigation("ApplicativoNav"); + + b.Navigation("InstallazioneNav"); + }); + + modelBuilder.Entity("LiMan.DB.DBModels.LogLicenzaModel", b => + { + b.HasOne("LiMan.DB.DBModels.ApplicativoModel", "ApplicativoNav") + .WithMany() + .HasForeignKey("CodApp"); + + b.HasOne("LiMan.DB.DBModels.InstallazioneModel", "InstallazioneNav") + .WithMany() + .HasForeignKey("CodInst"); + + b.HasOne("LiMan.DB.DBModels.LicenzaModel", "LicenzaNav") + .WithMany() + .HasForeignKey("IdxLic") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ApplicativoNav"); + + b.Navigation("InstallazioneNav"); + + b.Navigation("LicenzaNav"); + }); + + modelBuilder.Entity("LiMan.DB.DBModels.SubLicenzaModel", b => + { + b.HasOne("LiMan.DB.DBModels.LicenzaModel", "LicenzaNav") + .WithMany("Attivazioni") + .HasForeignKey("IdxLic") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("LicenzaNav"); + }); + + modelBuilder.Entity("LiMan.DB.DBModels.TicketModel", b => + { + b.HasOne("LiMan.DB.DBModels.LicenzaModel", "LicenzaNav") + .WithMany("Tickets") + .HasForeignKey("IdxLic") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("LicenzaNav"); + }); + + modelBuilder.Entity("LiMan.DB.DBModels.LicenzaModel", b => + { + b.Navigation("Attivazioni"); + + b.Navigation("Tickets"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/LiMan.DB/Migrations/20211117101539_AddLogCalls.cs b/LiMan.DB/Migrations/20211117101539_AddLogCalls.cs new file mode 100644 index 0000000..3bf3604 --- /dev/null +++ b/LiMan.DB/Migrations/20211117101539_AddLogCalls.cs @@ -0,0 +1,32 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace LiMan.DB.Migrations +{ + public partial class AddLogCalls : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "LogCall", + columns: table => new + { + DataRif = table.Column(type: "datetime2", nullable: false), + CodInst = table.Column(type: "nvarchar(450)", nullable: false), + CodApp = table.Column(type: "nvarchar(450)", nullable: false), + TargetUrl = table.Column(type: "nvarchar(450)", nullable: false), + NumCall = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_LogCall", x => new { x.DataRif, x.CodInst, x.CodApp, x.TargetUrl }); + }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "LogCall"); + } + } +} diff --git a/LiMan.DB/Migrations/LMDbContextModelSnapshot.cs b/LiMan.DB/Migrations/LMDbContextModelSnapshot.cs index b342fbd..b52d5fc 100644 --- a/LiMan.DB/Migrations/LMDbContextModelSnapshot.cs +++ b/LiMan.DB/Migrations/LMDbContextModelSnapshot.cs @@ -111,6 +111,28 @@ namespace LiMan.DB.Migrations b.ToTable("Licenze"); }); + modelBuilder.Entity("LiMan.DB.DBModels.LogCallModel", b => + { + b.Property("DataRif") + .HasColumnType("datetime2"); + + b.Property("CodInst") + .HasColumnType("nvarchar(450)"); + + b.Property("CodApp") + .HasColumnType("nvarchar(450)"); + + b.Property("TargetUrl") + .HasColumnType("nvarchar(450)"); + + b.Property("NumCall") + .HasColumnType("int"); + + b.HasKey("DataRif", "CodInst", "CodApp", "TargetUrl"); + + b.ToTable("LogCall"); + }); + modelBuilder.Entity("LiMan.DB.DBModels.LogLicenzaModel", b => { b.Property("IdxLogLic") diff --git a/LiMan.GLS/LiMan.GLS.csproj b/LiMan.GLS/LiMan.GLS.csproj index 78f11cb..f77e57e 100644 --- a/LiMan.GLS/LiMan.GLS.csproj +++ b/LiMan.GLS/LiMan.GLS.csproj @@ -1,7 +1,7 @@  - net6.0 + net5.0 diff --git a/LiMan.UI/Data/LiManDataService.cs b/LiMan.UI/Data/LiManDataService.cs index 457d60b..a4bd2c1 100644 --- a/LiMan.UI/Data/LiManDataService.cs +++ b/LiMan.UI/Data/LiManDataService.cs @@ -11,6 +11,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using static LiMan.DB.Enum; +using Microsoft.AspNetCore.Identity.UI.Services; namespace LiMan.UI.Data { @@ -20,8 +21,8 @@ namespace LiMan.UI.Data private static IConfiguration _configuration; private static ILogger _logger; - private static NLog.Logger Log = LogManager.GetCurrentClassLogger(); + private readonly IEmailSender _emailSender; private readonly IDistributedCache distributedCache; private readonly IMemoryCache memoryCache; @@ -54,10 +55,11 @@ namespace LiMan.UI.Data #region Public Constructors - public LiManDataService(IConfiguration configuration, ILogger logger, IMemoryCache memoryCache, IDistributedCache distributedCache) + public LiManDataService(IConfiguration configuration, ILogger logger, IMemoryCache memoryCache, IDistributedCache distributedCache, IEmailSender emailSender) { _logger = logger; _configuration = configuration; + _emailSender = emailSender; // conf cache this.memoryCache = memoryCache; this.distributedCache = distributedCache; @@ -547,6 +549,20 @@ namespace LiMan.UI.Data dbControllerGLS.rollBackEntity(item); } + public async Task SendEmail(string destEmail, string oggetto, string corpo) + { + bool answ = false; + try + { + await _emailSender.SendEmailAsync(destEmail, oggetto, corpo); + answ = true; + } + catch + { } + + return answ; + } + /// /// Aggiornamentos tato ticket /// diff --git a/LiMan.UI/LiMan.UI.csproj b/LiMan.UI/LiMan.UI.csproj index 61fb80c..01a4c35 100644 --- a/LiMan.UI/LiMan.UI.csproj +++ b/LiMan.UI/LiMan.UI.csproj @@ -1,8 +1,8 @@ - net6.0 - 1.1.2111.1618 + net5.0 + 1.1.2111.1719 LiMan.UI LiMan.UI diff --git a/LiMan.UI/Properties/PublishProfiles/IIS01.pubxml b/LiMan.UI/Properties/PublishProfiles/IIS01.pubxml index 81e712b..94ebf7d 100644 --- a/LiMan.UI/Properties/PublishProfiles/IIS01.pubxml +++ b/LiMan.UI/Properties/PublishProfiles/IIS01.pubxml @@ -22,7 +22,7 @@ by editing this MSBuild file. In order to learn more about this please visit htt True jenkins <_SavePWD>True - net6.0 + net5.0 false \ No newline at end of file diff --git a/LiMan.UI/Properties/PublishProfiles/IIS02.pubxml b/LiMan.UI/Properties/PublishProfiles/IIS02.pubxml index 1847a26..aaca518 100644 --- a/LiMan.UI/Properties/PublishProfiles/IIS02.pubxml +++ b/LiMan.UI/Properties/PublishProfiles/IIS02.pubxml @@ -22,7 +22,7 @@ by editing this MSBuild file. In order to learn more about this please visit htt True jenkins <_SavePWD>True - net6.0 + net5.0 false \ No newline at end of file diff --git a/LiMan.UI/Properties/PublishProfiles/W2019-IIS-DEV.pubxml b/LiMan.UI/Properties/PublishProfiles/W2019-IIS-DEV.pubxml index 3aaee28..c727b14 100644 --- a/LiMan.UI/Properties/PublishProfiles/W2019-IIS-DEV.pubxml +++ b/LiMan.UI/Properties/PublishProfiles/W2019-IIS-DEV.pubxml @@ -22,7 +22,7 @@ by editing this MSBuild file. In order to learn more about this please visit htt True jenkins <_SavePWD>True - net6.0 + net5.0 false \ No newline at end of file diff --git a/LiMan.UI/Resources/ChangeLog.html b/LiMan.UI/Resources/ChangeLog.html index 89f81a8..8d7b79a 100644 --- a/LiMan.UI/Resources/ChangeLog.html +++ b/LiMan.UI/Resources/ChangeLog.html @@ -1,6 +1,6 @@ License Manager -

Versione: 1.1.2111.1618

+

Versione: 1.1.2111.1719


Note di rilascio:
    diff --git a/LiMan.UI/Resources/VersNum.txt b/LiMan.UI/Resources/VersNum.txt index 352ab4e..7232e07 100644 --- a/LiMan.UI/Resources/VersNum.txt +++ b/LiMan.UI/Resources/VersNum.txt @@ -1 +1 @@ -1.1.2111.1618 +1.1.2111.1719 diff --git a/LiMan.UI/Resources/manifest.xml b/LiMan.UI/Resources/manifest.xml index 59648ab..9cfa5fd 100644 --- a/LiMan.UI/Resources/manifest.xml +++ b/LiMan.UI/Resources/manifest.xml @@ -1,6 +1,6 @@ - 1.1.2111.1618 + 1.1.2111.1719 https://nexus.steamware.net/repository/SWS/LiMan/stable/LAST/LiMan.UI.zip https://nexus.steamware.net/repository/SWS/LiMan/stable/LAST/ChangeLog.html false diff --git a/LiMan.UI/Startup.cs b/LiMan.UI/Startup.cs index 2bae00f..57cfb22 100644 --- a/LiMan.UI/Startup.cs +++ b/LiMan.UI/Startup.cs @@ -1,3 +1,4 @@ +using LiMan.DB; using LiMan.UI.Data; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Components; @@ -13,6 +14,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity.UI.Services; namespace LiMan.UI { @@ -97,6 +99,18 @@ namespace LiMan.UI options.InstanceName = "LiMan"; }); + // abilitazione x email management con MailKit + services.AddTransient(); + services.Configure(options => + { + options.Host_Address = Configuration["ExternalProviders:MailKit:SMTP:Address"]; + options.Host_Port = Convert.ToInt32(Configuration["ExternalProviders:MailKit:SMTP:Port"]); + options.Host_Username = Configuration["ExternalProviders:MailKit:SMTP:Account"]; + options.Host_Password = Configuration["ExternalProviders:MailKit:SMTP:Password"]; + options.Sender_EMail = Configuration["ExternalProviders:MailKit:SMTP:SenderEmail"]; + options.Sender_Name = Configuration["ExternalProviders:MailKit:SMTP:SenderName"]; + }); + services.AddLocalization(); services.AddRazorPages(); diff --git a/LiMan.UI/appsettings.json b/LiMan.UI/appsettings.json index ad09909..4667c39 100644 --- a/LiMan.UI/appsettings.json +++ b/LiMan.UI/appsettings.json @@ -1,15 +1,31 @@ { - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information" - } - }, - "AllowedHosts": "*", - "ConnectionStrings": { - "LiMan.GLS": "Server=SQLSTEAM;Database=SteamWare_Auth;User ID=sa;Password=keyhammer;integrated security=False;MultipleActiveResultSets=True;App=LiMan.UI;", - "LiMan.DB": "Server=SQLSTEAM;Database=LiMan.DB;User ID=sa;Password=keyhammer;integrated security=False;MultipleActiveResultSets=True;App=LiMan.UI;", - "Redis": "localhost:6379" + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" } + }, + "AllowedHosts": "*", + "ConnectionStrings": { + "LiMan.GLS": "Server=SQLSTEAM;Database=SteamWare_Auth;User ID=sa;Password=keyhammer;integrated security=False;MultipleActiveResultSets=True;App=LiMan.UI;", + "LiMan.DB": "Server=SQLSTEAM;Database=LiMan.DB;User ID=sa;Password=keyhammer;integrated security=False;MultipleActiveResultSets=True;App=LiMan.UI;", + "Redis": "localhost:6379" + }, + "ExternalProviders": { + "MailKit": { + "SMTP": { + "Address": "smtp.gmail.com", + "Port": "465", + "Account": "steamwarebot@gmail.com", + "Password": "drmfsls16", + "SenderEmail": "steamwarebot@gmail.com", + "SenderName": "Steamware Email BOT" + } + } + }, + "MailDest": { + "Admin": "samuele@steamware.net", + "ProcOp": "ceo@steamware.net" + } } \ No newline at end of file