240 lines
9.6 KiB
C#
240 lines
9.6 KiB
C#
using System.Text;
|
|
using System.Text.Json;
|
|
using GhostImageManager.Models;
|
|
|
|
namespace GhostImageManager.Services;
|
|
|
|
public class GhostApiService
|
|
{
|
|
private readonly HttpClient _httpClient;
|
|
private readonly ILogger<GhostApiService> _logger;
|
|
|
|
public GhostApiService(HttpClient httpClient, ILogger<GhostApiService> logger)
|
|
{
|
|
_httpClient = httpClient;
|
|
_logger = logger;
|
|
}
|
|
|
|
public async Task<List<GhostPost>> GetPostsAsync(GhostInstance instance, string filter = "", int limit = 100)
|
|
{
|
|
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);
|
|
var response = await _httpClient.SendAsync(request);
|
|
|
|
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();
|
|
}
|
|
|
|
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")
|
|
});
|
|
}
|
|
}
|
|
|
|
_logger.LogInformation("{Count} Posts von Ghost geladen", posts.Count);
|
|
return posts;
|
|
}
|
|
|
|
public async Task<GhostPost?> GetPostAsync(GhostInstance instance, string postId)
|
|
{
|
|
_logger.LogInformation("Lade Post {PostId} von {Url}", postId, instance.Url);
|
|
|
|
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);
|
|
|
|
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;
|
|
}
|
|
|
|
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)
|
|
{
|
|
_logger.LogInformation("Aktualisiere Post {PostId} ({Title}) in Ghost", post.Id, post.Title);
|
|
|
|
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);
|
|
|
|
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;
|
|
}
|
|
|
|
public async Task<string?> UploadImageAsync(GhostInstance instance, Stream fileStream, string fileName, string? reference = null)
|
|
{
|
|
_logger.LogInformation("Lade Bild {FileName} zu Ghost hoch", fileName);
|
|
|
|
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);
|
|
|
|
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;
|
|
}
|
|
|
|
var json = await response.Content.ReadAsStringAsync();
|
|
var doc = JsonDocument.Parse(json);
|
|
if (doc.RootElement.TryGetProperty("images", out var images) && images.GetArrayLength() > 0)
|
|
{
|
|
var url = GetString(images[0], "url");
|
|
_logger.LogInformation("Bild {FileName} hochgeladen: {Url}", fileName, url);
|
|
return url;
|
|
}
|
|
|
|
_logger.LogWarning("Keine URL im Upload-Response für {FileName} gefunden", fileName);
|
|
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;
|
|
}
|
|
}
|