Skip to content

Commit

Permalink
Added badge SVG customization URL query params and associated tests (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
erjdev authored Oct 23, 2024
1 parent e2d6639 commit a5418d8
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 1 deletion.
53 changes: 52 additions & 1 deletion cmd/badges/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,11 @@ func main() {
textLength = "200"
}

bs := parseBadgeSettings(r.URL.Query())

log.Info().Str(uniqueCode, "42c5269c").Str("loc", loc.String()).Str("category", category).Send()
w.Header().Set("Content-Type", "image/svg+xml;charset=utf-8")
_, _ = w.Write([]byte(`<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="100" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h69v20H0z"/><path fill="#4c1" d="M69 0h31v20H69z"/><path fill="url(#b)" d="M0 0h100v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"> <text x="355" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="590">` + title + `</text><text x="355" y="140" transform="scale(.1)" textLength="590">` + title + `</text><text x="835" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="` + textLength + `">` + s + `</text><text x="835" y="140" transform="scale(.1)" textLength="` + textLength + `">` + s + `</text></g> </svg>`))
_, _ = w.Write([]byte(`<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="` + bs.TopShadowAccentColor + `" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="100" height="20" rx="3" fill="#` + bs.FontColor + `"/></clipPath><g clip-path="url(#a)"><path fill="#` + bs.TitleBackgroundColor + `" d="M0 0h69v20H0z"/><path fill="#` + bs.BadgeBackgroundColor + `" d="M69 0h31v20H69z"/><path fill="url(#b)" d="M0 0h100v20H0z"/></g><g fill="#` + bs.FontColor + `" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"> <text x="355" y="150" fill="#` + bs.TextShadowColor + `" fill-opacity=".3" transform="scale(.1)" textLength="590">` + title + `</text><text x="355" y="140" transform="scale(.1)" textLength="590">` + title + `</text><text x="835" y="150" fill="#` + bs.TextShadowColor + `" fill-opacity=".3" transform="scale(.1)" textLength="` + textLength + `">` + s + `</text><text x="835" y="140" transform="scale(.1)" textLength="` + textLength + `">` + s + `</text></g> </svg>`))
})

addr := ":8080"
Expand Down Expand Up @@ -170,6 +172,55 @@ func processUrlPath(path string) (location, error) {
}, nil
}

type badgeSettings struct {
FontColor string
TextShadowColor string
TopShadowAccentColor string
TitleBackgroundColor string
BadgeBackgroundColor string
}

// Parses badge settings from url query params
// if error, ignore and return default badge settings
func parseBadgeSettings(values url.Values) *badgeSettings {
bs := badgeSettings{
FontColor: "fff",
TextShadowColor: "010101",
TopShadowAccentColor: "bbb",
TitleBackgroundColor: "555",
BadgeBackgroundColor: "4c1",
}

fontColor := strings.ToLower(values.Get("font-color"))
textShadowColor := strings.ToLower(values.Get("font-shadow-color"))
topShadowAccentColor := strings.ToLower(values.Get("top-shadow-accent-color"))
titleBackgroundColor := strings.ToLower(values.Get("title-bg-color"))
badgeBackgroundColor := strings.ToLower(values.Get("badge-bg-color"))

// Ensure valid colors
r, err := regexp.Compile(`^(?:(?:[\da-f]{3}){1,2}|(?:[\da-f]{4}){1,2})$`)
if err != nil {
return &bs
}
if r.MatchString(fontColor) {
bs.FontColor = fontColor
}
if r.MatchString(textShadowColor) {
bs.TextShadowColor = textShadowColor
}
if r.MatchString(topShadowAccentColor) {
bs.TopShadowAccentColor = topShadowAccentColor
}
if r.MatchString(titleBackgroundColor) {
bs.TitleBackgroundColor = titleBackgroundColor
}
if r.MatchString(badgeBackgroundColor) {
bs.BadgeBackgroundColor = badgeBackgroundColor
}

return &bs
}

// formatCount turns a float into a string usable for display
// to the user so, 2532 would be 2.5k and such up the various
// units
Expand Down
76 changes: 76 additions & 0 deletions cmd/badges/main_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"net/url"
"reflect"
"testing"
)
Expand Down Expand Up @@ -121,3 +122,78 @@ func Test_processPath(t *testing.T) {
})
}
}
func Test_parseBadgeSettings(t *testing.T) {

defaultSettings := &badgeSettings{
FontColor: "fff",
TextShadowColor: "010101",
TopShadowAccentColor: "bbb",
TitleBackgroundColor: "555",
BadgeBackgroundColor: "4c1",
}

tests := []struct {
name string
values url.Values
want *badgeSettings
}{
{
name: "default settings",
values: url.Values{},
want: defaultSettings,
},
{
name: "valid custom settings",
values: url.Values{
"font-color": []string{"abcdef"},
"font-shadow-color": []string{"def"},
"top-shadow-accent-color": []string{"321def"},
"title-bg-color": []string{"456"},
"badge-bg-color": []string{"789"},
},
want: &badgeSettings{
FontColor: "abcdef",
TextShadowColor: "def",
TopShadowAccentColor: "321def",
TitleBackgroundColor: "456",
BadgeBackgroundColor: "789",
},
},
{
name: "partially-valid custom settings",
values: url.Values{
"font-color": []string{"123321"},
"font-shadow-color": []string{"invalid"},
"top-shadow-accent-color": []string{"5a534332"},
"title-bg-color": []string{"dd"},
"badge-bg-color": []string{"X&^%^#$^$@%20"},
},
want: &badgeSettings{
FontColor: "123321",
TextShadowColor: defaultSettings.TextShadowColor,
TopShadowAccentColor: "5a534332",
TitleBackgroundColor: defaultSettings.TitleBackgroundColor,
BadgeBackgroundColor: defaultSettings.BadgeBackgroundColor,
},
},
{
name: "invalid custom settings",
values: url.Values{
"font-color": []string{"invalid"},
"font-shadow-color": []string{"invalid"},
"top-shadow-accent-color": []string{"invalid"},
"title-bg-color": []string{"invalid"},
"badge-bg-color": []string{"invalid"},
},
want: defaultSettings,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := parseBadgeSettings(tt.values); !reflect.DeepEqual(got, tt.want) {
t.Errorf("parseBadgeSettings() = %v, want %v", got, tt.want)
}
})
}
}

0 comments on commit a5418d8

Please sign in to comment.