mirror of
https://github.com/prymitive/karma
synced 2026-05-05 03:16:51 +00:00
169 lines
3.8 KiB
Go
169 lines
3.8 KiB
Go
package models
|
|
|
|
import (
|
|
"net/url"
|
|
"slices"
|
|
"strings"
|
|
|
|
"github.com/fvbommel/sortorder"
|
|
"github.com/go-json-experiment/json/jsontext"
|
|
|
|
"github.com/prymitive/karma/internal/config"
|
|
)
|
|
|
|
// Annotation extends Alertmanager scheme of key:value with additional data
|
|
// to control how given annotation should be rendered
|
|
type Annotation struct {
|
|
Name string `json:"name"`
|
|
Value string `json:"value"`
|
|
Visible bool `json:"visible"`
|
|
IsLink bool `json:"isLink"`
|
|
IsAction bool `json:"isAction"`
|
|
}
|
|
|
|
func (a Annotation) MarshalJSONTo(enc *jsontext.Encoder) error {
|
|
w := jsonWriter{enc: enc}
|
|
a.marshalTo(&w)
|
|
return w.err
|
|
}
|
|
|
|
func (a *Annotation) marshalTo(w *jsonWriter) {
|
|
w.beginObject()
|
|
w.key("name")
|
|
w.str(a.Name)
|
|
w.key("value")
|
|
w.str(a.Value)
|
|
w.key("visible")
|
|
w.boolean(a.Visible)
|
|
w.key("isLink")
|
|
w.boolean(a.IsLink)
|
|
w.key("isAction")
|
|
w.boolean(a.IsAction)
|
|
w.endObject()
|
|
}
|
|
|
|
// Annotations is a slice of Annotation structs, needed to implement sorting
|
|
type Annotations []Annotation
|
|
|
|
func (a Annotations) MarshalJSONTo(enc *jsontext.Encoder) error {
|
|
w := jsonWriter{enc: enc}
|
|
w.beginArray()
|
|
for i := range a {
|
|
a[i].marshalTo(&w)
|
|
}
|
|
w.endArray()
|
|
return w.err
|
|
}
|
|
|
|
func compareAnnotations(a, b Annotation) int {
|
|
// Sort the annotations listed in config.Config.Annotations.Order first, in
|
|
// the order they appear in that list; remaining annotations are sorted alphabetically.
|
|
ai, bi := -1, -1
|
|
for index, name := range config.Config.Annotations.Order {
|
|
if a.Name == name {
|
|
ai = index
|
|
} else if b.Name == name {
|
|
bi = index
|
|
}
|
|
// If both annotations are in c.C.A.Order, sort them according to the
|
|
// order in that list.
|
|
if ai >= 0 && bi >= 0 {
|
|
if ai < bi {
|
|
return -1
|
|
}
|
|
return 1
|
|
}
|
|
}
|
|
// If only one of the annotations was in c.C.A.Order, that one goes first.
|
|
if ai != bi {
|
|
if bi < ai {
|
|
return -1
|
|
}
|
|
return 1
|
|
}
|
|
// If neither annotation was in c.C.A.Order, sort alphabetically.
|
|
if sortorder.NaturalLess(a.Name, b.Name) {
|
|
return -1
|
|
}
|
|
if sortorder.NaturalLess(b.Name, a.Name) {
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func NewAnnotation(name, value string) Annotation {
|
|
return Annotation{
|
|
Name: name,
|
|
Value: value,
|
|
Visible: isVisible(name),
|
|
IsLink: isLink(value),
|
|
IsAction: isAction(name),
|
|
}
|
|
}
|
|
|
|
// AnnotationsFromMap will convert a map[string]string to a list of Annotation
|
|
// instances, it takes care of setting proper value for Visible attribute
|
|
func AnnotationsFromMap(m map[string]string) Annotations {
|
|
annotations := make(Annotations, 0, len(m))
|
|
for name, value := range m {
|
|
a := Annotation{
|
|
Name: name,
|
|
Value: value,
|
|
Visible: isVisible(name),
|
|
IsLink: isLink(value),
|
|
IsAction: isAction(name),
|
|
}
|
|
annotations = append(annotations, a)
|
|
}
|
|
SortAnnotations(annotations)
|
|
return annotations
|
|
}
|
|
|
|
func SortAnnotations(annotations Annotations) {
|
|
slices.SortFunc(annotations, compareAnnotations)
|
|
}
|
|
|
|
var linkSchemes = []string{
|
|
"ftp",
|
|
"http",
|
|
"https",
|
|
}
|
|
|
|
func isLink(s string) bool {
|
|
s = strings.TrimSpace(s)
|
|
|
|
if strings.Contains(s, " ") {
|
|
return false
|
|
}
|
|
u, err := url.ParseRequestURI(s)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
if slices.Contains(linkSchemes, u.Scheme) {
|
|
// parses with url.Parse and scheme is in the list of supported schemes
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func isVisible(name string) bool {
|
|
if slices.Contains(config.Config.Annotations.Visible, name) {
|
|
// annotation was explicitly marked as visible
|
|
return true
|
|
}
|
|
if slices.Contains(config.Config.Annotations.Hidden, name) {
|
|
// annotation was explicitly marked as hidden
|
|
return false
|
|
}
|
|
if config.Config.Annotations.Default.Hidden {
|
|
// user specified that default is to hide anything without explicit rules
|
|
return false
|
|
}
|
|
// default to show everything
|
|
return true
|
|
}
|
|
|
|
func isAction(name string) bool {
|
|
return slices.Contains(config.Config.Annotations.Actions, name)
|
|
}
|