diff --git a/DysonNetwork.Sphere/ActivityPub/ActivityPubActivityHandler.cs b/DysonNetwork.Sphere/ActivityPub/ActivityPubActivityHandler.cs index de1f2b0..55bb891 100644 --- a/DysonNetwork.Sphere/ActivityPub/ActivityPubActivityHandler.cs +++ b/DysonNetwork.Sphere/ActivityPub/ActivityPubActivityHandler.cs @@ -247,19 +247,22 @@ public class ActivityPubActivityHandler( private async Task HandleUndoAsync(string actorUri, Dictionary activity) { var objectValue = activity.GetValueOrDefault("object"); + var objectDict = ConvertToDictionary(objectValue); - if (objectValue is not Dictionary objectDict) + if (objectDict == null) { logger.LogWarning("Unable undo operation, no object found... {Object}", JsonSerializer.Serialize(activity)); return false; } + + var objectType = GetStringValue(objectDict, "type"); + var objectUri = GetStringValue(objectDict, "object"); - var objectType = objectDict.GetValueOrDefault("type")?.ToString(); return objectType switch { - "Follow" => await UndoFollowAsync(actorUri, objectDict.GetValueOrDefault("object")?.ToString()), - "Like" => await UndoLikeAsync(actorUri, objectDict.GetValueOrDefault("object")?.ToString()), - "Announce" => await UndoAnnounceAsync(actorUri, objectDict.GetValueOrDefault("object")?.ToString()), + "Follow" => await UndoFollowAsync(actorUri, objectUri), + "Like" => await UndoLikeAsync(actorUri, objectUri), + "Announce" => await UndoAnnounceAsync(actorUri, objectUri), _ => throw new InvalidOperationException($"Unhandled undo operation for {objectType}") }; } @@ -267,10 +270,12 @@ public class ActivityPubActivityHandler( private async Task HandleCreateAsync(string actorUri, Dictionary activity) { var objectValue = activity.GetValueOrDefault("object"); - if (objectValue is not Dictionary objectDict) + var objectDict = ConvertToDictionary(objectValue); + + if (objectDict == null) return false; - var objectType = objectDict.GetValueOrDefault("type")?.ToString(); + var objectType = GetStringValue(objectDict, "type"); if (objectType != "Note" && objectType != "Article") { logger.LogInformation("Skipping non-note content type: {Type}", objectType); @@ -279,7 +284,7 @@ public class ActivityPubActivityHandler( var actor = await GetOrCreateActorAsync(actorUri); - var contentUri = objectDict.GetValueOrDefault("id")?.ToString(); + var contentUri = GetStringValue(objectDict, "id"); if (string.IsNullOrEmpty(contentUri)) return false; @@ -298,16 +303,16 @@ public class ActivityPubActivityHandler( FediverseType = objectType == "Article" ? FediverseContentType.FediverseArticle : FediverseContentType.FediverseNote, - Title = objectDict.GetValueOrDefault("name")?.ToString(), - Description = objectDict.GetValueOrDefault("summary")?.ToString(), - Content = objectDict.GetValueOrDefault("content")?.ToString(), + Title = GetStringValue(objectDict, "name"), + Description = GetStringValue(objectDict, "summary"), + Content = GetStringValue(objectDict, "content"), ContentType = objectDict.GetValueOrDefault("contentMap") != null ? PostContentType.Html : PostContentType.Markdown, PublishedAt = ParseInstant(objectDict.GetValueOrDefault("published")), EditedAt = ParseInstant(objectDict.GetValueOrDefault("updated")), ActorId = actor.Id, - Language = objectDict.GetValueOrDefault("language")?.ToString(), + Language = GetStringValue(objectDict, "language"), Mentions = ParseMentions(objectDict.GetValueOrDefault("tag")), Attachments = ParseAttachments(objectDict.GetValueOrDefault("attachment")) ?? [], Type = objectType == "Article" ? PostType.Article : PostType.Moment, @@ -545,6 +550,56 @@ public class ActivityPubActivityHandler( return uriObj.Host; } + private static string? GetStringValue(Dictionary dict, string key) + { + var value = dict.GetValueOrDefault(key); + if (value == null) + return null; + + return value switch + { + string str => str, + JsonElement element => element.ValueKind == JsonValueKind.String ? element.GetString() : element.ToString(), + _ => value.ToString() + }; + } + + private static Dictionary? ConvertToDictionary(object? value) + { + if (value == null) + return null; + + if (value is Dictionary dict) + return dict; + + if (value is JsonElement { ValueKind: JsonValueKind.Object } element) + { + var result = new Dictionary(); + foreach (var property in element.EnumerateObject()) + { + result[property.Name] = ConvertJsonElementToObject(property.Value); + } + return result; + } + + return null; + } + + private static object ConvertJsonElementToObject(JsonElement element) + { + return element.ValueKind switch + { + JsonValueKind.String => element.GetString() ?? string.Empty, + JsonValueKind.Number => element.TryGetInt64(out var longValue) ? longValue : element.GetDouble(), + JsonValueKind.True => true, + JsonValueKind.False => false, + JsonValueKind.Null => null!, + JsonValueKind.Object => ConvertToDictionary(element) ?? new Dictionary(), + JsonValueKind.Array => element.EnumerateArray().Select(ConvertJsonElementToObject).ToList(), + _ => element.ToString() + }; + } + private Instant? ParseInstant(object? value) { if (value == null)