209 lines
8.2 KiB
C#
209 lines
8.2 KiB
C#
using System.Net.Http.Headers;
|
|
using System.Text.Json;
|
|
using ProfileManager.Models;
|
|
|
|
namespace ProfileManager.Services;
|
|
|
|
public sealed class GiteaApiClient
|
|
{
|
|
private readonly HttpClient _httpClient;
|
|
private readonly string _baseUrl;
|
|
private static readonly JsonSerializerOptions JsonOptions = new()
|
|
{
|
|
PropertyNameCaseInsensitive = true
|
|
};
|
|
|
|
public GiteaApiClient(string? baseUrl = null, string? apiToken = null)
|
|
{
|
|
_baseUrl = (baseUrl ?? Environment.GetEnvironmentVariable("GITEA_API_URL") ?? "https://git.webcore-consulting.dev/api/v1")
|
|
.TrimEnd('/');
|
|
|
|
var handler = new SocketsHttpHandler
|
|
{
|
|
PooledConnectionLifetime = TimeSpan.FromMinutes(2),
|
|
ConnectTimeout = TimeSpan.FromSeconds(10)
|
|
};
|
|
|
|
_httpClient = new HttpClient(handler)
|
|
{
|
|
Timeout = TimeSpan.FromSeconds(15)
|
|
};
|
|
|
|
_httpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("NickiProfileBot", "1.0"));
|
|
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
|
|
|
var token = apiToken ?? Environment.GetEnvironmentVariable("GITEA_TOKEN");
|
|
if (!string.IsNullOrWhiteSpace(token))
|
|
{
|
|
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
|
}
|
|
}
|
|
|
|
public async Task<List<HeatmapItem>> GetHeatmapAsync(string username, CancellationToken cancellationToken = default)
|
|
{
|
|
var url = $"{_baseUrl}/users/{Uri.EscapeDataString(username)}/heatmap";
|
|
Console.WriteLine($"[API] Fetching heatmap from: {url}");
|
|
|
|
try
|
|
{
|
|
using var response = await _httpClient.GetAsync(url, cancellationToken);
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
var json = await response.Content.ReadAsStringAsync(cancellationToken);
|
|
var items = JsonSerializer.Deserialize<List<HeatmapItem>>(json, JsonOptions);
|
|
if (items != null && items.Count > 0)
|
|
{
|
|
Console.WriteLine($"[API] Successfully retrieved {items.Count} heatmap data points.");
|
|
return items;
|
|
}
|
|
}
|
|
|
|
Console.ForegroundColor = ConsoleColor.Yellow;
|
|
Console.WriteLine($"[API-WARN] Heatmap request failed (Status: {response.StatusCode}). Switching to mock fallback.");
|
|
Console.ResetColor();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.Yellow;
|
|
Console.WriteLine($"[API-WARN] Network error connecting to Gitea ({ex.Message}). Using realistic fallback data.");
|
|
Console.ResetColor();
|
|
}
|
|
|
|
return GenerateMockHeatmap();
|
|
}
|
|
|
|
public async Task<List<GiteaRepo>> GetReposAsync(string username, CancellationToken cancellationToken = default)
|
|
{
|
|
var url = $"{_baseUrl}/users/{Uri.EscapeDataString(username)}/repos?limit=100&sort=updated";
|
|
Console.WriteLine($"[API] Fetching repositories from: {url}");
|
|
|
|
try
|
|
{
|
|
using var response = await _httpClient.GetAsync(url, cancellationToken);
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
var json = await response.Content.ReadAsStringAsync(cancellationToken);
|
|
var repos = JsonSerializer.Deserialize<List<GiteaRepo>>(json, JsonOptions);
|
|
if (repos != null && repos.Count > 0)
|
|
{
|
|
Console.WriteLine($"[API] Successfully retrieved {repos.Count} repositories.");
|
|
return repos;
|
|
}
|
|
}
|
|
|
|
Console.ForegroundColor = ConsoleColor.Yellow;
|
|
Console.WriteLine($"[API-WARN] Repositories request failed (Status: {response.StatusCode}). Switching to mock fallback.");
|
|
Console.ResetColor();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.Yellow;
|
|
Console.WriteLine($"[API-WARN] Network error connecting to Gitea ({ex.Message}). Using realistic fallback data.");
|
|
Console.ResetColor();
|
|
}
|
|
|
|
return GenerateMockRepos();
|
|
}
|
|
|
|
private static List<HeatmapItem> GenerateMockHeatmap()
|
|
{
|
|
var items = new List<HeatmapItem>();
|
|
var now = DateTimeOffset.UtcNow;
|
|
var random = new Random(42); // Fixed seed for reproducible fallback
|
|
|
|
for (int i = 0; i < 365; i++)
|
|
{
|
|
var day = now.AddDays(-i);
|
|
// Simulate realistic developer habits (more activity on weekdays and active streaks)
|
|
bool isWeekend = day.DayOfWeek is DayOfWeek.Saturday or DayOfWeek.Sunday;
|
|
int chance = isWeekend ? 40 : 75;
|
|
|
|
if (random.Next(100) < chance)
|
|
{
|
|
int commits = random.Next(1, 14);
|
|
items.Add(new HeatmapItem
|
|
{
|
|
Timestamp = day.ToUnixTimeSeconds(),
|
|
Contributions = commits
|
|
});
|
|
}
|
|
}
|
|
|
|
return items;
|
|
}
|
|
|
|
private static List<GiteaRepo> GenerateMockRepos()
|
|
{
|
|
var now = DateTime.UtcNow;
|
|
return
|
|
[
|
|
new GiteaRepo
|
|
{
|
|
Name = "Markdown-Editor-Pro",
|
|
FullName = "NickiCloud/Markdown-Editor-Pro",
|
|
Description = "Moderner, performanter Markdown-Editor mit Live-Vorschau, Syntax-Highlighting & LaTeX-Support auf Avalonia UI.",
|
|
HtmlUrl = "https://git.webcore-consulting.dev/NickiCloud/Markdown-Editor-Pro",
|
|
Language = "C#",
|
|
StarsCount = 7,
|
|
ForksCount = 1,
|
|
UpdatedAt = now.AddHours(-3)
|
|
},
|
|
new GiteaRepo
|
|
{
|
|
Name = "CloudDrop",
|
|
FullName = "NickiCloud/CloudDrop",
|
|
Description = "Leichtgewichtiger, selbstgehosteter File-Sharing-Dienst mit temporären Download-Links und verschlüsselter Ablage.",
|
|
HtmlUrl = "https://git.webcore-consulting.dev/NickiCloud/CloudDrop",
|
|
Language = "C#",
|
|
StarsCount = 5,
|
|
ForksCount = 0,
|
|
UpdatedAt = now.AddDays(-2)
|
|
},
|
|
new GiteaRepo
|
|
{
|
|
Name = "KasseApp",
|
|
FullName = "NickiCloud/KasseApp",
|
|
Description = "Intuitive Kassen- und Abrechnungssoftware für Vereine und Events mit Offline-First SQLite-Datenbank.",
|
|
HtmlUrl = "https://git.webcore-consulting.dev/NickiCloud/KasseApp",
|
|
Language = "C#",
|
|
StarsCount = 4,
|
|
ForksCount = 0,
|
|
UpdatedAt = now.AddDays(-5)
|
|
},
|
|
new GiteaRepo
|
|
{
|
|
Name = "DrinkReminder",
|
|
FullName = "NickiCloud/DrinkReminder",
|
|
Description = "Smarter Tray-Assistent für Desktop & Mobile zur Erinnerung an regelmäßige Flüssigkeitszufuhr.",
|
|
HtmlUrl = "https://git.webcore-consulting.dev/NickiCloud/DrinkReminder",
|
|
Language = "C#",
|
|
StarsCount = 3,
|
|
ForksCount = 0,
|
|
UpdatedAt = now.AddDays(-12)
|
|
},
|
|
new GiteaRepo
|
|
{
|
|
Name = "Selfhosted-Infra",
|
|
FullName = "NickiCloud/Selfhosted-Infra",
|
|
Description = "Docker-Compose & Konfigurationen für Debian, Gitea, Mailcow, Nginx Reverse Proxy, UFW & Fail2ban.",
|
|
HtmlUrl = "https://git.webcore-consulting.dev/NickiCloud/Selfhosted-Infra",
|
|
Language = "Shell",
|
|
StarsCount = 6,
|
|
ForksCount = 0,
|
|
UpdatedAt = now.AddDays(-18)
|
|
},
|
|
new GiteaRepo
|
|
{
|
|
Name = "WebCore-Portal",
|
|
FullName = "NickiCloud/WebCore-Portal",
|
|
Description = "Interaktives Service-Portal mit MudBlazor Komponenten und JWT-Authentifizierung.",
|
|
HtmlUrl = "https://git.webcore-consulting.dev/NickiCloud/WebCore-Portal",
|
|
Language = "HTML",
|
|
StarsCount = 2,
|
|
ForksCount = 0,
|
|
UpdatedAt = now.AddDays(-25)
|
|
}
|
|
];
|
|
}
|
|
}
|