using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Text; using System.Text.Json; using System.Threading.Tasks; namespace TrelloIntegration { /// /// Trello-Karten-Client für WinForms-Anwendungen (.NET Framework 4.8, C# 7.3) /// Erstellt Karten via Trello REST API über HttpClient. /// public class TrelloCardClient : IDisposable { private readonly string _apiKey; private readonly string _token; private readonly HttpClient _httpClient; /// /// Initialisiert einen neuen TrelloCardClient. /// /// Trello API Key /// Trello API Token mit write-Recht public TrelloCardClient(string apiKey, string token) { _apiKey = apiKey ?? throw new ArgumentNullException(nameof(apiKey)); _token = token ?? throw new ArgumentNullException(nameof(token)); _httpClient = new HttpClient { BaseAddress = new Uri("https://api.trello.com/1/") }; } /// /// Erstellt eine neue Trello-Karte asynchron und gibt die Roh-JSON-Antwort zurück. /// /// Konfiguration der Karte (Name, Liste, Beschreibung, Labels, DueDate, StartDate) /// Antwort-JSON als String (enthaltend die erstellte Karte) public async Task CreateCardAsync(CreateCardOptions options) { ValidateOptions(options); var values = new Dictionary { ["key"] = _apiKey, ["token"] = _token, ["idList"] = options.IdList, ["name"] = options.Name }; if (!string.IsNullOrWhiteSpace(options.Desc)) values["desc"] = options.Desc; if (!string.IsNullOrWhiteSpace(options.Pos)) values["pos"] = options.Pos; if (options.IdLabels != null && options.IdLabels.Count > 0) values["idLabels"] = string.Join(",", options.IdLabels); if (options.DueDate.HasValue) values["due"] = options.DueDate.Value.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm"); if (options.StartDate.HasValue) values["start"] = options.StartDate.Value.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm"); var content = new FormUrlEncodedContent(values); var response = await _httpClient.PostAsync("cards", content); var responseBody = await response.Content.ReadAsStringAsync(); if (!response.IsSuccessStatusCode) { throw new HttpRequestException( $"Trello API Fehler {response.StatusCode}: {responseBody}"); } return responseBody; } /// /// Erstellt eine Karte und gibt das Ergebnis als TrelloCard-Objekt zurück. /// public async Task CreateCardAndParseAsync(CreateCardOptions options) { var json = await CreateCardAsync(options); return ParseTrelloCard(json); } private static TrelloCard ParseTrelloCard(string json) { // Minimaler Parser ohne System.Text.Json (für .NET Framework 4.8) // Extrahiert die wichtigsten Felder aus der JSON-Antwort var card = new TrelloCard(); card.Id = ExtractJsonValue(json, "id"); card.Name = ExtractJsonValue(json, "name"); card.Desc = ExtractJsonValue(json, "desc"); card.IdList = ExtractJsonValue(json, "idList"); card.ShortUrl = ExtractJsonValue(json, "shortUrl"); var due = ExtractJsonValue(json, "due"); if (!string.IsNullOrWhiteSpace(due)) if (DateTime.TryParse(due, out var dtDue)) card.DueDate = dtDue; else card.DueDate = null; var start = ExtractJsonValue(json, "start"); if (!string.IsNullOrWhiteSpace(start)) if (DateTime.TryParse(start, out var dtStart)) card.StartDate = dtStart; else card.StartDate = null; return card; } private static string ExtractJsonValue(string json, string key) { // Einfacher JSON-String-Extractor für "key": "value" var pattern = "\"" + key + "\"\\s*:\\s*\""; var startIndex = json.IndexOf(pattern, StringComparison.Ordinal); if (startIndex < 0) return null; startIndex += pattern.Length; var endIndex = json.IndexOf("\"", startIndex); if (endIndex < 0) return null; return json.Substring(startIndex, endIndex - startIndex); } private void ValidateOptions(CreateCardOptions options) { if (options == null) throw new ArgumentNullException(nameof(options)); if (string.IsNullOrWhiteSpace(options.Name)) throw new ArgumentException("Name ist erforderlich.", nameof(options.Name)); if (string.IsNullOrWhiteSpace(options.IdList)) throw new ArgumentException("IdList ist erforderlich.", nameof(options.IdList)); } /// /// Gibt die Ressourcen des Clients frei (empiohlen). /// public void Dispose() { _httpClient?.Dispose(); } } }