Wp2ghost/GhostImageManager/Services/GhostApiService.cs

241 lines
9.6 KiB
C#
Raw Permalink Normal View History

2026-09-24 19:23:54 +02:00
using System.Text;
using System.Text.Json;
using GhostImageManager.Models;
namespace GhostImageManager.Services;
public class GhostApiService
{
private readonly HttpClient _httpClient;
2026-09-28 19:09:09 +02:00
private readonly ILogger<GhostApiService> _logger;
2026-09-24 19:23:54 +02:00
2026-09-28 19:09:09 +02:00
public GhostApiService(HttpClient httpClient, ILogger<GhostApiService> logger)
2026-09-24 19:23:54 +02:00
{
_httpClient = httpClient;
2026-09-28 19:09:09 +02:00
_logger = logger;
2026-09-24 19:23:54 +02:00
}
public async Task<List<GhostPost>> GetPostsAsync(GhostInstance instance, string filter = "", int limit = 100)
{
2026-09-28 19:09:09 +02:00
var endpoint = $"posts/?limit={limit}&filter={Uri.EscapeDataString(filter)}&formats=html,plaintext&fields=id,title,slug,feature_image,html,created_at,updated_at,status";
_logger.LogInformation("Hole Posts von {Url} (Filter: {Filter}, Limit: {Limit})", instance.Url, filter, limit);
var request = CreateRequest(HttpMethod.Get, instance, endpoint);
2026-09-24 19:23:54 +02:00
var response = await _httpClient.SendAsync(request);
2026-09-28 19:09:09 +02:00
if (!response.IsSuccessStatusCode)
{
var errorContent = await response.Content.ReadAsStringAsync();
_logger.LogError("Ghost API Fehler beim Laden der Posts: {StatusCode} - {Error}", response.StatusCode, errorContent);
response.EnsureSuccessStatusCode();
}
2026-09-24 19:23:54 +02:00
var json = await response.Content.ReadAsStringAsync();
var doc = JsonDocument.Parse(json);
var posts = new List<GhostPost>();
if (doc.RootElement.TryGetProperty("posts", out var postsElement))
{
foreach (var post in postsElement.EnumerateArray())
{
posts.Add(new GhostPost
{
Id = GetString(post, "id"),
Title = GetString(post, "title"),
Slug = GetString(post, "slug"),
Html = GetString(post, "html"),
FeatureImage = GetString(post, "feature_image"),
CreatedAt = GetDateTime(post, "created_at"),
UpdatedAt = GetDateTime(post, "updated_at"),
Status = GetString(post, "status")
});
}
}
2026-09-28 19:09:09 +02:00
_logger.LogInformation("{Count} Posts von Ghost geladen", posts.Count);
2026-09-24 19:23:54 +02:00
return posts;
}
public async Task<GhostPost?> GetPostAsync(GhostInstance instance, string postId)
{
2026-09-28 19:09:09 +02:00
_logger.LogInformation("Lade Post {PostId} von {Url}", postId, instance.Url);
2026-09-24 19:23:54 +02:00
var request = CreateRequest(HttpMethod.Get, instance, $"posts/{postId}/?fields=id,title,slug,feature_image,html,created_at,updated_at,status");
var response = await _httpClient.SendAsync(request);
2026-09-28 19:09:09 +02:00
if (!response.IsSuccessStatusCode)
{
var errorContent = await response.Content.ReadAsStringAsync();
_logger.LogError("Ghost API Fehler beim Laden von Post {PostId}: {StatusCode} - {Error}", postId, response.StatusCode, errorContent);
return null;
}
2026-09-24 19:23:54 +02:00
var json = await response.Content.ReadAsStringAsync();
var doc = JsonDocument.Parse(json);
if (doc.RootElement.TryGetProperty("posts", out var posts) && posts.GetArrayLength() > 0)
{
var post = posts[0];
return new GhostPost
{
Id = GetString(post, "id"),
Title = GetString(post, "title"),
Slug = GetString(post, "slug"),
Html = GetString(post, "html"),
FeatureImage = GetString(post, "feature_image"),
CreatedAt = GetDateTime(post, "created_at"),
UpdatedAt = GetDateTime(post, "updated_at"),
Status = GetString(post, "status")
};
}
return null;
}
public async Task<bool> UpdatePostAsync(GhostInstance instance, GhostPost post)
{
2026-09-28 19:09:09 +02:00
_logger.LogInformation("Aktualisiere Post {PostId} ({Title}) in Ghost", post.Id, post.Title);
2026-09-24 19:23:54 +02:00
var request = CreateRequest(HttpMethod.Put, instance, $"posts/{post.Id}/?source=html");
var body = new
{
posts = new[]
{
new
{
id = post.Id,
title = post.Title,
html = post.Html,
status = post.Status,
feature_image = post.FeatureImage,
updated_at = post.UpdatedAt?.ToString("o")
}
}
};
request.Content = new StringContent(JsonSerializer.Serialize(body), Encoding.UTF8, "application/json");
var response = await _httpClient.SendAsync(request);
2026-09-28 19:09:09 +02:00
if (!response.IsSuccessStatusCode)
{
var errorContent = await response.Content.ReadAsStringAsync();
_logger.LogError("Ghost API Fehler beim Aktualisieren von Post {PostId}: {StatusCode} - {Error}", post.Id, response.StatusCode, errorContent);
return false;
}
_logger.LogInformation("Post {PostId} erfolgreich aktualisiert", post.Id);
return true;
}
public async Task<List<GhostUser>> GetUsersAsync(GhostInstance instance)
{
_logger.LogInformation("Hole Benutzer von {Url}", instance.Url);
var request = CreateRequest(HttpMethod.Get, instance, "users/?limit=100&fields=id,name,slug,email,profile_image");
var response = await _httpClient.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
var errorContent = await response.Content.ReadAsStringAsync();
_logger.LogError("Ghost API Fehler beim Laden der Benutzer: {StatusCode} - {Error}", response.StatusCode, errorContent);
return new List<GhostUser>();
}
var json = await response.Content.ReadAsStringAsync();
var doc = JsonDocument.Parse(json);
var users = new List<GhostUser>();
if (doc.RootElement.TryGetProperty("users", out var usersElement))
{
foreach (var user in usersElement.EnumerateArray())
{
users.Add(new GhostUser
{
Id = GetString(user, "id"),
Name = GetString(user, "name"),
Slug = GetString(user, "slug"),
Email = GetString(user, "email"),
ProfileImage = GetString(user, "profile_image")
});
}
}
_logger.LogInformation("{Count} Benutzer von Ghost geladen", users.Count);
return users;
2026-09-24 19:23:54 +02:00
}
public async Task<string?> UploadImageAsync(GhostInstance instance, Stream fileStream, string fileName, string? reference = null)
{
2026-09-28 19:09:09 +02:00
_logger.LogInformation("Lade Bild {FileName} zu Ghost hoch", fileName);
2026-09-24 19:23:54 +02:00
var token = JwtTokenService.GenerateToken(instance.AdminApiKey);
var request = new HttpRequestMessage(HttpMethod.Post, $"{instance.Url.TrimEnd('/')}/ghost/api/admin/images/upload/");
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Ghost", token);
request.Headers.Add("Accept-Version", "v5.0");
var content = new MultipartFormDataContent();
var streamContent = new StreamContent(fileStream);
var ext = Path.GetExtension(fileName).ToLowerInvariant();
var mimeType = ext switch
{
".jpg" or ".jpeg" => "image/jpeg",
".png" => "image/png",
".gif" => "image/gif",
".webp" => "image/webp",
".svg" => "image/svg+xml",
_ => "application/octet-stream"
};
streamContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(mimeType);
content.Add(streamContent, "file", fileName);
if (!string.IsNullOrEmpty(reference))
content.Add(new StringContent(reference), "ref");
request.Content = content;
var response = await _httpClient.SendAsync(request);
2026-09-28 19:09:09 +02:00
if (!response.IsSuccessStatusCode)
{
var errorContent = await response.Content.ReadAsStringAsync();
_logger.LogError("Ghost API Fehler beim Hochladen von {FileName}: {StatusCode} - {Error}", fileName, response.StatusCode, errorContent);
return null;
}
2026-09-24 19:23:54 +02:00
var json = await response.Content.ReadAsStringAsync();
var doc = JsonDocument.Parse(json);
if (doc.RootElement.TryGetProperty("images", out var images) && images.GetArrayLength() > 0)
{
2026-09-28 19:09:09 +02:00
var url = GetString(images[0], "url");
_logger.LogInformation("Bild {FileName} hochgeladen: {Url}", fileName, url);
return url;
2026-09-24 19:23:54 +02:00
}
2026-09-28 19:09:09 +02:00
_logger.LogWarning("Keine URL im Upload-Response für {FileName} gefunden", fileName);
2026-09-24 19:23:54 +02:00
return null;
}
private HttpRequestMessage CreateRequest(HttpMethod method, GhostInstance instance, string endpoint)
{
var token = JwtTokenService.GenerateToken(instance.AdminApiKey);
var request = new HttpRequestMessage(method, $"{instance.Url.TrimEnd('/')}/ghost/api/admin/{endpoint}");
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Ghost", token);
request.Headers.Add("Accept-Version", "v5.0");
return request;
}
private static string GetString(JsonElement element, string property)
{
if (element.TryGetProperty(property, out var prop) && prop.ValueKind != JsonValueKind.Null)
return prop.GetString() ?? "";
return "";
}
private static DateTime? GetDateTime(JsonElement element, string property)
{
if (element.TryGetProperty(property, out var prop) && prop.ValueKind != JsonValueKind.Null)
if (DateTime.TryParse(prop.GetString(), out var dt))
return dt;
return null;
}
}