diff --git a/BackupPipefy.Application/Services/BackupService.cs b/BackupPipefy.Application/Services/BackupService.cs new file mode 100644 index 0000000..6fec736 --- /dev/null +++ b/BackupPipefy.Application/Services/BackupService.cs @@ -0,0 +1,79 @@ +using BackupPipefy.Domain.Entities; +using BackupPipefy.Infrastructure.Data; +using BackupPipefy.Infrastructure.Services; +using Microsoft.EntityFrameworkCore; + +public class BackupService +{ + private readonly PipefyClient _client; + private readonly BackupContext _context; + private readonly int _requestsPerMinute; + + public BackupService(PipefyClient client, BackupContext context, int requestsPerMinute) + { + _client = client; + _context = context; + _requestsPerMinute = requestsPerMinute; + } + + public async Task RunBackup(int pipeId) + { + var control = await _context.BackupControls.FirstOrDefaultAsync(); + if (control == null) + { + control = new BackupControl { LastBackupTime = DateTime.MinValue }; + _context.BackupControls.Add(control); + await _context.SaveChangesAsync(); + } + + DateTime startTime = DateTime.Now; + + string json = await _client.GetCardsAsync(pipeId, control.LastBackupTime); + + var doc = System.Text.Json.JsonDocument.Parse(json); + var edges = doc.RootElement.GetProperty("data") + .GetProperty("allCards") + .GetProperty("edges"); + + int count = 0; + int delayMs = (int)(60000 / _requestsPerMinute); + + foreach (var edge in edges.EnumerateArray()) + { + var node = edge.GetProperty("node"); + long id = long.Parse(node.GetProperty("id").GetString()); + + var card = await _context.PipefyCards.FindAsync(id); + if (card != null) + { + card.JsonData = node.GetRawText(); + } + else + { + await _context.PipefyCards.AddAsync(new PipefyCard + { + Id = id, + JsonData = node.GetRawText() + }); + } + + count++; + await Task.Delay(delayMs); + } + + await _context.SaveChangesAsync(); + + // Atualiza o controle de backup + control.LastBackupTime = startTime; + await _context.SaveChangesAsync(); + + // Grava log + _context.BackupLogs.Add(new BackupLog + { + ExecutionTime = startTime, + Status = "SUCCESS", + RecordsProcessed = count + }); + await _context.SaveChangesAsync(); + } +} diff --git a/BackupPipefy.Domain/BackupPipefy.Domain.csproj b/BackupPipefy.Domain/BackupPipefy.Domain.csproj index 125f4c9..9ba7383 100644 --- a/BackupPipefy.Domain/BackupPipefy.Domain.csproj +++ b/BackupPipefy.Domain/BackupPipefy.Domain.csproj @@ -6,4 +6,8 @@ enable + + + + diff --git a/BackupPipefy.Domain/Entities/BackupLog.cs b/BackupPipefy.Domain/Entities/BackupLog.cs index e8d66e0..27eb61f 100644 --- a/BackupPipefy.Domain/Entities/BackupLog.cs +++ b/BackupPipefy.Domain/Entities/BackupLog.cs @@ -1,12 +1,13 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace BackupPipefy.Domain.Entities { - internal class BackupLog + public class BackupLog { + public int LogId { get; set; } + public DateTime ExecutionTime { get; set; } = DateTime.Now; + public string Status { get; set; } + public int RecordsProcessed { get; set; } + public string ErrorMessage { get; set; } } } diff --git a/BackupPipefy.Domain/Entities/PipefyCard.cs b/BackupPipefy.Domain/Entities/PipefyCard.cs index 36eae0a..148ee7c 100644 --- a/BackupPipefy.Domain/Entities/PipefyCard.cs +++ b/BackupPipefy.Domain/Entities/PipefyCard.cs @@ -1,12 +1,10 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace BackupPipefy.Domain.Entities { - internal class PipefyCard + public class PipefyCard { + public long Id { get; set; } // ID do card + public string JsonData { get; set; } // JSON bruto retornado pelo GraphQL } } diff --git a/BackupPipefy.Infrastructure/Data/BackupContext.cs b/BackupPipefy.Infrastructure/Data/BackupContext.cs index 4a60f97..d725db5 100644 --- a/BackupPipefy.Infrastructure/Data/BackupContext.cs +++ b/BackupPipefy.Infrastructure/Data/BackupContext.cs @@ -1,12 +1,26 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using BackupPipefy.Domain.Entities; namespace BackupPipefy.Infrastructure.Data { - internal class BackupContext + public class BackupContext : DbContext { + public DbSet PipefyCards { get; set; } + public DbSet BackupLogs { get; set; } + public DbSet BackupControls { get; set; } + + public BackupContext(DbContextOptions options) : base(options) { } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .HasKey(c => c.Id); + + modelBuilder.Entity() + .HasKey(l => l.LogId); + + modelBuilder.Entity() + .HasKey(c => c.Id); + } } } diff --git a/BackupPipefy.Infrastructure/Services/PipefyClient.cs b/BackupPipefy.Infrastructure/Services/PipefyClient.cs new file mode 100644 index 0000000..e99e4a1 --- /dev/null +++ b/BackupPipefy.Infrastructure/Services/PipefyClient.cs @@ -0,0 +1,27 @@ +namespace BackupPipefy.Infrastructure.Services +{ + public class PipefyClient + { + private readonly HttpClient _httpClient; + + public PipefyClient(string apiToken) + { + _httpClient = new HttpClient(); + _httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiToken}"); + } + + public async Task GetCardsAsync(int pipeId, DateTime? lastUpdated = null) + { + // Aqui você vai montar sua query GraphQL real + string query = "{ allCards { edges { node { id updated_at } } } }"; + + var payload = new { query }; + var content = new StringContent(System.Text.Json.JsonSerializer.Serialize(payload), System.Text.Encoding.UTF8, "application/json"); + + var response = await _httpClient.PostAsync("https://api.pipefy.com/graphql", content); + response.EnsureSuccessStatusCode(); + + return await response.Content.ReadAsStringAsync(); + } + } +} \ No newline at end of file