From e02dcb943263da2fa701a7aba96b5dc41c14ffe0 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sat, 19 Oct 2024 21:02:14 +0300 Subject: fix linkedin escapes --- internal/platforms/linkedin/escapes.go | 39 +++++++++++++++++++++++++++++ internal/platforms/linkedin/escapes_test.go | 15 +++++++++++ internal/platforms/linkedin/linkedin.go | 13 ++++++---- internal/platforms/mastodon/mastodon.go | 7 ++++++ internal/schedule/schedule.go | 2 +- 5 files changed, 70 insertions(+), 6 deletions(-) create mode 100644 internal/platforms/linkedin/escapes.go create mode 100644 internal/platforms/linkedin/escapes_test.go diff --git a/internal/platforms/linkedin/escapes.go b/internal/platforms/linkedin/escapes.go new file mode 100644 index 0000000..5f803a5 --- /dev/null +++ b/internal/platforms/linkedin/escapes.go @@ -0,0 +1,39 @@ +package linkedin + +import ( + "strings" +) + +// https://learn.microsoft.com/en-us/linkedin/marketing/community-management/shares/little-text-format?view=li-lms-2024-01#language-grammar +func escapeLinkedInText(input string) string { + var builder strings.Builder + + reservedChars := map[rune]string{ + '"': "\\\"", + '|': "\\|", + '{': "\\{", + '}': "\\}", + // '@': "\\@", + '[': "\\[", + ']': "\\]", + '(': "\\(", + ')': "\\)", + '<': "\\<", + '>': "\\>", + //'#': "\\#", + '\\': "\\\\", + '*': "\\*", + '_': "\\_", + '~': "\\~", + } + + for _, char := range input { + if escapeSeq, ok := reservedChars[char]; ok { + builder.WriteString(escapeSeq) + } else { + builder.WriteRune(char) + } + } + + return builder.String() +} diff --git a/internal/platforms/linkedin/escapes_test.go b/internal/platforms/linkedin/escapes_test.go new file mode 100644 index 0000000..b1f9203 --- /dev/null +++ b/internal/platforms/linkedin/escapes_test.go @@ -0,0 +1,15 @@ +package linkedin + +import ( + "testing" +) + +func TestLinkedInEscapes(t *testing.T) { + var ( + input = `This is a test message with special characters: " {} @ [] () <> # \ * _ ~ |` + expected = `This is a test message with special characters: \" \{\} @ \[\] \(\) \<\> # \\ \* \_ \~ \|` + ) + if escaped := escapeLinkedInText(input); escaped != expected { + t.Errorf("expected '%s' but got '%s'", expected, escaped) + } +} diff --git a/internal/platforms/linkedin/linkedin.go b/internal/platforms/linkedin/linkedin.go index c283fbc..f6d89f5 100644 --- a/internal/platforms/linkedin/linkedin.go +++ b/internal/platforms/linkedin/linkedin.go @@ -14,6 +14,7 @@ import ( "codeberg.org/snonux/gos/internal/entry" "codeberg.org/snonux/gos/internal/platforms/linkedin/oauth2" "codeberg.org/snonux/gos/internal/prompt" + "github.com/fatih/color" ) var errUnauthorized = errors.New("unauthorized access, refresh or create token?") @@ -58,7 +59,7 @@ func callLinkedInAPI(ctx context.Context, personID, accessToken, content string) post := map[string]interface{}{ "author": fmt.Sprintf("urn:li:person:%s", personID), - "commentary": content, // TODO: Can't post (...) paretenthesis? escape them? TEST AGAIN! + "commentary": escapeLinkedInText(content), "visibility": "PUBLIC", "distribution": map[string]interface{}{ "feedDistribution": "MAIN_FEED", @@ -88,15 +89,17 @@ func callLinkedInAPI(ctx context.Context, personID, accessToken, content string) return fmt.Errorf("Error sending request: %w", err) } defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + color.Cyan(string(body)) if resp.StatusCode != http.StatusCreated { - body, _ := io.ReadAll(resp.Body) - err = fmt.Errorf("failed to post to LinkedIn. Status: %s\n%s\n", resp.Status, body) + err = fmt.Errorf("failed to post to LinkedIn. Status: %s\n", resp.Status) if resp.StatusCode == http.StatusUnauthorized { err = errors.Join(err, errUnauthorized) } } return err } - -// TODO: Implement Gemini output? diff --git a/internal/platforms/mastodon/mastodon.go b/internal/platforms/mastodon/mastodon.go index f582b4c..0a87d74 100644 --- a/internal/platforms/mastodon/mastodon.go +++ b/internal/platforms/mastodon/mastodon.go @@ -6,12 +6,14 @@ import ( "encoding/json" "errors" "fmt" + "io" "log" "net/http" "codeberg.org/snonux/gos/internal/config" "codeberg.org/snonux/gos/internal/entry" "codeberg.org/snonux/gos/internal/prompt" + "github.com/fatih/color" ) func Post(ctx context.Context, args config.Args, sizeLimit int, ent entry.Entry) error { @@ -51,6 +53,11 @@ func Post(ctx context.Context, args config.Args, sizeLimit int, ent entry.Entry) return fmt.Errorf("request failed: %w", err) } defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + color.Cyan(string(body)) if resp.StatusCode != http.StatusOK { return fmt.Errorf("unexpected status code: %d", resp.StatusCode) diff --git a/internal/schedule/schedule.go b/internal/schedule/schedule.go index 5512e4d..be2b6f8 100644 --- a/internal/schedule/schedule.go +++ b/internal/schedule/schedule.go @@ -26,7 +26,7 @@ func Run(args config.Args, platform string) (entry.Entry, error) { } log.Println("For", platform, "stats:", stats) - if stats.targetHit() { + if stats.targetHit(args.PauseDays) { return entry.Zero, ErrNothingToSchedule } -- cgit v1.2.3