/
uzer_007
/
Rixea
Обзор
Документация
Войти
/
uzer_007
/
Rixea
Код
Запросы
0
Задачи
Вики
Пакеты
5
Релизы
2
CI/CD
Аналитика
Безопасность
master
models/webhook/webhook.go
305 строк
9 KB
uzer_007
feat: первая версия Rixea
02 авг 2026, 22:16
02 авг 2026, 22:16
d4f7504
Код
Авторство
О чём код?
// Copyright 2026 Uzer_007. All rights reserved. // SPDX-License-Identifier: MIT package webhook import ( "context" "fmt" "strings" "gitverse.ru/uzer_007/Rixea/models/db" "gitverse.ru/uzer_007/Rixea/modules/json" "gitverse.ru/uzer_007/Rixea/modules/log" "gitverse.ru/uzer_007/Rixea/modules/optional" "gitverse.ru/uzer_007/Rixea/modules/secret" "gitverse.ru/uzer_007/Rixea/modules/setting" "gitverse.ru/uzer_007/Rixea/modules/timeutil" "gitverse.ru/uzer_007/Rixea/modules/util" webhook_module "gitverse.ru/uzer_007/Rixea/modules/webhook" ) // ErrWebhookNotExist represents a "WebhookNotExist" kind of error. type ErrWebhookNotExist struct { ID int64 } // IsErrWebhookNotExist checks if an error is a ErrWebhookNotExist. func IsErrWebhookNotExist(err error) bool { _, ok := err.(ErrWebhookNotExist) return ok } func (err ErrWebhookNotExist) Error() string { return fmt.Sprintf("webhook does not exist [id: %d]", err.ID) } func (err ErrWebhookNotExist) Unwrap() error { return util.ErrNotExist } // ErrHookTaskNotExist represents a "HookTaskNotExist" kind of error. type ErrHookTaskNotExist struct { TaskID int64 HookID int64 UUID string } // IsErrHookTaskNotExist checks if an error is a ErrHookTaskNotExist. func IsErrHookTaskNotExist(err error) bool { _, ok := err.(ErrHookTaskNotExist) return ok } func (err ErrHookTaskNotExist) Error() string { return fmt.Sprintf("hook task does not exist [task: %d, hook: %d, uuid: %s]", err.TaskID, err.HookID, err.UUID) } func (err ErrHookTaskNotExist) Unwrap() error { return util.ErrNotExist } // HookContentType is the content type of a web hook type HookContentType int const ( // ContentTypeJSON is a JSON payload for web hooks ContentTypeJSON HookContentType = iota + 1 // ContentTypeForm is an url-encoded form payload for web hook ContentTypeForm ) var hookContentTypes = map[string]HookContentType{ "json": ContentTypeJSON, "form": ContentTypeForm, } // ToHookContentType returns HookContentType by given name. func ToHookContentType(name string) HookContentType { return hookContentTypes[name] } // HookTaskCleanupType is the type of cleanup to perform on hook_task type HookTaskCleanupType int const ( // OlderThan hook_task rows will be cleaned up by the age of the row OlderThan HookTaskCleanupType = iota // PerWebhook hook_task rows will be cleaned up by leaving the most recent deliveries for each webhook PerWebhook ) var hookTaskCleanupTypes = map[string]HookTaskCleanupType{ "OlderThan": OlderThan, "PerWebhook": PerWebhook, } // ToHookTaskCleanupType returns HookTaskCleanupType by given name. func ToHookTaskCleanupType(name string) HookTaskCleanupType { return hookTaskCleanupTypes[name] } // Name returns the name of a given web hook's content type func (t HookContentType) Name() string { switch t { case ContentTypeJSON: return "json" case ContentTypeForm: return "form" } return "" } // IsValidHookContentType returns true if given name is a valid hook content type. func IsValidHookContentType(name string) bool { _, ok := hookContentTypes[name] return ok } // Webhook represents a web hook object. type Webhook struct { ID int64 RepoID int64 // An ID of 0 indicates either a default or system webhook OwnerID int64 IsSystemWebhook bool URL string Name string HTTPMethod string ContentType HookContentType Secret string Events string *webhook_module.HookEvent IsActive bool Type webhook_module.HookType Meta string // store hook-specific attributes LastStatus webhook_module.HookStatus // Last delivery status // HeaderAuthorizationEncrypted should be accessed using HeaderAuthorization() and SetHeaderAuthorization() HeaderAuthorizationEncrypted string CreatedUnix timeutil.TimeStamp UpdatedUnix timeutil.TimeStamp } // AfterLoad updates the webhook object upon setting a column func (w *Webhook) AfterLoad() { w.HookEvent = &webhook_module.HookEvent{} if err := json.Unmarshal([]byte(w.Events), w.HookEvent); err != nil { log.Error("Unmarshal[%d]: %v", w.ID, err) } } // History returns history of webhook by given conditions. func (w *Webhook) History(ctx context.Context, page int) ([]*HookTask, error) { return HookTasks(ctx, w.ID, page) } // UpdateEvent handles conversion from HookEvent to Events. func (w *Webhook) UpdateEvent() error { data, err := json.Marshal(w.HookEvent) w.Events = string(data) return err } func (w *Webhook) HasEvent(evt webhook_module.HookEventType) bool { if w.SendEverything { return true } if w.PushOnly { return evt == webhook_module.HookEventPush } checkEvt := evt switch evt { case webhook_module.HookEventPullRequestReviewApproved, webhook_module.HookEventPullRequestReviewRejected, webhook_module.HookEventPullRequestReviewComment: checkEvt = webhook_module.HookEventPullRequestReview } return w.HookEvents[checkEvt] } // EventsArray returns an array of hook events func (w *Webhook) EventsArray() []string { if w.SendEverything { events := make([]string, 0, len(webhook_module.AllEvents())) for _, evt := range webhook_module.AllEvents() { events = append(events, string(evt)) } return events } if w.PushOnly { return []string{string(webhook_module.HookEventPush)} } events := make([]string, 0, len(w.HookEvents)) for event, enabled := range w.HookEvents { if enabled { events = append(events, string(event)) } } return events } // HeaderAuthorization returns the decrypted Authorization header. // Not on the reference (*w), to be accessible on WebhooksNew. func (w Webhook) HeaderAuthorization() (string, error) { if w.HeaderAuthorizationEncrypted == "" { return "", nil } return secret.DecryptSecret(setting.SecretKey, secret.PurposeWebhookAuth, w.HeaderAuthorizationEncrypted) } // SetHeaderAuthorization encrypts and sets the Authorization header. func (w *Webhook) SetHeaderAuthorization(cleartext string) error { if cleartext == "" { w.HeaderAuthorizationEncrypted = "" return nil } ciphertext, err := secret.EncryptSecret(setting.CryptoProfile, setting.SecretKey, secret.PurposeWebhookAuth, cleartext) if err != nil { return err } w.HeaderAuthorizationEncrypted = ciphertext return nil } // CreateWebhook creates a new web hook. func CreateWebhook(ctx context.Context, w *Webhook) error { w.Type = strings.TrimSpace(w.Type) return insertReindexerWebhook(ctx, w) } // CreateWebhooks creates multiple web hooks func CreateWebhooks(ctx context.Context, ws []*Webhook) error { if len(ws) == 0 { return nil } for i := range ws { ws[i].Type = strings.TrimSpace(ws[i].Type) } return insertReindexerWebhooks(ctx, ws) } // DeleteWebhooksByRepoID deletes all repository webhooks and their delivery tasks. func DeleteWebhooksByRepoID(ctx context.Context, repoID int64) error { return deleteReindexerWebhooksByRepoID(ctx, repoID) } // GetWebhookByID returns webhook of repository by given ID. func GetWebhookByID(ctx context.Context, id int64) (*Webhook, error) { return getReindexerWebhook(ctx, id, 0, 0) } // GetWebhookByRepoID returns webhook of repository by given ID. func GetWebhookByRepoID(ctx context.Context, repoID, id int64) (*Webhook, error) { return getReindexerWebhook(ctx, id, repoID, 0) } // GetWebhookByOwnerID returns webhook of a user or organization by given ID. func GetWebhookByOwnerID(ctx context.Context, ownerID, id int64) (*Webhook, error) { return getReindexerWebhook(ctx, id, 0, ownerID) } // ListWebhookOptions are options to filter webhooks on ListWebhooksByOpts type ListWebhookOptions struct { db.ListOptions RepoID int64 OwnerID int64 IsActive optional.Option[bool] } // FindWebhooks returns webhook definitions matching options. func FindWebhooks(ctx context.Context, opts ListWebhookOptions) ([]*Webhook, error) { return findReindexerWebhooks(ctx, opts) } // UpdateWebhook updates information of webhook. func UpdateWebhook(ctx context.Context, w *Webhook) error { return updateReindexerWebhook(ctx, w) } // UpdateWebhookLastStatus updates last status of webhook. func UpdateWebhookLastStatus(ctx context.Context, w *Webhook) error { return updateReindexerWebhookLastStatus(ctx, w.ID, w.LastStatus) } // DeleteWebhookByID uses argument bean as query condition, // ID must be specified and do not assign unnecessary fields. func DeleteWebhookByID(ctx context.Context, id int64) (err error) { return deleteReindexerWebhook(ctx, id) } // DeleteWebhookByRepoID deletes webhook of repository by given ID. func DeleteWebhookByRepoID(ctx context.Context, repoID, id int64) error { if _, err := GetWebhookByRepoID(ctx, repoID, id); err != nil { return err } return DeleteWebhookByID(ctx, id) } // DeleteWebhookByOwnerID deletes webhook of a user or organization by given ID. func DeleteWebhookByOwnerID(ctx context.Context, ownerID, id int64) error { if _, err := GetWebhookByOwnerID(ctx, ownerID, id); err != nil { return err } return DeleteWebhookByID(ctx, id) }