diff --git a/ContagemLigacoes.csproj b/ContagemLigacoes.csproj new file mode 100644 index 0000000..9b8fea5 --- /dev/null +++ b/ContagemLigacoes.csproj @@ -0,0 +1,16 @@ + + + + Exe + net9.0-windows + enable + enable + none + + + + + + + + diff --git a/ContagemLigacoes.sln b/ContagemLigacoes.sln new file mode 100644 index 0000000..5d4f035 --- /dev/null +++ b/ContagemLigacoes.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.12.35527.113 d17.12 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ContagemLigacoes", "ContagemLigacoes.csproj", "{BE025921-A746-4E01-903F-E04A1C91A85A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BE025921-A746-4E01-903F-E04A1C91A85A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BE025921-A746-4E01-903F-E04A1C91A85A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BE025921-A746-4E01-903F-E04A1C91A85A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BE025921-A746-4E01-903F-E04A1C91A85A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..0a89c39 --- /dev/null +++ b/Program.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections.Generic; +using System.Numerics; +using System.Threading.Tasks; +using Npgsql; +using Spectre.Console; + +class Program +{ + static DateTime _endTime; + static bool _stop = false; + static bool _isAuthenticated = false; + static readonly string _connectionString = "Server=192.168.10.248;Port=5432;Database=pipefy_move_cards;User Id=postgres;Password=gds21;"; + static readonly string _windowsID = Environment.UserName; + // Agora guardamos uma lista de tuplas (UserID, Nome) + static readonly List<(BigInteger UserId, string Nome)> _pipeUsers = new(); + + static void Main() + { + AnsiConsole.Clear(); + + // 1) Autenticação (pode retornar múltiplos usuários) + Autenticacao(); + + if (!_isAuthenticated) + { + AnsiConsole.MarkupLine("[bold red]Nenhum usuário encontrado ou erro na autenticação. Saindo...[/]"); + Console.ReadLine(); + return; + } + + // 2) Loop principal: atualizar dados e aguardar entrada + while (!_stop) + { + AtualizarDados(); + AguardarEntrada(); + } + + AnsiConsole.MarkupLine("[bold yellow]Aplicação encerrada.[/]"); + } + + static void Autenticacao() + { + AnsiConsole.Status() + .Spinner(Spinner.Known.Dots) + .Start("[green]Autenticando usuário...[/]", ctx => + { + const string query = @" + SELECT ""UserID"", ""Nome"" + FROM public.""usuarios"" + WHERE ""windowsID"" = @WindowsID"; + + try + { + using var conn = new NpgsqlConnection(_connectionString); + conn.Open(); + using var cmd = new NpgsqlCommand(query, conn); + cmd.Parameters.AddWithValue("@WindowsID", _windowsID); + + using var reader = cmd.ExecuteReader(); + while (reader.Read()) + { + var userId = BigInteger.Parse(reader["UserID"].ToString()!); + var nome = reader["Nome"].ToString()!; + _pipeUsers.Add((userId, nome)); + } + + if (_pipeUsers.Count > 0) + { + _isAuthenticated = true; + } + else + { + AnsiConsole.MarkupLine("[bold red]Nenhum usuário encontrado para este WindowsID.[/]"); + _isAuthenticated = false; + } + } + catch (Exception ex) + { + AnsiConsole.MarkupLine($"\n[red]Erro na autenticação:[/] {ex.Message}"); + _isAuthenticated = false; + } + }); + } + + static void AtualizarDados() + { + AnsiConsole.Clear(); + + // Painel de cabeçalho que mostra quantos usuários foram carregados + var header = new Panel($"[bold]WindowsID[/]: {_windowsID} • [bold]Usuários encontrados[/]: {_pipeUsers.Count}") + .Header("[yellow]Resumo Diário por Usuário[/]") + .Expand(); + AnsiConsole.Write(header); + + // Montamos uma tabela com: Nome do usuário | UserID | Registros Hoje + var table = new Table().Border(TableBorder.Rounded); + table.AddColumn("[green]Nome[/]"); + table.AddColumn("[green]UserID[/]"); + table.AddColumn("[green]Registros Hoje[/]"); + + // Para cada usuário, rodar uma query COUNT(*) e adicionar linha na tabela + foreach (var (userId, nome) in _pipeUsers) + { + int count = 0; + AnsiConsole.Status() + .Spinner(Spinner.Known.Line) + .Start($"[blue]Obtendo registros de [yellow]{nome}[/]...[/]", ctx => + { + const string query = @" + SELECT COUNT(*) + FROM public.""ActionsHistory"" + WHERE ""UserID"" = @pipeUser + AND ""MovedAt"" > CURRENT_DATE + AND ""FieldID"" IS NOT NULL"; + try + { + using var conn = new NpgsqlConnection(_connectionString); + conn.Open(); + using var cmd = new NpgsqlCommand(query, conn); + cmd.Parameters.AddWithValue("@pipeUser", userId); + count = Convert.ToInt32(cmd.ExecuteScalar()); + } + catch (Exception ex) + { + // Em caso de erro, exibimos zero e continuamos + count = 0; + AnsiConsole.MarkupLine($"\n[red]Erro ao consultar {nome}:[/] {ex.Message}"); + } + }); + + table.AddRow(nome, userId.ToString(), $"[bold yellow]{count}[/]"); + } + + AnsiConsole.Write(table); + + AnsiConsole.MarkupLine("\n[gray]Pressione [green]ENTER[/] para atualizar agora ou qualquer outra tecla para sair.[/]"); + } + + static void AguardarEntrada() + { + // Tempo de espera em segundos (ex.: 10 minutos = 600s) + int intervalSeconds = 600; + _endTime = DateTime.Now.AddSeconds(intervalSeconds); + + // Escreve uma linha em branco para “reservar” o lugar do contador + AnsiConsole.WriteLine(""); + + // Começa o loop que vai atualizar a mesma linha a cada segundo + while (!_stop) + { + var remaining = _endTime - DateTime.Now; + + if (remaining.TotalMilliseconds <= 0) + { + // Quando chegar a zero, exibe a mensagem de atualização automática + AnsiConsole.MarkupLine("\r[red]Atualização automática agora![/]"); + Thread.Sleep(1000); + break; + } + + // Monta o texto de “Próxima atualização em MM:SS” + AnsiConsole.Markup($"\r[blue]Próxima atualização em {remaining.Minutes:00}:{remaining.Seconds:00}[/]"); + + // Pequena pausa de 1 segundo + Thread.Sleep(1000); + + // Se o usuário apertar qualquer tecla… + if (Console.KeyAvailable) + { + var key = Console.ReadKey(true); + // …e não for ENTER, sinalizamos para parar o loop e sair + if (key.Key != ConsoleKey.Enter) + _stop = true; + else + break; + } + } + + // Garante que, ao sair do loop, o cursor fique embaixo do texto + Console.WriteLine(""); + } + +}