code.gitea.io/gitea@v1.22.3/routers/api/v1/repo/hook.go (about)

     1  // Copyright 2014 The Gogs Authors. All rights reserved.
     2  // Copyright 2020 The Gitea Authors.
     3  // SPDX-License-Identifier: MIT
     4  
     5  package repo
     6  
     7  import (
     8  	"net/http"
     9  
    10  	"code.gitea.io/gitea/models/db"
    11  	"code.gitea.io/gitea/models/perm"
    12  	access_model "code.gitea.io/gitea/models/perm/access"
    13  	"code.gitea.io/gitea/models/webhook"
    14  	"code.gitea.io/gitea/modules/git"
    15  	"code.gitea.io/gitea/modules/setting"
    16  	api "code.gitea.io/gitea/modules/structs"
    17  	"code.gitea.io/gitea/modules/web"
    18  	webhook_module "code.gitea.io/gitea/modules/webhook"
    19  	"code.gitea.io/gitea/routers/api/v1/utils"
    20  	"code.gitea.io/gitea/services/context"
    21  	"code.gitea.io/gitea/services/convert"
    22  	webhook_service "code.gitea.io/gitea/services/webhook"
    23  )
    24  
    25  // ListHooks list all hooks of a repository
    26  func ListHooks(ctx *context.APIContext) {
    27  	// swagger:operation GET /repos/{owner}/{repo}/hooks repository repoListHooks
    28  	// ---
    29  	// summary: List the hooks in a repository
    30  	// produces:
    31  	// - application/json
    32  	// parameters:
    33  	// - name: owner
    34  	//   in: path
    35  	//   description: owner of the repo
    36  	//   type: string
    37  	//   required: true
    38  	// - name: repo
    39  	//   in: path
    40  	//   description: name of the repo
    41  	//   type: string
    42  	//   required: true
    43  	// - name: page
    44  	//   in: query
    45  	//   description: page number of results to return (1-based)
    46  	//   type: integer
    47  	// - name: limit
    48  	//   in: query
    49  	//   description: page size of results
    50  	//   type: integer
    51  	// responses:
    52  	//   "200":
    53  	//     "$ref": "#/responses/HookList"
    54  	//   "404":
    55  	//     "$ref": "#/responses/notFound"
    56  
    57  	opts := &webhook.ListWebhookOptions{
    58  		ListOptions: utils.GetListOptions(ctx),
    59  		RepoID:      ctx.Repo.Repository.ID,
    60  	}
    61  
    62  	hooks, count, err := db.FindAndCount[webhook.Webhook](ctx, opts)
    63  	if err != nil {
    64  		ctx.InternalServerError(err)
    65  		return
    66  	}
    67  
    68  	apiHooks := make([]*api.Hook, len(hooks))
    69  	for i := range hooks {
    70  		apiHooks[i], err = webhook_service.ToHook(ctx.Repo.RepoLink, hooks[i])
    71  		if err != nil {
    72  			ctx.InternalServerError(err)
    73  			return
    74  		}
    75  	}
    76  
    77  	ctx.SetTotalCountHeader(count)
    78  	ctx.JSON(http.StatusOK, &apiHooks)
    79  }
    80  
    81  // GetHook get a repo's hook by id
    82  func GetHook(ctx *context.APIContext) {
    83  	// swagger:operation GET /repos/{owner}/{repo}/hooks/{id} repository repoGetHook
    84  	// ---
    85  	// summary: Get a hook
    86  	// produces:
    87  	// - application/json
    88  	// parameters:
    89  	// - name: owner
    90  	//   in: path
    91  	//   description: owner of the repo
    92  	//   type: string
    93  	//   required: true
    94  	// - name: repo
    95  	//   in: path
    96  	//   description: name of the repo
    97  	//   type: string
    98  	//   required: true
    99  	// - name: id
   100  	//   in: path
   101  	//   description: id of the hook to get
   102  	//   type: integer
   103  	//   format: int64
   104  	//   required: true
   105  	// responses:
   106  	//   "200":
   107  	//     "$ref": "#/responses/Hook"
   108  	//   "404":
   109  	//     "$ref": "#/responses/notFound"
   110  
   111  	repo := ctx.Repo
   112  	hookID := ctx.ParamsInt64(":id")
   113  	hook, err := utils.GetRepoHook(ctx, repo.Repository.ID, hookID)
   114  	if err != nil {
   115  		return
   116  	}
   117  	apiHook, err := webhook_service.ToHook(repo.RepoLink, hook)
   118  	if err != nil {
   119  		ctx.InternalServerError(err)
   120  		return
   121  	}
   122  	ctx.JSON(http.StatusOK, apiHook)
   123  }
   124  
   125  // TestHook tests a hook
   126  func TestHook(ctx *context.APIContext) {
   127  	// swagger:operation POST /repos/{owner}/{repo}/hooks/{id}/tests repository repoTestHook
   128  	// ---
   129  	// summary: Test a push webhook
   130  	// produces:
   131  	// - application/json
   132  	// parameters:
   133  	// - name: owner
   134  	//   in: path
   135  	//   description: owner of the repo
   136  	//   type: string
   137  	//   required: true
   138  	// - name: repo
   139  	//   in: path
   140  	//   description: name of the repo
   141  	//   type: string
   142  	//   required: true
   143  	// - name: id
   144  	//   in: path
   145  	//   description: id of the hook to test
   146  	//   type: integer
   147  	//   format: int64
   148  	//   required: true
   149  	// - name: ref
   150  	//   in: query
   151  	//   description: "The name of the commit/branch/tag, indicates which commit will be loaded to the webhook payload."
   152  	//   type: string
   153  	//   required: false
   154  	// responses:
   155  	//   "204":
   156  	//     "$ref": "#/responses/empty"
   157  	//   "404":
   158  	//     "$ref": "#/responses/notFound"
   159  
   160  	if ctx.Repo.Commit == nil {
   161  		// if repo does not have any commits, then don't send a webhook
   162  		ctx.Status(http.StatusNoContent)
   163  		return
   164  	}
   165  
   166  	ref := git.BranchPrefix + ctx.Repo.Repository.DefaultBranch
   167  	if r := ctx.FormTrim("ref"); r != "" {
   168  		ref = r
   169  	}
   170  
   171  	hookID := ctx.ParamsInt64(":id")
   172  	hook, err := utils.GetRepoHook(ctx, ctx.Repo.Repository.ID, hookID)
   173  	if err != nil {
   174  		return
   175  	}
   176  
   177  	commit := convert.ToPayloadCommit(ctx, ctx.Repo.Repository, ctx.Repo.Commit)
   178  
   179  	commitID := ctx.Repo.Commit.ID.String()
   180  	if err := webhook_service.PrepareWebhook(ctx, hook, webhook_module.HookEventPush, &api.PushPayload{
   181  		Ref:          ref,
   182  		Before:       commitID,
   183  		After:        commitID,
   184  		CompareURL:   setting.AppURL + ctx.Repo.Repository.ComposeCompareURL(commitID, commitID),
   185  		Commits:      []*api.PayloadCommit{commit},
   186  		TotalCommits: 1,
   187  		HeadCommit:   commit,
   188  		Repo:         convert.ToRepo(ctx, ctx.Repo.Repository, access_model.Permission{AccessMode: perm.AccessModeNone}),
   189  		Pusher:       convert.ToUserWithAccessMode(ctx, ctx.Doer, perm.AccessModeNone),
   190  		Sender:       convert.ToUserWithAccessMode(ctx, ctx.Doer, perm.AccessModeNone),
   191  	}); err != nil {
   192  		ctx.Error(http.StatusInternalServerError, "PrepareWebhook: ", err)
   193  		return
   194  	}
   195  
   196  	ctx.Status(http.StatusNoContent)
   197  }
   198  
   199  // CreateHook create a hook for a repository
   200  func CreateHook(ctx *context.APIContext) {
   201  	// swagger:operation POST /repos/{owner}/{repo}/hooks repository repoCreateHook
   202  	// ---
   203  	// summary: Create a hook
   204  	// consumes:
   205  	// - application/json
   206  	// produces:
   207  	// - application/json
   208  	// parameters:
   209  	// - name: owner
   210  	//   in: path
   211  	//   description: owner of the repo
   212  	//   type: string
   213  	//   required: true
   214  	// - name: repo
   215  	//   in: path
   216  	//   description: name of the repo
   217  	//   type: string
   218  	//   required: true
   219  	// - name: body
   220  	//   in: body
   221  	//   schema:
   222  	//     "$ref": "#/definitions/CreateHookOption"
   223  	// responses:
   224  	//   "201":
   225  	//     "$ref": "#/responses/Hook"
   226  	//   "404":
   227  	//     "$ref": "#/responses/notFound"
   228  
   229  	utils.AddRepoHook(ctx, web.GetForm(ctx).(*api.CreateHookOption))
   230  }
   231  
   232  // EditHook modify a hook of a repository
   233  func EditHook(ctx *context.APIContext) {
   234  	// swagger:operation PATCH /repos/{owner}/{repo}/hooks/{id} repository repoEditHook
   235  	// ---
   236  	// summary: Edit a hook in a repository
   237  	// produces:
   238  	// - application/json
   239  	// parameters:
   240  	// - name: owner
   241  	//   in: path
   242  	//   description: owner of the repo
   243  	//   type: string
   244  	//   required: true
   245  	// - name: repo
   246  	//   in: path
   247  	//   description: name of the repo
   248  	//   type: string
   249  	//   required: true
   250  	// - name: id
   251  	//   in: path
   252  	//   description: index of the hook
   253  	//   type: integer
   254  	//   format: int64
   255  	//   required: true
   256  	// - name: body
   257  	//   in: body
   258  	//   schema:
   259  	//     "$ref": "#/definitions/EditHookOption"
   260  	// responses:
   261  	//   "200":
   262  	//     "$ref": "#/responses/Hook"
   263  	//   "404":
   264  	//     "$ref": "#/responses/notFound"
   265  	form := web.GetForm(ctx).(*api.EditHookOption)
   266  	hookID := ctx.ParamsInt64(":id")
   267  	utils.EditRepoHook(ctx, form, hookID)
   268  }
   269  
   270  // DeleteHook delete a hook of a repository
   271  func DeleteHook(ctx *context.APIContext) {
   272  	// swagger:operation DELETE /repos/{owner}/{repo}/hooks/{id} repository repoDeleteHook
   273  	// ---
   274  	// summary: Delete a hook in a repository
   275  	// produces:
   276  	// - application/json
   277  	// parameters:
   278  	// - name: owner
   279  	//   in: path
   280  	//   description: owner of the repo
   281  	//   type: string
   282  	//   required: true
   283  	// - name: repo
   284  	//   in: path
   285  	//   description: name of the repo
   286  	//   type: string
   287  	//   required: true
   288  	// - name: id
   289  	//   in: path
   290  	//   description: id of the hook to delete
   291  	//   type: integer
   292  	//   format: int64
   293  	//   required: true
   294  	// responses:
   295  	//   "204":
   296  	//     "$ref": "#/responses/empty"
   297  	//   "404":
   298  	//     "$ref": "#/responses/notFound"
   299  	if err := webhook.DeleteWebhookByRepoID(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":id")); err != nil {
   300  		if webhook.IsErrWebhookNotExist(err) {
   301  			ctx.NotFound()
   302  		} else {
   303  			ctx.Error(http.StatusInternalServerError, "DeleteWebhookByRepoID", err)
   304  		}
   305  		return
   306  	}
   307  	ctx.Status(http.StatusNoContent)
   308  }