From 1a8bcb5bf953d199d093a23cc303f6fc94841422 Mon Sep 17 00:00:00 2001 From: Melroy van den Berg Date: Thu, 24 Apr 2025 16:16:47 +0200 Subject: [PATCH] Add poll results in case of a question type --- formatter/formatter.go | 138 +++++++++++++++++++++++------------------ 1 file changed, 78 insertions(+), 60 deletions(-) diff --git a/formatter/formatter.go b/formatter/formatter.go index 9d6e8d8..91614ea 100644 --- a/formatter/formatter.go +++ b/formatter/formatter.go @@ -32,25 +32,25 @@ func Format(data map[string]interface{}) (string, error) { // createSummary generates a human-readable summary of the ActivityPub object func createSummary(jsonStr string) string { objectType := gjson.Get(jsonStr, "type").String() - + // Build a header with the object type bold := color.New(color.Bold).SprintFunc() cyan := color.New(color.FgCyan).SprintFunc() green := color.New(color.FgGreen).SprintFunc() yellow := color.New(color.FgYellow).SprintFunc() red := color.New(color.FgRed).SprintFunc() - + header := fmt.Sprintf("%s: %s\n", bold("Type"), cyan(objectType)) - + // Add common fields var summaryParts []string summaryParts = append(summaryParts, header) - + // Add ID if available if id := gjson.Get(jsonStr, "id").String(); id != "" { summaryParts = append(summaryParts, fmt.Sprintf("%s: %s", bold("ID"), green(id))) } - + // Process based on type switch objectType { case "Person", "Application", "Group", "Organization", "Service": @@ -68,7 +68,7 @@ func createSummary(jsonStr string) string { case "Tombstone": summaryParts = formatTombstone(jsonStr, summaryParts, bold, green) } - + return strings.Join(summaryParts, "\n") } @@ -77,31 +77,31 @@ func formatActor(jsonStr string, parts []string, bold, cyan, green, red, yellow if name := gjson.Get(jsonStr, "name").String(); name != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("Name"), cyan(name))) } - + if preferredUsername := gjson.Get(jsonStr, "preferredUsername").String(); preferredUsername != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("Username"), red(preferredUsername))) } - + if url := gjson.Get(jsonStr, "url").String(); url != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("URL"), green(url))) } - + if summary := gjson.Get(jsonStr, "summary").String(); summary != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("Summary"), summary)) } - + if published := gjson.Get(jsonStr, "published").String(); published != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("Published"), yellow(formatDate(published)))) } - + if followers := gjson.Get(jsonStr, "followers").String(); followers != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("Followers"), green(followers))) } - + if following := gjson.Get(jsonStr, "following").String(); following != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("Following"), green(following))) } - + return parts } @@ -115,7 +115,7 @@ func formatContent(jsonStr string, parts []string, bold, green func(a ...interfa } parts = append(parts, fmt.Sprintf("%s: %s", bold("Content"), content)) } - + // Check for attachments (images, videos, etc.) attachments := gjson.Get(jsonStr, "attachment").Array() if len(attachments) > 0 { @@ -125,12 +125,12 @@ func formatContent(jsonStr string, parts []string, bold, green func(a ...interfa mediaType := attachment.Get("mediaType").String() url := attachment.Get("url").String() name := attachment.Get("name").String() - + // Truncate long descriptions if len(name) > 100 { name = name[:97] + "..." } - + attachmentInfo := fmt.Sprintf(" %d. %s", i+1, green(attachmentType)) if mediaType != "" { attachmentInfo += fmt.Sprintf(" (%s)", mediaType) @@ -139,37 +139,55 @@ func formatContent(jsonStr string, parts []string, bold, green func(a ...interfa attachmentInfo += fmt.Sprintf(": %s", name) } parts = append(parts, attachmentInfo) - + if url != "" { parts = append(parts, fmt.Sprintf(" URL: %s", url)) } } } - + if published := gjson.Get(jsonStr, "published").String(); published != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("Published"), formatDate(published))) } - + if updated := gjson.Get(jsonStr, "updated").String(); updated != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("Updated"), formatDate(updated))) } - + if attributedTo := gjson.Get(jsonStr, "attributedTo").String(); attributedTo != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("Author"), attributedTo)) } - + if to := gjson.Get(jsonStr, "to").Array(); len(to) > 0 { parts = append(parts, fmt.Sprintf("%s: %s", bold("To"), formatArray(to))) } - + if cc := gjson.Get(jsonStr, "cc").Array(); len(cc) > 0 { parts = append(parts, fmt.Sprintf("%s: %s", bold("CC"), formatArray(cc))) } - + if inReplyTo := gjson.Get(jsonStr, "inReplyTo").String(); inReplyTo != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("In Reply To"), inReplyTo)) } - + + // Include endTime for Question type + if endTime := gjson.Get(jsonStr, "endTime").String(); endTime != "" { + parts = append(parts, fmt.Sprintf("%s: %s", bold("End Time"), formatDate(endTime))) + } + + // Include options (oneOf/anyOf) for Question type + options := gjson.Get(jsonStr, "oneOf").Array() + if len(options) == 0 { + options = gjson.Get(jsonStr, "anyOf").Array() + } + if len(options) > 0 { + parts = append(parts, fmt.Sprintf("%s:", bold("Poll Options"))) + for i, opt := range options { + name := opt.Get("name").String() + parts = append(parts, fmt.Sprintf(" %d. %s", i+1, name)) + } + } + return parts } @@ -178,13 +196,13 @@ func formatActivity(jsonStr string, parts []string, bold, green, yellow func(a . if actor := gjson.Get(jsonStr, "actor").String(); actor != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("Actor"), actor)) } - + if object := gjson.Get(jsonStr, "object").String(); object != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("Object"), object)) } else if gjson.Get(jsonStr, "object").IsObject() { objectType := gjson.Get(jsonStr, "object.type").String() parts = append(parts, fmt.Sprintf("%s: %s", bold("Object Type"), yellow(objectType))) - + if content := gjson.Get(jsonStr, "object.content").String(); content != "" { content = stripHTML(content) if len(content) > 300 { @@ -192,7 +210,7 @@ func formatActivity(jsonStr string, parts []string, bold, green, yellow func(a . } parts = append(parts, fmt.Sprintf("%s: %s", bold("Content"), content)) } - + // Check for attachments in the object attachments := gjson.Get(jsonStr, "object.attachment").Array() if len(attachments) > 0 { @@ -202,12 +220,12 @@ func formatActivity(jsonStr string, parts []string, bold, green, yellow func(a . mediaType := attachment.Get("mediaType").String() url := attachment.Get("url").String() name := attachment.Get("name").String() - + // Truncate long descriptions if len(name) > 100 { name = name[:97] + "..." } - + attachmentInfo := fmt.Sprintf(" %d. %s", i+1, green(attachmentType)) if mediaType != "" { attachmentInfo += fmt.Sprintf(" (%s)", mediaType) @@ -216,22 +234,22 @@ func formatActivity(jsonStr string, parts []string, bold, green, yellow func(a . attachmentInfo += fmt.Sprintf(": %s", name) } parts = append(parts, attachmentInfo) - + if url != "" { parts = append(parts, fmt.Sprintf(" URL: %s", url)) } } } } - + if published := gjson.Get(jsonStr, "published").String(); published != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("Published"), formatDate(published))) } - + if target := gjson.Get(jsonStr, "target").String(); target != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("Target"), target)) } - + return parts } @@ -240,19 +258,19 @@ func formatCollection(jsonStr string, parts []string, bold, green func(a ...inte if totalItems := gjson.Get(jsonStr, "totalItems").Int(); totalItems > 0 { parts = append(parts, fmt.Sprintf("%s: %d", bold("Total Items"), totalItems)) } - + // Show first few items if available items := gjson.Get(jsonStr, "items").Array() if len(items) == 0 { items = gjson.Get(jsonStr, "orderedItems").Array() } - + if len(items) > 0 { itemCount := len(items) if itemCount > 3 { itemCount = 3 } - + parts = append(parts, fmt.Sprintf("%s:", bold("First Items"))) for i := 0; i < itemCount; i++ { item := items[i].String() @@ -261,12 +279,12 @@ func formatCollection(jsonStr string, parts []string, bold, green func(a ...inte } parts = append(parts, fmt.Sprintf(" - %s", item)) } - + if len(items) > 3 { parts = append(parts, fmt.Sprintf(" ... and %d more items", len(items)-3)) } } - + return parts } @@ -275,23 +293,23 @@ func formatMedia(jsonStr string, parts []string, bold, green func(a ...interface if name := gjson.Get(jsonStr, "name").String(); name != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("Name"), name)) } - + if url := gjson.Get(jsonStr, "url").String(); url != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("URL"), url)) } - + if duration := gjson.Get(jsonStr, "duration").String(); duration != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("Duration"), duration)) } - + if published := gjson.Get(jsonStr, "published").String(); published != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("Published"), formatDate(published))) } - + if attributedTo := gjson.Get(jsonStr, "attributedTo").String(); attributedTo != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("Author"), attributedTo)) } - + return parts } @@ -300,7 +318,7 @@ func formatEvent(jsonStr string, parts []string, bold, green func(a ...interface if name := gjson.Get(jsonStr, "name").String(); name != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("Name"), name)) } - + if content := gjson.Get(jsonStr, "content").String(); content != "" { content = stripHTML(content) if len(content) > 300 { @@ -308,19 +326,19 @@ func formatEvent(jsonStr string, parts []string, bold, green func(a ...interface } parts = append(parts, fmt.Sprintf("%s: %s", bold("Description"), content)) } - + if startTime := gjson.Get(jsonStr, "startTime").String(); startTime != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("Start Time"), formatDate(startTime))) } - + if endTime := gjson.Get(jsonStr, "endTime").String(); endTime != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("End Time"), formatDate(endTime))) } - + if location := gjson.Get(jsonStr, "location").String(); location != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("Location"), location)) } - + return parts } @@ -329,11 +347,11 @@ func formatTombstone(jsonStr string, parts []string, bold, green func(a ...inter if formerType := gjson.Get(jsonStr, "formerType").String(); formerType != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("Former Type"), formerType)) } - + if deleted := gjson.Get(jsonStr, "deleted").String(); deleted != "" { parts = append(parts, fmt.Sprintf("%s: %s", bold("Deleted"), formatDate(deleted))) } - + return parts } @@ -350,7 +368,7 @@ func formatDate(isoDate string) string { func stripHTML(html string) string { // Simple HTML tag stripping - in a real implementation, you might want to use a proper HTML parser result := html - + // Replace common HTML entities replacements := map[string]string{ "&": "&", @@ -360,29 +378,29 @@ func stripHTML(html string) string { "'": "'", " ": " ", } - + for entity, replacement := range replacements { result = strings.ReplaceAll(result, entity, replacement) } - + // Remove HTML tags for { startIdx := strings.Index(result, "<") if startIdx == -1 { break } - + endIdx := strings.Index(result[startIdx:], ">") if endIdx == -1 { break } - + result = result[:startIdx] + result[startIdx+endIdx+1:] } - + // Normalize whitespace result = strings.Join(strings.Fields(result), " ") - + return result } @@ -391,15 +409,15 @@ func formatArray(values []gjson.Result) string { if len(values) == 0 { return "" } - + var items []string for _, v := range values { items = append(items, v.String()) } - + if len(items) == 1 { return items[0] } - + return fmt.Sprintf("[\n %s\n ]", strings.Join(items, ",\n ")) }