From f5764bbf269d82e7e344834a5eeb8de82356cfde Mon Sep 17 00:00:00 2001
From: Giteabot <teabot@gitea.io>
Date: Sun, 31 Dec 2023 20:53:09 +0800
Subject: [PATCH] Fix: system webhooks API bug (#28531) (#28666)

Backport #28531 by @pulltheflower

- Fix the bug about admin/hooks API that `GET /admin/hooks` can only
fetch system_hooks, `POST /admin/hooks` can only create default_hooks.

Co-authored-by: vincent <38434877+pulltheflower@users.noreply.github.com>
(cherry picked from commit 3c79315cf2308e68caba5bd7f2f94aa3472d9425)
---
 routers/api/v1/utils/hook.go | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/routers/api/v1/utils/hook.go b/routers/api/v1/utils/hook.go
index 1f879ac341..494d7f99dd 100644
--- a/routers/api/v1/utils/hook.go
+++ b/routers/api/v1/utils/hook.go
@@ -6,6 +6,7 @@ package utils
 import (
 	"fmt"
 	"net/http"
+	"strconv"
 	"strings"
 
 	user_model "code.gitea.io/gitea/models/user"
@@ -162,6 +163,7 @@ func pullHook(events []string, event string) bool {
 // addHook add the hook specified by `form`, `ownerID` and `repoID`. If there is
 // an error, write to `ctx` accordingly. Return (webhook, ok)
 func addHook(ctx *context.APIContext, form *api.CreateHookOption, ownerID, repoID int64) (*webhook.Webhook, bool) {
+	var isSystemWebhook bool
 	if !checkCreateHookOption(ctx, form) {
 		return nil, false
 	}
@@ -169,13 +171,22 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, ownerID, repoI
 	if len(form.Events) == 0 {
 		form.Events = []string{"push"}
 	}
+	if form.Config["is_system_webhook"] != "" {
+		sw, err := strconv.ParseBool(form.Config["is_system_webhook"])
+		if err != nil {
+			ctx.Error(http.StatusUnprocessableEntity, "", "Invalid is_system_webhook value")
+			return nil, false
+		}
+		isSystemWebhook = sw
+	}
 	w := &webhook.Webhook{
-		OwnerID:     ownerID,
-		RepoID:      repoID,
-		URL:         form.Config["url"],
-		ContentType: webhook.ToHookContentType(form.Config["content_type"]),
-		Secret:      form.Config["secret"],
-		HTTPMethod:  "POST",
+		OwnerID:         ownerID,
+		RepoID:          repoID,
+		URL:             form.Config["url"],
+		ContentType:     webhook.ToHookContentType(form.Config["content_type"]),
+		Secret:          form.Config["secret"],
+		HTTPMethod:      "POST",
+		IsSystemWebhook: isSystemWebhook,
 		HookEvent: &webhook_module.HookEvent{
 			ChooseEvents: true,
 			HookEvents: webhook_module.HookEvents{