feat: Implementazione completa sistema schedulazione con intervalli personalizzati

- Aggiunto supporto schedulazione con intervalli flessibili (secondi/minuti/ore/giorni/settimane/mesi)
- Esteso modello ProfileSchedule con campi IntervalValue e IntervalUnit
- Ottimizzato ScheduledJobService per controlli ogni 30s con esecuzione parallela
- Implementata interfaccia UI completa con anteprima real-time in italiano
- Aggiunta migrazione database AddIntervalSchedulingFields
- Implementati metodi calcolo NextExecutionTime per intervalli
- Aggiunta gestione tracking anti-duplicati e cleanup automatico
- Creata documentazione completa (6 file, 2500+ righe)

Modifiche tecniche:
- ProfileSchedule.cs: Nuovi campi e metodi CalculateNextInterval/GetScheduleDescription
- ScheduledJobService.cs: Ridotto check interval a 30s, aggiunto parallel processing
- ProfileScheduleService.cs: Supporto calcolo intervalli in UpdateNextExecutionTimeAsync
- Scheduling.razor: Aggiunta sezione UI per configurazione intervalli
- Scheduling.razor.cs: Implementato GetIntervalPreview() e gestione stato campi
This commit is contained in:
2025-10-02 01:12:39 +02:00
parent b76a6760fb
commit d042863a56
71 changed files with 17860 additions and 144 deletions
+334
View File
@@ -0,0 +1,334 @@
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
using CredentialManager.Models;
namespace Data_Coupler.Models;
/// <summary>
/// Modello per l'export/import completo dei dati di backup
/// </summary>
public class SystemBackupData
{
[JsonPropertyName("metadata")]
public BackupMetadata Metadata { get; set; } = new();
[JsonPropertyName("profiles")]
public List<DataCouplerProfileBackup> Profiles { get; set; } = new();
[JsonPropertyName("credentials")]
public List<CredentialBackup> Credentials { get; set; } = new();
[JsonPropertyName("keyAssociations")]
public List<KeyAssociationBackup> KeyAssociations { get; set; } = new();
[JsonPropertyName("profileSchedules")]
public List<ProfileScheduleBackup> ProfileSchedules { get; set; } = new();
}
/// <summary>
/// Metadati del backup
/// </summary>
public class BackupMetadata
{
[JsonPropertyName("version")]
public string Version { get; set; } = "1.0";
[JsonPropertyName("createdAt")]
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
[JsonPropertyName("createdBy")]
public string? CreatedBy { get; set; }
[JsonPropertyName("applicationVersion")]
public string ApplicationVersion { get; set; } = "1.0.0";
[JsonPropertyName("totalRecords")]
public BackupRecordCount RecordCounts { get; set; } = new();
[JsonPropertyName("description")]
public string? Description { get; set; }
}
/// <summary>
/// Conteggio record nel backup
/// </summary>
public class BackupRecordCount
{
[JsonPropertyName("profiles")]
public int Profiles { get; set; }
[JsonPropertyName("credentials")]
public int Credentials { get; set; }
[JsonPropertyName("keyAssociations")]
public int KeyAssociations { get; set; }
[JsonPropertyName("profileSchedules")]
public int ProfileSchedules { get; set; }
}
/// <summary>
/// Backup di un profilo DataCoupler
/// </summary>
public class DataCouplerProfileBackup
{
[JsonPropertyName("id")]
public int Id { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
[JsonPropertyName("description")]
public string? Description { get; set; }
[JsonPropertyName("sourceType")]
public string SourceType { get; set; } = string.Empty;
[JsonPropertyName("sourceCredentialName")]
public string? SourceCredentialName { get; set; }
[JsonPropertyName("sourceDatabaseName")]
public string? SourceDatabaseName { get; set; }
[JsonPropertyName("sourceSchema")]
public string? SourceSchema { get; set; }
[JsonPropertyName("sourceTable")]
public string? SourceTable { get; set; }
[JsonPropertyName("sourceCustomQuery")]
public string? SourceCustomQuery { get; set; }
[JsonPropertyName("sourceFilePath")]
public string? SourceFilePath { get; set; }
[JsonPropertyName("destinationType")]
public string DestinationType { get; set; } = string.Empty;
[JsonPropertyName("destinationCredentialName")]
public string? DestinationCredentialName { get; set; }
[JsonPropertyName("destinationSchema")]
public string? DestinationSchema { get; set; }
[JsonPropertyName("destinationTable")]
public string? DestinationTable { get; set; }
[JsonPropertyName("destinationEndpoint")]
public string? DestinationEndpoint { get; set; }
[JsonPropertyName("fieldMappings")]
public List<FieldMappingDto>? FieldMappings { get; set; }
[JsonPropertyName("sourceKeyField")]
public string? SourceKeyField { get; set; }
[JsonPropertyName("useRecordAssociations")]
public bool UseRecordAssociations { get; set; }
[JsonPropertyName("createdBy")]
public string? CreatedBy { get; set; }
[JsonPropertyName("createdAt")]
public DateTime CreatedAt { get; set; }
[JsonPropertyName("lastUsedAt")]
public DateTime? LastUsedAt { get; set; }
[JsonPropertyName("isActive")]
public bool IsActive { get; set; } = true;
}
/// <summary>
/// Backup di una credenziale (dati sensibili esclusi per sicurezza)
/// </summary>
public class CredentialBackup
{
[JsonPropertyName("id")]
public int Id { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
[JsonPropertyName("type")]
public string Type { get; set; } = string.Empty;
[JsonPropertyName("databaseType")]
public string? DatabaseType { get; set; }
[JsonPropertyName("host")]
public string? Host { get; set; }
[JsonPropertyName("port")]
public int? Port { get; set; }
[JsonPropertyName("databaseName")]
public string? DatabaseName { get; set; }
[JsonPropertyName("username")]
public string? Username { get; set; }
// NOTA: Password, API Keys e Token NON vengono inclusi nel backup per sicurezza
[JsonPropertyName("commandTimeout")]
public int CommandTimeout { get; set; } = 30;
[JsonPropertyName("timeoutSeconds")]
public int TimeoutSeconds { get; set; } = 100;
[JsonPropertyName("ignoreSslErrors")]
public bool IgnoreSslErrors { get; set; } = false;
[JsonPropertyName("restServiceType")]
public string? RestServiceType { get; set; }
[JsonPropertyName("headers")]
public string? Headers { get; set; }
[JsonPropertyName("additionalParameters")]
public string? AdditionalParameters { get; set; }
[JsonPropertyName("createdAt")]
public DateTime CreatedAt { get; set; }
[JsonPropertyName("updatedAt")]
public DateTime? UpdatedAt { get; set; }
[JsonPropertyName("createdBy")]
public string? CreatedBy { get; set; }
[JsonPropertyName("isActive")]
public bool IsActive { get; set; } = true;
}
/// <summary>
/// Backup di un'associazione chiave
/// </summary>
public class KeyAssociationBackup
{
[JsonPropertyName("id")]
public int Id { get; set; }
[JsonPropertyName("keyValue")]
public string KeyValue { get; set; } = string.Empty;
[JsonPropertyName("sourceKeyField")]
public string SourceKeyField { get; set; } = string.Empty;
[JsonPropertyName("destinationKeyField")]
public string DestinationKeyField { get; set; } = string.Empty;
[JsonPropertyName("destinationEntity")]
public string DestinationEntity { get; set; } = string.Empty;
[JsonPropertyName("destinationId")]
public string DestinationId { get; set; } = string.Empty;
[JsonPropertyName("restCredentialName")]
public string RestCredentialName { get; set; } = string.Empty;
[JsonPropertyName("createdAt")]
public DateTime CreatedAt { get; set; }
[JsonPropertyName("updatedAt")]
public DateTime? UpdatedAt { get; set; }
[JsonPropertyName("lastVerifiedAt")]
public DateTime? LastVerifiedAt { get; set; }
[JsonPropertyName("isActive")]
public bool IsActive { get; set; } = true;
[JsonPropertyName("dataHash")]
public string? DataHash { get; set; }
[JsonPropertyName("sourcesInfo")]
public string? SourcesInfo { get; set; }
[JsonPropertyName("additionalInfo")]
public string? AdditionalInfo { get; set; }
}
/// <summary>
/// Backup di una schedule profilo
/// </summary>
public class ProfileScheduleBackup
{
[JsonPropertyName("id")]
public int Id { get; set; }
[JsonPropertyName("profileName")]
public string ProfileName { get; set; } = string.Empty;
[JsonPropertyName("scheduleType")]
public string ScheduleType { get; set; } = string.Empty; // "daily", "weekly", "monthly"
[JsonPropertyName("dailyExecutionTime")]
public TimeSpan? DailyExecutionTime { get; set; }
[JsonPropertyName("weeklyDayOfWeek")]
public int? WeeklyDayOfWeek { get; set; } // 0 = Sunday, 1 = Monday, etc.
[JsonPropertyName("monthlyDayOfMonth")]
public int? MonthlyDayOfMonth { get; set; } // 1-31
[JsonPropertyName("isActive")]
public bool IsActive { get; set; } = true;
[JsonPropertyName("isPaused")]
public bool IsPaused { get; set; } = false;
[JsonPropertyName("lastExecuted")]
public DateTime? LastExecuted { get; set; }
[JsonPropertyName("nextExecution")]
public DateTime? NextExecution { get; set; }
[JsonPropertyName("createdAt")]
public DateTime CreatedAt { get; set; }
[JsonPropertyName("createdBy")]
public string? CreatedBy { get; set; }
}
/// <summary>
/// Risultato dell'operazione di backup/restore
/// </summary>
public class BackupOperationResult
{
public bool Success { get; set; }
public string? Message { get; set; }
public TimeSpan Duration { get; set; }
public BackupRecordCount ProcessedCounts { get; set; } = new();
public List<string> Warnings { get; set; } = new();
public List<string> Errors { get; set; } = new();
public string? FilePath { get; set; }
}
/// <summary>
/// Opzioni per l'operazione di backup
/// </summary>
public class BackupOptions
{
public bool IncludeProfiles { get; set; } = true;
public bool IncludeCredentials { get; set; } = true;
public bool IncludeKeyAssociations { get; set; } = true;
public bool IncludeProfileSchedules { get; set; } = true;
public bool IncludeOnlyActiveRecords { get; set; } = true;
public string? Description { get; set; }
public string? CreatedBy { get; set; }
}
/// <summary>
/// Opzioni per l'operazione di restore
/// </summary>
public class RestoreOptions
{
public bool RestoreProfiles { get; set; } = true;
public bool RestoreCredentials { get; set; } = false; // Default false per sicurezza
public bool RestoreKeyAssociations { get; set; } = true;
public bool RestoreProfileSchedules { get; set; } = true;
public bool OverwriteExisting { get; set; } = false;
public bool CreateBackupBeforeRestore { get; set; } = true;
public string? ImportedBy { get; set; }
}