Files
owncast/core/webhooks/webhooks.go
Copilot 740dd9c6fa Add server status as a default field in all webhooks using BaseWebhookData struct (#4410)
* Initial plan

* Add server status as default field in all webhooks

Co-authored-by: gabek <414923+gabek@users.noreply.github.com>

* Fix goimports linter error by removing trailing whitespace

Co-authored-by: gabek <414923+gabek@users.noreply.github.com>

* Move serverURL from status object to separate webhook field per feedback

Per code review feedback, serverURL is a configuration value, not a status property. This change:
- Removes ServerURL from models.Status struct
- Adds ServerURL as separate field in WebhookEvent
- Populates ServerURL directly when sending webhooks using configrepository.GetServerURL()
- Updates all tests to expect new structure

This provides the same functionality (server URL in all webhooks) while correctly treating it as configuration rather than status.

Co-authored-by: gabek <414923+gabek@users.noreply.github.com>

* Add omitempty tag to ServerURL field in WebhookEvent struct

Co-authored-by: gabek <414923+gabek@users.noreply.github.com>

* Fix webhook duplication by moving status to eventData for all events

Co-authored-by: gabek <414923+gabek@users.noreply.github.com>

* Restore type safety to webhook EventData using proper typed structs

Co-authored-by: gabek <414923+gabek@users.noreply.github.com>

* Move ServerURL from top-level WebhookEvent to eventData for all webhook types

Co-authored-by: gabek <414923+gabek@users.noreply.github.com>

* Update core/webhooks/webhooks.go

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Create BaseWebhookData struct for common webhook fields using struct embedding

Co-authored-by: gabek <414923+gabek@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: gabek <414923+gabek@users.noreply.github.com>
Co-authored-by: Gabe Kangas <gabek@real-ity.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-31 17:12:38 -07:00

93 lines
2.9 KiB
Go

package webhooks
import (
"sync"
"time"
"github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/persistence/webhookrepository"
)
// BaseWebhookData contains common fields shared across all webhook event data.
type BaseWebhookData struct {
Status models.Status `json:"status"`
ServerURL string `json:"serverURL,omitempty"`
}
// WebhookEvent represents an event sent as a webhook.
type WebhookEvent struct {
EventData interface{} `json:"eventData,omitempty"`
Type models.EventType `json:"type"` // messageSent | userJoined | userNameChange
}
// WebhookChatMessage represents a single chat message sent as a webhook payload.
type WebhookChatMessage struct {
BaseWebhookData
User *models.User `json:"user,omitempty"`
Timestamp *time.Time `json:"timestamp,omitempty"`
Body string `json:"body,omitempty"`
RawBody string `json:"rawBody,omitempty"`
ID string `json:"id,omitempty"`
ClientID uint `json:"clientId,omitempty"`
Visible bool `json:"visible"`
}
// WebhookUserJoinedEventData represents user joined event data sent as a webhook payload.
type WebhookUserJoinedEventData struct {
BaseWebhookData
ID string `json:"id"`
Timestamp time.Time `json:"timestamp"`
User *models.User `json:"user"`
}
// WebhookUserPartEventData represents user parted event data sent as a webhook payload.
type WebhookUserPartEventData struct {
BaseWebhookData
ID string `json:"id"`
Timestamp time.Time `json:"timestamp"`
User *models.User `json:"user"`
}
// WebhookNameChangeEventData represents name change event data sent as a webhook payload.
type WebhookNameChangeEventData struct {
BaseWebhookData
ID string `json:"id"`
Timestamp time.Time `json:"timestamp"`
User *models.User `json:"user"`
NewName string `json:"newName"`
}
// WebhookVisibilityToggleEventData represents message visibility toggle event data sent as a webhook payload.
type WebhookVisibilityToggleEventData struct {
BaseWebhookData
ID string `json:"id"`
Timestamp time.Time `json:"timestamp"`
User *models.User `json:"user"`
Visible bool `json:"visible"`
MessageIDs []string `json:"ids"`
}
// SendEventToWebhooks will send a single webhook event to all webhook destinations.
func SendEventToWebhooks(payload WebhookEvent) {
sendEventToWebhooks(payload, nil)
}
func sendEventToWebhooks(payload WebhookEvent, wg *sync.WaitGroup) {
webhooksRepo := webhookrepository.Get()
webhooks := webhooksRepo.GetWebhooksForEvent(payload.Type)
for _, webhook := range webhooks {
// Use wg to track the number of notifications to be sent.
if wg != nil {
wg.Add(1)
}
addToQueue(webhook, payload, wg)
}
}
func getServerURL() string {
configRepo := configrepository.Get()
return configRepo.GetServerURL()
}