2025-05-31 19:26:02 +02:00
|
|
|
using System.Globalization;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using Google.Apis.Sheets.v4;
|
|
|
|
|
using Microsoft.AspNetCore.Authorization;
|
|
|
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
|
using DiunaBI.Core.Models;
|
|
|
|
|
using DiunaBI.Database.Context;
|
|
|
|
|
using DiunaBI.Core.Services;
|
|
|
|
|
using Google.Cloud.Firestore;
|
|
|
|
|
|
|
|
|
|
namespace DiunaBI.WebAPI.Controllers;
|
|
|
|
|
|
|
|
|
|
[ApiController]
|
|
|
|
|
[Route("api/[controller]")]
|
|
|
|
|
public class LayersController : Controller
|
|
|
|
|
{
|
|
|
|
|
private readonly AppDbContext _db;
|
|
|
|
|
private readonly SpreadsheetsResource.ValuesResource? _googleSheetValues;
|
|
|
|
|
private readonly GoogleDriveHelper _googleDriveHelper;
|
|
|
|
|
private readonly IConfiguration _configuration;
|
|
|
|
|
private readonly LogsController _logsController;
|
2025-06-02 16:54:33 +02:00
|
|
|
private readonly PluginManager _pluginManager;
|
2025-05-31 19:26:02 +02:00
|
|
|
|
|
|
|
|
public LayersController(
|
|
|
|
|
AppDbContext db,
|
|
|
|
|
GoogleSheetsHelper googleSheetsHelper,
|
|
|
|
|
GoogleDriveHelper googleDriveHelper,
|
|
|
|
|
IConfiguration configuration,
|
2025-06-02 16:54:33 +02:00
|
|
|
FirestoreDb firestoreDb,
|
|
|
|
|
PluginManager pluginManager
|
2025-05-31 19:26:02 +02:00
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
_db = db;
|
|
|
|
|
if (googleSheetsHelper.Service is not null)
|
|
|
|
|
{
|
|
|
|
|
_googleSheetValues = googleSheetsHelper.Service.Spreadsheets.Values;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_googleDriveHelper = googleDriveHelper;
|
|
|
|
|
_configuration = configuration;
|
|
|
|
|
_logsController = new LogsController(firestoreDb);
|
2025-06-02 16:54:33 +02:00
|
|
|
_pluginManager = pluginManager;
|
2025-05-31 19:26:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet]
|
|
|
|
|
public IActionResult GetAll(int start, int limit, string? name, LayerType? type)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var response = _db.Layers.Where(x => !x.IsDeleted);
|
|
|
|
|
if (name != null)
|
|
|
|
|
{
|
|
|
|
|
response = response.Where(x => x.Name != null && x.Name.Contains(name));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (type != null)
|
|
|
|
|
{
|
|
|
|
|
response = response.Where(x => x.Type == type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Ok(response
|
|
|
|
|
.OrderByDescending(x => x.Number)
|
|
|
|
|
.Skip(start).Take(limit).AsNoTracking().ToList());
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
return BadRequest(e.ToString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet]
|
|
|
|
|
[Route("{id:guid}")]
|
|
|
|
|
public IActionResult Get(Guid id)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return Ok(_db.Layers
|
|
|
|
|
.Include(x => x.CreatedBy)
|
|
|
|
|
.Include(x => x.ModifiedBy)
|
|
|
|
|
.Include(x => x.Records).AsNoTracking().First(x => x.Id == id && !x.IsDeleted));
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
return BadRequest(e.ToString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet]
|
|
|
|
|
[Route("getForPowerBI/{apiKey}/{number:int}")]
|
|
|
|
|
public IActionResult GetByNumber(string apiKey, int number)
|
|
|
|
|
{
|
|
|
|
|
if (apiKey != _configuration["apiKey"])
|
|
|
|
|
{
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = $"Unauthorized request - wrong apiKey ({number})",
|
|
|
|
|
Type = LogEntryType.Warning,
|
|
|
|
|
LogType = LogType.PowerBi,
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
return Unauthorized();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (
|
|
|
|
|
!Request.Headers.TryGetValue("Authorization", out var authHeader))
|
|
|
|
|
{
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = $"Unauthorized request - no authorization header ({number})",
|
|
|
|
|
Type = LogEntryType.Warning,
|
|
|
|
|
LogType = LogType.PowerBi,
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
return Unauthorized();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var credentialsArr = authHeader.ToString().Split(" ");
|
|
|
|
|
if (credentialsArr.Length != 2)
|
|
|
|
|
{
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = $"Unauthorized request - wrong auth header format ({number})",
|
|
|
|
|
Type = LogEntryType.Warning,
|
|
|
|
|
LogType = LogType.PowerBi,
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
return Unauthorized();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var authValue = Encoding.UTF8.GetString(Convert.FromBase64String(credentialsArr[1]));
|
|
|
|
|
var username = authValue.Split(':')[0];
|
|
|
|
|
var password = authValue.Split(':')[1];
|
|
|
|
|
if (username != _configuration["powerBI-user"] || password != _configuration["powerBI-pass"])
|
|
|
|
|
{
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = $"Unauthorized request - bad credentials ({number})",
|
|
|
|
|
Type = LogEntryType.Warning,
|
|
|
|
|
LogType = LogType.PowerBi,
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
return Unauthorized();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = $"Sending data for layer {number}",
|
|
|
|
|
Type = LogEntryType.Info,
|
|
|
|
|
LogType = LogType.PowerBi,
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return Ok(_db.Layers
|
|
|
|
|
.Include(x => x.CreatedBy)
|
|
|
|
|
.Include(x => x.Records).AsNoTracking().First(x => x.Number == number && !x.IsDeleted));
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = e.ToString(),
|
|
|
|
|
Type = LogEntryType.Error,
|
|
|
|
|
LogType = LogType.PowerBi,
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
return BadRequest(e.ToString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet]
|
|
|
|
|
[Route("getConfiguration/{apiKey}/{number:int}")]
|
|
|
|
|
public IActionResult GetConfigurationByNumber(string apiKey, int number)
|
|
|
|
|
{
|
|
|
|
|
if (apiKey != _configuration["apiKey"])
|
|
|
|
|
{
|
|
|
|
|
return Unauthorized();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (
|
|
|
|
|
!Request.Headers.TryGetValue("Authorization", out var authHeader))
|
|
|
|
|
{
|
|
|
|
|
return Unauthorized();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var credentialsArr = authHeader.ToString().Split(" ");
|
|
|
|
|
if (credentialsArr.Length != 2)
|
|
|
|
|
{
|
|
|
|
|
return Unauthorized();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var authValue = Encoding.UTF8.GetString(Convert.FromBase64String(credentialsArr[1]));
|
|
|
|
|
var username = authValue.Split(':')[0];
|
|
|
|
|
var password = authValue.Split(':')[1];
|
|
|
|
|
if (username != _configuration["morska-user"] || password != _configuration["morska-pass"])
|
|
|
|
|
{
|
|
|
|
|
return Unauthorized();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var config = _db.Layers
|
|
|
|
|
.Include(x => x.Records)
|
|
|
|
|
.AsNoTracking()
|
|
|
|
|
.First(x => x.Number == number && !x.IsDeleted);
|
|
|
|
|
|
|
|
|
|
if (config is null)
|
|
|
|
|
{
|
|
|
|
|
return BadRequest();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var type = config.Records?.Where(x => x.Code == "Type").FirstOrDefault();
|
|
|
|
|
if (type is null || type.Desc1 != "ExternalConfiguration")
|
|
|
|
|
{
|
|
|
|
|
return BadRequest();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Ok(config);
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
return BadRequest();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet]
|
|
|
|
|
[Route("exportToGoogleSheet/{id:guid}")]
|
|
|
|
|
public IActionResult ExportToGoogleSheet(Guid id)
|
|
|
|
|
{
|
|
|
|
|
if (_googleSheetValues is null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Google Sheets API not initialized");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var layer = _db.Layers
|
|
|
|
|
.Include(x => x.Records!.OrderByDescending(y => y.Code)).AsNoTracking().First(x => x.Id == id && !x.IsDeleted);
|
|
|
|
|
|
2025-06-02 16:54:33 +02:00
|
|
|
var export = _pluginManager.GetExporter("GoogleSheet");
|
|
|
|
|
if (export == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("GoogleSheet exporter not found");
|
|
|
|
|
}
|
2025-05-31 19:26:02 +02:00
|
|
|
export.Export(layer);
|
|
|
|
|
return Ok(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet]
|
|
|
|
|
[Route("AutoImportWithQueue/{apiKey}")]
|
|
|
|
|
[AllowAnonymous]
|
|
|
|
|
public IActionResult AutoImportWithQueue(string apiKey)
|
|
|
|
|
{
|
|
|
|
|
if (Request.Host.Value != _configuration["apiLocalUrl"] || apiKey != _configuration["apiKey"])
|
|
|
|
|
{
|
|
|
|
|
return Unauthorized();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var importWorkerLayers = _db.Layers
|
|
|
|
|
.Include(x => x.Records)
|
|
|
|
|
.Where(x =>
|
|
|
|
|
x.Records!.Any(y => y.Code == "Type" && y.Desc1 == "ImportWorker") &&
|
|
|
|
|
x.Records!.Any(y => y.Code == "IsEnabled" && y.Desc1 == "True")
|
|
|
|
|
)
|
|
|
|
|
.OrderBy(x => x.CreatedAt)
|
|
|
|
|
.AsNoTracking()
|
|
|
|
|
.ToList();
|
|
|
|
|
|
|
|
|
|
if (importWorkerLayers.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = "No Layers to import.",
|
|
|
|
|
Type = LogEntryType.Info,
|
|
|
|
|
LogType = LogType.Queue,
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
return Ok();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var importWorker in importWorkerLayers)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
await _queue.AddJob(new QueueJob
|
|
|
|
|
{
|
|
|
|
|
LayerId = importWorker.Id,
|
|
|
|
|
Type = JobType.ImportWorker,
|
|
|
|
|
});
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = $"Error while adding job into queue (import): {importWorker.Name}, {importWorker.Id}",
|
|
|
|
|
Type = LogEntryType.Error,
|
|
|
|
|
LogType = LogType.Queue,
|
|
|
|
|
Message = e.ToString(),
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return Ok();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet]
|
|
|
|
|
[Route("ProcessQueue/{apiKey}")]
|
|
|
|
|
[AllowAnonymous]
|
|
|
|
|
public IActionResult ProcessQueue(string apiKey)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
var allJobs = await _queue.GetJobs();
|
|
|
|
|
var importJobs = allJobs
|
|
|
|
|
.Where(x => x.Type == JobType.ImportWorker && x.Status == JobStatus.New);
|
|
|
|
|
|
|
|
|
|
foreach (var job in importJobs)
|
|
|
|
|
{
|
|
|
|
|
job.Attempts = job.Attempts + 1;
|
|
|
|
|
//await _queue.UpdateJob(job);
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
return Ok();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet]
|
|
|
|
|
[Route("AutoImport/{apiKey}/{nameFilter}")]
|
|
|
|
|
[AllowAnonymous]
|
|
|
|
|
public IActionResult AutoImport(string apiKey, string nameFilter)
|
|
|
|
|
{
|
|
|
|
|
if (Request.Host.Value != _configuration["apiLocalUrl"] || apiKey != _configuration["apiKey"])
|
|
|
|
|
{
|
|
|
|
|
return Unauthorized();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_googleSheetValues is null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Google Sheets API not initialized");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var importWorkerLayers = _db.Layers
|
|
|
|
|
.Include(x => x.Records)
|
|
|
|
|
.Where(x =>
|
|
|
|
|
x.Name != null && x.Name.Contains(nameFilter) &&
|
|
|
|
|
x.Records!.Any(y => y.Code == "Type" && y.Desc1 == "ImportWorker") &&
|
|
|
|
|
x.Records!.Any(y => y.Code == "IsEnabled" && y.Desc1 == "True")
|
|
|
|
|
)
|
|
|
|
|
.OrderByDescending(x => x.CreatedAt)
|
|
|
|
|
.AsNoTracking()
|
|
|
|
|
.ToList();
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = $"Starting import: {nameFilter}, Admin layers count ({importWorkerLayers.Count})",
|
|
|
|
|
Type = LogEntryType.Info,
|
|
|
|
|
LogType = LogType.Import,
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (importWorkerLayers.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = "No Layers to import.",
|
|
|
|
|
Type = LogEntryType.Info,
|
|
|
|
|
LogType = LogType.Import,
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
return Ok();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var importWorker in importWorkerLayers)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var type = importWorker.Records!.FirstOrDefault(x => x.Code == "ImportType")?.Desc1 ??
|
|
|
|
|
"Standard";
|
|
|
|
|
var source = importWorker.Records!.FirstOrDefault(x => x.Code == "Source")?.Desc1 ??
|
|
|
|
|
"GoogleSheet";
|
|
|
|
|
if (source == "DataInbox" && type == "Import-D3")
|
|
|
|
|
{
|
2025-06-02 16:54:33 +02:00
|
|
|
var d3Importer = _pluginManager.GetImporter("MorskaD3");
|
|
|
|
|
if (d3Importer == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("MorskaD3 importer not found");
|
|
|
|
|
}
|
2025-05-31 19:26:02 +02:00
|
|
|
d3Importer.Import(importWorker);
|
2025-06-02 16:54:33 +02:00
|
|
|
|
2025-05-31 19:26:02 +02:00
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = $"{importWorker.Name}, {importWorker.Id}",
|
|
|
|
|
Type = LogEntryType.Info,
|
|
|
|
|
LogType = LogType.Import,
|
|
|
|
|
Message = "Success",
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
|
|
|
|
case "D1":
|
2025-06-02 16:54:33 +02:00
|
|
|
var d1importer = _pluginManager.GetImporter("MorskaD1");
|
|
|
|
|
if (d1importer == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("MorskaD1 importer not found");
|
|
|
|
|
}
|
|
|
|
|
d1importer.Import(importWorker);
|
|
|
|
|
|
2025-05-31 19:26:02 +02:00
|
|
|
Thread.Sleep(5000); // be aware of GSheet API quota
|
|
|
|
|
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = $"{importWorker.Name}, {importWorker.Id}",
|
|
|
|
|
Type = LogEntryType.Info,
|
|
|
|
|
LogType = LogType.Import,
|
|
|
|
|
Message = "Success",
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
case "FK2":
|
|
|
|
|
{
|
2025-06-02 16:54:33 +02:00
|
|
|
var fk2importer = _pluginManager.GetImporter("MorskaFK2");
|
|
|
|
|
if (fk2importer == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("MorskaFK2 importer not found");
|
|
|
|
|
}
|
|
|
|
|
fk2importer.Import(importWorker);
|
2025-05-31 19:26:02 +02:00
|
|
|
Thread.Sleep(5000); // be aware of GSheet API quota
|
|
|
|
|
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = $"{importWorker.Name}, {importWorker.Id}",
|
|
|
|
|
Type = LogEntryType.Info,
|
|
|
|
|
LogType = LogType.Import,
|
|
|
|
|
Message = "Success",
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
var startDate = importWorker.Records!.FirstOrDefault(x => x.Code == "StartDate")?.Desc1;
|
|
|
|
|
if (startDate == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("StartDate record nod found");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var endDate = importWorker.Records!.First(x => x.Code == "EndDate").Desc1;
|
|
|
|
|
if (endDate == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("EndDate record nod found");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var startDateParsed = DateTime.ParseExact(startDate, "yyyy.MM.dd", null);
|
|
|
|
|
var endDateParsed = DateTime.ParseExact(endDate, "yyyy.MM.dd", null);
|
|
|
|
|
if (startDateParsed.Date <= DateTime.UtcNow.Date &&
|
|
|
|
|
endDateParsed.Date >= DateTime.UtcNow.Date)
|
|
|
|
|
{
|
2025-06-02 16:54:33 +02:00
|
|
|
var importer = _pluginManager.GetImporter("MorskaImporter");
|
|
|
|
|
if (importer == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("MorskaImporter not found");
|
|
|
|
|
}
|
2025-05-31 19:26:02 +02:00
|
|
|
importer.Import(importWorker);
|
|
|
|
|
Thread.Sleep(5000); // be aware of GSheet API quota
|
|
|
|
|
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = $"{importWorker.Name}, {importWorker.Id}",
|
|
|
|
|
Type = LogEntryType.Info,
|
|
|
|
|
LogType = LogType.Import,
|
|
|
|
|
Message = "Success",
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
else if (IsImportedLayerUpToDate(importWorker) == false)
|
|
|
|
|
{
|
2025-06-02 16:54:33 +02:00
|
|
|
var importer = _pluginManager.GetImporter("MorskaImporter");
|
|
|
|
|
if (importer == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("MorskaImporter not found");
|
|
|
|
|
}
|
2025-05-31 19:26:02 +02:00
|
|
|
importer.Import(importWorker);
|
|
|
|
|
Thread.Sleep(5000); // be aware of GSheet API quota
|
|
|
|
|
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = $"{importWorker.Name}, {importWorker.Id}",
|
|
|
|
|
Type = LogEntryType.Warning,
|
|
|
|
|
LogType = LogType.Import,
|
|
|
|
|
Message = "Success (reimported)",
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = $"{importWorker.Name}, {importWorker.Id}",
|
|
|
|
|
Type = LogEntryType.Warning,
|
|
|
|
|
LogType = LogType.Import,
|
|
|
|
|
Message = "importLayer records are up to date. Not processed.",
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = $"{importWorker.Name}, {importWorker.Id}",
|
|
|
|
|
Type = LogEntryType.Error,
|
|
|
|
|
LogType = LogType.Import,
|
|
|
|
|
Message = e.ToString(),
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Ok();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = "Process error",
|
|
|
|
|
Type = LogEntryType.Error,
|
|
|
|
|
LogType = LogType.Import,
|
|
|
|
|
Message = e.ToString(),
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
return BadRequest(e.ToString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet]
|
|
|
|
|
[Route("AutoProcess/{apiKey}")]
|
|
|
|
|
[AllowAnonymous]
|
|
|
|
|
public IActionResult AutoProcess(string apiKey)
|
|
|
|
|
{
|
|
|
|
|
if (Request.Host.Value != _configuration["apiLocalUrl"] || apiKey != _configuration["apiKey"])
|
|
|
|
|
{
|
|
|
|
|
return Unauthorized();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_googleSheetValues is null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Google Sheets API not initialized");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string[] processTypes =
|
|
|
|
|
[
|
|
|
|
|
"T3-SingleSource",
|
|
|
|
|
"T3-SourceYearSummary",
|
|
|
|
|
"T3-MultiSourceSummary", // AA
|
|
|
|
|
"T3-MultiSourceYearSummary", // AA/13
|
|
|
|
|
"T4-SingleSource",
|
|
|
|
|
"T5-LastValues",
|
|
|
|
|
"T1-R1",
|
|
|
|
|
"T4-R2",
|
|
|
|
|
"T1-R3"
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
foreach (var type in processTypes)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var processWorkerLayers = _db.Layers
|
|
|
|
|
.Include(x => x.Records)
|
|
|
|
|
.Where(x =>
|
|
|
|
|
x.Records!.Any(y => y.Code == "Type" && y.Desc1 == "ProcessWorker") &&
|
|
|
|
|
x.Records!.Any(y => y.Code == "IsEnabled" && y.Desc1 == "True") &&
|
|
|
|
|
x.Records!.Any(y => y.Code == "ProcessType" && y.Desc1 == type)
|
|
|
|
|
)
|
|
|
|
|
.OrderBy(x => x.CreatedAt)
|
|
|
|
|
.AsNoTracking()
|
|
|
|
|
.ToList();
|
|
|
|
|
|
|
|
|
|
foreach (var processWorker in processWorkerLayers)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
ProcessLayer(processWorker);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = $"{processWorker.Name}, {processWorker.Id}",
|
|
|
|
|
Type = LogEntryType.Error,
|
|
|
|
|
LogType = LogType.Process,
|
|
|
|
|
Message = e.ToString(),
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = "Process error",
|
|
|
|
|
Type = LogEntryType.Error,
|
|
|
|
|
LogType = LogType.Process,
|
|
|
|
|
Message = e.ToString(),
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Ok();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ProcessLayer(Layer processWorker)
|
|
|
|
|
{
|
|
|
|
|
if (_googleSheetValues == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Google Sheets API not initialized");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var year = processWorker.Records?.SingleOrDefault(x => x.Code == "Year")?.Desc1;
|
|
|
|
|
if (year == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Year record nod found");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var processType = processWorker.Records?.SingleOrDefault(x => x.Code == "ProcessType")?.Desc1;
|
|
|
|
|
switch (processType)
|
|
|
|
|
{
|
|
|
|
|
case null:
|
|
|
|
|
throw new Exception("ProcessType record not found");
|
|
|
|
|
case "T3-SourceYearSummary":
|
|
|
|
|
{
|
2025-06-02 16:54:33 +02:00
|
|
|
var processor = _pluginManager.GetProcessor("T3.SourceYearSummary");
|
|
|
|
|
if (processor == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("T3.SourceYearSummary processor not found");
|
|
|
|
|
}
|
2025-05-31 19:26:02 +02:00
|
|
|
processor.Process(processWorker);
|
|
|
|
|
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = $"{processWorker.Name}, {processWorker.Id}",
|
|
|
|
|
Type = LogEntryType.Info,
|
|
|
|
|
LogType = LogType.Process,
|
|
|
|
|
Message = "Success",
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case "T3-MultiSourceYearSummary":
|
|
|
|
|
{
|
2025-06-02 16:54:33 +02:00
|
|
|
var processor = _pluginManager.GetProcessor("T3.MultiSourceYearSummary");
|
|
|
|
|
if (processor == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("T3.MultiSourceYearSummary processor not found");
|
|
|
|
|
}
|
2025-05-31 19:26:02 +02:00
|
|
|
processor.Process(processWorker);
|
|
|
|
|
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = $"{processWorker.Name}, {processWorker.Id}",
|
|
|
|
|
Type = LogEntryType.Info,
|
|
|
|
|
LogType = LogType.Process,
|
|
|
|
|
Message = "Success",
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case "T3-MultiSourceCopySelectedCodesYearSummary":
|
|
|
|
|
{
|
2025-06-02 16:54:33 +02:00
|
|
|
var processor = _pluginManager.GetProcessor("T3.MultiSourceCopySelectedCodesYearSummary");
|
|
|
|
|
if (processor == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("T3.MultiSourceCopySelectedCodesYearSummary processor not found");
|
|
|
|
|
}
|
2025-05-31 19:26:02 +02:00
|
|
|
processor.Process(processWorker);
|
|
|
|
|
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = $"{processWorker.Name}, {processWorker.Id}",
|
|
|
|
|
Type = LogEntryType.Info,
|
|
|
|
|
LogType = LogType.Process,
|
|
|
|
|
Message = "Success",
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case "T1-R1":
|
|
|
|
|
{
|
2025-06-02 16:54:33 +02:00
|
|
|
var processor = _pluginManager.GetProcessor("T1.R1");
|
|
|
|
|
if (processor == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("T1.R1 processor not found");
|
|
|
|
|
}
|
2025-05-31 19:26:02 +02:00
|
|
|
processor.Process(processWorker);
|
|
|
|
|
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = $"{processWorker.Name}, {processWorker.Id}",
|
|
|
|
|
Type = LogEntryType.Info,
|
|
|
|
|
LogType = LogType.Process,
|
|
|
|
|
Message = "Success",
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case "T4-R2":
|
|
|
|
|
{
|
2025-06-02 16:54:33 +02:00
|
|
|
var processor = _pluginManager.GetProcessor("T4.R2");
|
|
|
|
|
if (processor == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("T4.R2 processor not found");
|
|
|
|
|
}
|
2025-05-31 19:26:02 +02:00
|
|
|
processor.Process(processWorker);
|
|
|
|
|
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = $"{processWorker.Name}, {processWorker.Id}",
|
|
|
|
|
Type = LogEntryType.Info,
|
|
|
|
|
LogType = LogType.Process,
|
|
|
|
|
Message = "Success",
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
case "T1-R3":
|
|
|
|
|
{
|
2025-06-02 16:54:33 +02:00
|
|
|
var processor = _pluginManager.GetProcessor("T1.R3");
|
|
|
|
|
if (processor == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("T1.R3 processor not found");
|
|
|
|
|
}
|
2025-05-31 19:26:02 +02:00
|
|
|
processor.Process(processWorker);
|
|
|
|
|
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = $"{processWorker.Name}, {processWorker.Id}",
|
|
|
|
|
Type = LogEntryType.Info,
|
|
|
|
|
LogType = LogType.Process,
|
|
|
|
|
Message = "Success",
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var month = processWorker.Records?.SingleOrDefault(x => x.Code == "Month")?.Desc1;
|
|
|
|
|
if (month == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Month record not found");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (processType!)
|
|
|
|
|
{
|
|
|
|
|
case "T3-SingleSource":
|
|
|
|
|
{
|
2025-06-02 16:54:33 +02:00
|
|
|
var t3SingleSource = _pluginManager.GetProcessor("T3.SingleSource");
|
|
|
|
|
if (t3SingleSource == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("T3.SingleSource processor not found");
|
|
|
|
|
}
|
2025-05-31 19:26:02 +02:00
|
|
|
t3SingleSource.Process(processWorker);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case "T4-SingleSource":
|
|
|
|
|
{
|
2025-06-02 16:54:33 +02:00
|
|
|
var t4SingleSource = _pluginManager.GetProcessor("T4.SingleSource");
|
|
|
|
|
if (t4SingleSource == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("T4.SingleSource processor not found");
|
|
|
|
|
}
|
2025-05-31 19:26:02 +02:00
|
|
|
t4SingleSource.Process(processWorker);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case "T5-LastValues":
|
|
|
|
|
{
|
2025-06-02 16:54:33 +02:00
|
|
|
var t5LastValues = _pluginManager.GetProcessor("T5.LastValues");
|
|
|
|
|
if (t5LastValues == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("T5.LastValues processor not found");
|
|
|
|
|
}
|
2025-05-31 19:26:02 +02:00
|
|
|
t5LastValues.Process(processWorker);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case "T3-MultiSourceSummary":
|
|
|
|
|
{
|
2025-06-02 16:54:33 +02:00
|
|
|
var t3MultiSourceSummary = _pluginManager.GetProcessor("T3.MultiSourceSummary");
|
|
|
|
|
if (t3MultiSourceSummary == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("T3.MultiSourceSummary processor not found");
|
|
|
|
|
}
|
2025-05-31 19:26:02 +02:00
|
|
|
t3MultiSourceSummary.Process(processWorker);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case "T3-MultiSourceCopySelectedCodes":
|
|
|
|
|
{
|
2025-06-02 16:54:33 +02:00
|
|
|
var t3MultiSourceCopySelectedCode = _pluginManager.GetProcessor("T3.MultiSourceCopySelectedCodes");
|
|
|
|
|
if (t3MultiSourceCopySelectedCode == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("T3.MultiSourceCopySelectedCodes processor not found");
|
|
|
|
|
}
|
2025-05-31 19:26:02 +02:00
|
|
|
t3MultiSourceCopySelectedCode.Process(processWorker);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_logsController.AddEntry(new LogEntry
|
|
|
|
|
{
|
|
|
|
|
Title = $"{processWorker.Name}, {processWorker.Id}",
|
|
|
|
|
Type = LogEntryType.Info,
|
|
|
|
|
LogType = LogType.Process,
|
|
|
|
|
Message = "Success",
|
|
|
|
|
CreatedAt = DateTime.UtcNow
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal void SaveRecords(Guid id, ICollection<Record> records, Guid currentUserId)
|
|
|
|
|
{
|
|
|
|
|
var toDelete = _db.Records.Where(x => x.LayerId == id).ToList();
|
|
|
|
|
if (toDelete.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
_db.Records.RemoveRange(toDelete);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var record in records)
|
|
|
|
|
{
|
|
|
|
|
record.CreatedById = currentUserId;
|
|
|
|
|
record.CreatedAt = DateTime.UtcNow;
|
|
|
|
|
record.ModifiedById = currentUserId;
|
|
|
|
|
record.ModifiedAt = DateTime.UtcNow;
|
|
|
|
|
record.LayerId = id;
|
|
|
|
|
_db.Records.Add(record);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void WriteToConsole(params string[] messages)
|
|
|
|
|
{
|
|
|
|
|
foreach (var message in messages)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine($"DiunaLog: {message}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool IsImportedLayerUpToDate(Layer importWorker)
|
|
|
|
|
{
|
|
|
|
|
if (_googleSheetValues is null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("Google Sheets API not initialized");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var newestLayer = _db.Layers
|
|
|
|
|
.Include(x => x.Records)
|
|
|
|
|
.Where(x => x.ParentId == importWorker.Id)
|
|
|
|
|
.OrderByDescending(x => x.CreatedAt)
|
|
|
|
|
.AsNoTracking()
|
|
|
|
|
.FirstOrDefault();
|
|
|
|
|
|
|
|
|
|
if (newestLayer is null)
|
|
|
|
|
{
|
|
|
|
|
return true; // importWorker is not active yet, no check needed
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var sheetId = importWorker.Records!.FirstOrDefault(x => x.Code == "SheetId")?.Desc1;
|
|
|
|
|
if (sheetId == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception($"SheetId not found, {importWorker.Name}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var sheetTabName = importWorker.Records!.FirstOrDefault(x => x.Code == "SheetTabName")?.Desc1;
|
|
|
|
|
if (sheetTabName == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception($"SheetTabName not found, {importWorker.Name}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var dataRange = importWorker.Records!.FirstOrDefault(x => x.Code == "DataRange")?.Desc1;
|
|
|
|
|
if (dataRange == null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception($"DataRange not found, {importWorker.Name}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var dataRangeResponse = _googleSheetValues.Get(sheetId, $"{sheetTabName}!{dataRange}").Execute();
|
|
|
|
|
var data = dataRangeResponse.Values;
|
|
|
|
|
|
|
|
|
|
var isUpToDate = true;
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < data[1].Count; i++)
|
|
|
|
|
{
|
|
|
|
|
if (data[0][i].ToString() == "") continue;
|
|
|
|
|
var record = newestLayer.Records!.FirstOrDefault(x => x.Code == data[0][i].ToString());
|
|
|
|
|
if (record == null)
|
|
|
|
|
{
|
|
|
|
|
WriteToConsole("Code not found in DiunaBI", data[0][i].ToString()!);
|
|
|
|
|
isUpToDate = false;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!double.TryParse(data[1][i].ToString(), CultureInfo.GetCultureInfo("pl-PL"),
|
|
|
|
|
out var value) ||
|
|
|
|
|
double.Abs((double)(record.Value1 - value)!) < 0.01) continue;
|
|
|
|
|
isUpToDate = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var record in newestLayer.Records!)
|
|
|
|
|
{
|
|
|
|
|
if (data[0].Contains(record.Code))
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WriteToConsole($"Code not found in GoogleSheet: {record.Code}");
|
|
|
|
|
isUpToDate = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return isUpToDate;
|
|
|
|
|
}
|
|
|
|
|
}
|