Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/.tool-versions
.idea
notifiers-secret.yaml
vendor/
Expand Down
58 changes: 50 additions & 8 deletions docs/services/googlechat.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ kind: Secret
metadata:
name: <secret-name>
stringData:
space-webhook-url: https://chat.googleapis.com/v1/spaces/<space_id>/messages?key=<key>&token=<token>
space-webhook-url: https://chat.googleapis.com/v1/spaces/<space_id>/messages?key=<key>&token=<token>
```

6. Create a subscription for your space
Expand All @@ -47,14 +47,9 @@ metadata:

## Templates

You can send [simple text](https://developers.google.com/chat/reference/message-formats/basic) or [card messages](https://developers.google.com/chat/reference/message-formats/cards) to a Google Chat space. A simple text message template can be defined as follows:
### Card Message

```yaml
template.app-sync-succeeded: |
message: The app {{ .app.metadata.name }} has successfully synced!
```

A card message can be defined as follows:
You can send [card messages](https://developers.google.com/chat/reference/message-formats/cards) to a Google Chat space. A card message can be defined as follows:

```yaml
template.app-sync-succeeded: |
Expand Down Expand Up @@ -83,6 +78,53 @@ but this is not recommended as Google has deprecated this field and recommends u

The card message can be written in JSON too.

### Simple Text

You can send [simple text](https://developers.google.com/chat/reference/message-formats/basic) to a Google Chat space. A simple text message template can be defined as follows:

```yaml
template.app-sync-succeeded: |
googlechat:
text: The app {{ .app.metadata.name }} has successfully synced!
```

If neither `googlechat.text` nor `googlechat.cardsV2`/`googlechat.cards` is specified, it default to `message` field:

```yaml
template.app-sync-succeeded: |
message: The app {{ .app.metadata.name }} has successfully synced!
```

If you want to include simple text even if cards are specified or text is resolved to empty (or not provided), you can still default to `message` field:

```yaml
template.app-sync-succeeded: |
message: The app {{ .app.metadata.name }} has successfully synced!
googlechat:
text: "{{if false}}never{{end}}"
defaultTextToMessage: true
```

### Fallback Text

You can provide a [fallback text](https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces.messages#Message.FIELDS.fallback_text) to be used when sending messages. It's a plain-text description of the message's cards, used when the actual cards can't be displayed—for example, mobile notifications. The fallback text can be defined as follows:

```yaml
template.app-sync-succeeded: |
googlechat:
fallbackText: The app {{ .app.metadata.name }} has successfully synced!
```

If you want to include fallback text even if it is resolved to empty (or not provided), you can still default to `message` field:

```yaml
template.app-sync-succeeded: |
message: The app {{ .app.metadata.name }} has successfully synced!
googlechat:
fallbackText: "{{if false}}never{{end}}"
defaultFallbackTextToMessage: true
```

## Chat Threads

It is possible send both simple text and card messages in a chat thread by specifying a unique key for the thread. The thread key can be defined as follows:
Expand Down
74 changes: 65 additions & 9 deletions pkg/services/googlechat.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,33 @@ import (
)

type GoogleChatNotification struct {
Cards string `json:"cards"`
CardsV2 string `json:"cardsV2"`
ThreadKey string `json:"threadKey,omitempty"`
Cards string `json:"cards"`
CardsV2 string `json:"cardsV2"`
ThreadKey string `json:"threadKey,omitempty"`
Text string `json:"text,omitempty"`
FallbackText string `json:"fallbackText,omitempty"`
DefaultTextToMessage bool `json:"defaultTextToMessage,omitempty"`
DefaultFallbackTextToMessage bool `json:"defaultFallbackTextToMessage,omitempty"`
}

type googleChatMessage struct {
Text string `json:"text"`
Cards []chat.Card `json:"cards,omitempty"`
CardsV2 []chat.CardWithId `json:"cardsV2,omitempty"`
Text string `json:"text,omitempty"`
Cards []chat.Card `json:"cards,omitempty"`
CardsV2 []chat.CardWithId `json:"cardsV2,omitempty"`
FallbackText string `json:"fallbackText,omitempty"`
}

func (n *GoogleChatNotification) GetTemplater(name string, f texttemplate.FuncMap) (Templater, error) {
text, err := texttemplate.New(name).Funcs(f).Parse(n.Text)
if err != nil {
return nil, fmt.Errorf("error in '%s' googlechat.text : %w", name, err)
}

fallbackText, err := texttemplate.New(name).Funcs(f).Parse(n.FallbackText)
if err != nil {
return nil, fmt.Errorf("error in '%s' googlechat.fallbackText : %w", name, err)
}

cards, err := texttemplate.New(name).Funcs(f).Parse(n.Cards)
if err != nil {
return nil, fmt.Errorf("error in '%s' googlechat.cards : %w", name, err)
Expand All @@ -50,6 +65,25 @@ func (n *GoogleChatNotification) GetTemplater(name string, f texttemplate.FuncMa
if notification.GoogleChat == nil {
notification.GoogleChat = &GoogleChatNotification{}
}
notification.GoogleChat.DefaultTextToMessage = n.DefaultTextToMessage
notification.GoogleChat.DefaultFallbackTextToMessage = n.DefaultFallbackTextToMessage

var textBuff bytes.Buffer
if err := text.Execute(&textBuff, vars); err != nil {
return err
}
if val := textBuff.String(); val != "" {
notification.GoogleChat.Text = val
}

var fallbackTextBuff bytes.Buffer
if err := fallbackText.Execute(&fallbackTextBuff, vars); err != nil {
return err
}
if val := fallbackTextBuff.String(); val != "" {
notification.GoogleChat.FallbackText = val
}

var cardsBuff bytes.Buffer
if err := cards.Execute(&cardsBuff, vars); err != nil {
return err
Expand Down Expand Up @@ -185,10 +219,12 @@ func (s googleChatService) Send(notification Notification, dest Destination) err

func googleChatNotificationToMessage(n Notification) (*googleChatMessage, error) {
message := &googleChatMessage{}
if n.GoogleChat != nil && (n.GoogleChat.CardsV2 != "" || n.GoogleChat.Cards != "") {
useCards := false

if n.GoogleChat != nil {
if n.GoogleChat.CardsV2 != "" {
useCards = true
// Unmarshal Modern Type

var cardData []chat.GoogleAppsCardV1Card
err := yaml.Unmarshal([]byte(n.GoogleChat.CardsV2), &cardData)
if err != nil {
Expand All @@ -206,14 +242,34 @@ func googleChatNotificationToMessage(n Notification) (*googleChatMessage, error)
}

if n.GoogleChat.Cards != "" {
useCards = true
// Unmarshal Legacy Type
err := yaml.Unmarshal([]byte(n.GoogleChat.Cards), &message.Cards)
if err != nil {
return nil, err
}
}
} else {

// May override message text even if `defaultTextToMessage` is true, give priority to explicit `Text`.
// User may arrange for their template to render empty and fallback to `Message`.
if n.GoogleChat.Text != "" {
message.Text = n.GoogleChat.Text
} else if n.GoogleChat.DefaultTextToMessage {
message.Text = n.Message
}

// May override message text even if `defaultFallbackTextToMessage` is true, give priority to explicit `FallbackText`.
// User may arrange for their template to render empty and fallback to `Message`.
if n.GoogleChat.FallbackText != "" {
message.FallbackText = n.GoogleChat.FallbackText
} else if n.GoogleChat.DefaultFallbackTextToMessage {
message.FallbackText = n.Message
}
}

if message.Text == "" && !useCards {
message.Text = n.Message
}

return message, nil
}
Loading
Loading