2015-12-05 21:24:13 +03:00
// Copyright 2015 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package repo
import (
"encoding/json"
"errors"
"fmt"
"strings"
"github.com/Unknwon/com"
2016-11-10 19:24:48 +03:00
"code.gitea.io/git"
2016-11-11 12:39:44 +03:00
api "code.gitea.io/sdk/gitea"
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
2015-12-05 21:24:13 +03:00
)
const (
2016-11-07 23:58:22 +03:00
tplHooks base . TplName = "repo/settings/hooks"
tplHookNew base . TplName = "repo/settings/hook_new"
tplOrgHookNew base . TplName = "org/settings/hook_new"
2015-12-05 21:24:13 +03:00
)
2016-11-24 10:04:31 +03:00
// Webhooks render web hooks list page
2016-03-11 19:56:52 +03:00
func Webhooks ( ctx * context . Context ) {
2015-12-05 21:24:13 +03:00
ctx . Data [ "Title" ] = ctx . Tr ( "repo.settings.hooks" )
ctx . Data [ "PageIsSettingsHooks" ] = true
ctx . Data [ "BaseLink" ] = ctx . Repo . RepoLink
2016-11-11 12:39:44 +03:00
ctx . Data [ "Description" ] = ctx . Tr ( "repo.settings.hooks_desc" , "https://godoc.org/code.gitea.io/sdk/gitea" )
2015-12-05 21:24:13 +03:00
ws , err := models . GetWebhooksByRepoID ( ctx . Repo . Repository . ID )
if err != nil {
ctx . Handle ( 500 , "GetWebhooksByRepoID" , err )
return
}
ctx . Data [ "Webhooks" ] = ws
2016-11-07 23:58:22 +03:00
ctx . HTML ( 200 , tplHooks )
2015-12-05 21:24:13 +03:00
}
2016-11-24 10:04:31 +03:00
type orgRepoCtx struct {
2015-12-05 21:24:13 +03:00
OrgID int64
RepoID int64
Link string
NewTemplate base . TplName
}
// getOrgRepoCtx determines whether this is a repo context or organization context.
2016-11-24 10:04:31 +03:00
func getOrgRepoCtx ( ctx * context . Context ) ( * orgRepoCtx , error ) {
2015-12-05 21:24:13 +03:00
if len ( ctx . Repo . RepoLink ) > 0 {
2016-11-24 10:04:31 +03:00
return & orgRepoCtx {
2015-12-05 21:24:13 +03:00
RepoID : ctx . Repo . Repository . ID ,
Link : ctx . Repo . RepoLink ,
2016-11-07 23:58:22 +03:00
NewTemplate : tplHookNew ,
2015-12-05 21:24:13 +03:00
} , nil
}
if len ( ctx . Org . OrgLink ) > 0 {
2016-11-24 10:04:31 +03:00
return & orgRepoCtx {
2016-07-23 20:08:22 +03:00
OrgID : ctx . Org . Organization . ID ,
2015-12-05 21:24:13 +03:00
Link : ctx . Org . OrgLink ,
2016-11-07 23:58:22 +03:00
NewTemplate : tplOrgHookNew ,
2015-12-05 21:24:13 +03:00
} , nil
}
return nil , errors . New ( "Unable to set OrgRepo context" )
}
2016-03-11 19:56:52 +03:00
func checkHookType ( ctx * context . Context ) string {
2015-12-05 21:24:13 +03:00
hookType := strings . ToLower ( ctx . Params ( ":type" ) )
if ! com . IsSliceContainsStr ( setting . Webhook . Types , hookType ) {
ctx . Handle ( 404 , "checkHookType" , nil )
return ""
}
return hookType
}
2016-11-24 10:04:31 +03:00
// WebhooksNew render creating webhook page
2016-03-11 19:56:52 +03:00
func WebhooksNew ( ctx * context . Context ) {
2015-12-05 21:24:13 +03:00
ctx . Data [ "Title" ] = ctx . Tr ( "repo.settings.add_webhook" )
ctx . Data [ "PageIsSettingsHooks" ] = true
ctx . Data [ "PageIsSettingsHooksNew" ] = true
ctx . Data [ "Webhook" ] = models . Webhook { HookEvent : & models . HookEvent { } }
orCtx , err := getOrgRepoCtx ( ctx )
if err != nil {
ctx . Handle ( 500 , "getOrgRepoCtx" , err )
return
}
ctx . Data [ "HookType" ] = checkHookType ( ctx )
if ctx . Written ( ) {
return
}
ctx . Data [ "BaseLink" ] = orCtx . Link
ctx . HTML ( 200 , orCtx . NewTemplate )
}
2016-11-24 10:04:31 +03:00
// ParseHookEvent convert web form content to models.HookEvent
2015-12-05 21:24:13 +03:00
func ParseHookEvent ( form auth . WebhookForm ) * models . HookEvent {
return & models . HookEvent {
PushOnly : form . PushOnly ( ) ,
SendEverything : form . SendEverything ( ) ,
ChooseEvents : form . ChooseEvents ( ) ,
HookEvents : models . HookEvents {
2016-08-14 13:32:24 +03:00
Create : form . Create ,
Push : form . Push ,
PullRequest : form . PullRequest ,
2015-12-05 21:24:13 +03:00
} ,
}
}
2016-11-24 10:04:31 +03:00
// WebHooksNewPost response for creating webhook
2016-03-11 19:56:52 +03:00
func WebHooksNewPost ( ctx * context . Context , form auth . NewWebhookForm ) {
2015-12-05 21:24:13 +03:00
ctx . Data [ "Title" ] = ctx . Tr ( "repo.settings.add_webhook" )
ctx . Data [ "PageIsSettingsHooks" ] = true
ctx . Data [ "PageIsSettingsHooksNew" ] = true
ctx . Data [ "Webhook" ] = models . Webhook { HookEvent : & models . HookEvent { } }
ctx . Data [ "HookType" ] = "gogs"
orCtx , err := getOrgRepoCtx ( ctx )
if err != nil {
ctx . Handle ( 500 , "getOrgRepoCtx" , err )
return
}
ctx . Data [ "BaseLink" ] = orCtx . Link
if ctx . HasError ( ) {
ctx . HTML ( 200 , orCtx . NewTemplate )
return
}
2016-11-07 23:58:22 +03:00
contentType := models . ContentTypeJSON
2016-11-07 19:53:22 +03:00
if models . HookContentType ( form . ContentType ) == models . ContentTypeForm {
contentType = models . ContentTypeForm
2015-12-05 21:24:13 +03:00
}
w := & models . Webhook {
RepoID : orCtx . RepoID ,
URL : form . PayloadURL ,
ContentType : contentType ,
Secret : form . Secret ,
HookEvent : ParseHookEvent ( form . WebhookForm ) ,
IsActive : form . Active ,
HookTaskType : models . GOGS ,
OrgID : orCtx . OrgID ,
}
if err := w . UpdateEvent ( ) ; err != nil {
ctx . Handle ( 500 , "UpdateEvent" , err )
return
} else if err := models . CreateWebhook ( w ) ; err != nil {
ctx . Handle ( 500 , "CreateWebhook" , err )
return
}
ctx . Flash . Success ( ctx . Tr ( "repo.settings.add_hook_success" ) )
ctx . Redirect ( orCtx . Link + "/settings/hooks" )
}
2016-11-24 10:04:31 +03:00
// SlackHooksNewPost response for creating slack hook
2016-03-11 19:56:52 +03:00
func SlackHooksNewPost ( ctx * context . Context , form auth . NewSlackHookForm ) {
2015-12-05 21:24:13 +03:00
ctx . Data [ "Title" ] = ctx . Tr ( "repo.settings" )
ctx . Data [ "PageIsSettingsHooks" ] = true
ctx . Data [ "PageIsSettingsHooksNew" ] = true
ctx . Data [ "Webhook" ] = models . Webhook { HookEvent : & models . HookEvent { } }
orCtx , err := getOrgRepoCtx ( ctx )
if err != nil {
ctx . Handle ( 500 , "getOrgRepoCtx" , err )
return
}
if ctx . HasError ( ) {
ctx . HTML ( 200 , orCtx . NewTemplate )
return
}
meta , err := json . Marshal ( & models . SlackMeta {
Channel : form . Channel ,
Username : form . Username ,
IconURL : form . IconURL ,
Color : form . Color ,
} )
if err != nil {
ctx . Handle ( 500 , "Marshal" , err )
return
}
w := & models . Webhook {
RepoID : orCtx . RepoID ,
URL : form . PayloadURL ,
2016-11-07 23:58:22 +03:00
ContentType : models . ContentTypeJSON ,
2015-12-05 21:24:13 +03:00
HookEvent : ParseHookEvent ( form . WebhookForm ) ,
IsActive : form . Active ,
HookTaskType : models . SLACK ,
Meta : string ( meta ) ,
OrgID : orCtx . OrgID ,
}
if err := w . UpdateEvent ( ) ; err != nil {
ctx . Handle ( 500 , "UpdateEvent" , err )
return
} else if err := models . CreateWebhook ( w ) ; err != nil {
ctx . Handle ( 500 , "CreateWebhook" , err )
return
}
ctx . Flash . Success ( ctx . Tr ( "repo.settings.add_hook_success" ) )
ctx . Redirect ( orCtx . Link + "/settings/hooks" )
}
2016-11-24 10:04:31 +03:00
func checkWebhook ( ctx * context . Context ) ( * orgRepoCtx , * models . Webhook ) {
2015-12-05 21:24:13 +03:00
ctx . Data [ "RequireHighlightJS" ] = true
orCtx , err := getOrgRepoCtx ( ctx )
if err != nil {
ctx . Handle ( 500 , "getOrgRepoCtx" , err )
return nil , nil
}
ctx . Data [ "BaseLink" ] = orCtx . Link
2016-07-15 20:02:55 +03:00
var w * models . Webhook
if orCtx . RepoID > 0 {
w , err = models . GetWebhookByRepoID ( ctx . Repo . Repository . ID , ctx . ParamsInt64 ( ":id" ) )
} else {
2016-07-23 20:08:22 +03:00
w , err = models . GetWebhookByOrgID ( ctx . Org . Organization . ID , ctx . ParamsInt64 ( ":id" ) )
2016-07-15 20:02:55 +03:00
}
2015-12-05 21:24:13 +03:00
if err != nil {
if models . IsErrWebhookNotExist ( err ) {
ctx . Handle ( 404 , "GetWebhookByID" , nil )
} else {
ctx . Handle ( 500 , "GetWebhookByID" , err )
}
return nil , nil
}
switch w . HookTaskType {
case models . SLACK :
ctx . Data [ "SlackHook" ] = w . GetSlackHook ( )
ctx . Data [ "HookType" ] = "slack"
default :
ctx . Data [ "HookType" ] = "gogs"
}
ctx . Data [ "History" ] , err = w . History ( 1 )
if err != nil {
ctx . Handle ( 500 , "History" , err )
}
return orCtx , w
}
2016-11-24 10:04:31 +03:00
// WebHooksEdit render editing web hook page
2016-03-11 19:56:52 +03:00
func WebHooksEdit ( ctx * context . Context ) {
2015-12-05 21:24:13 +03:00
ctx . Data [ "Title" ] = ctx . Tr ( "repo.settings.update_webhook" )
ctx . Data [ "PageIsSettingsHooks" ] = true
ctx . Data [ "PageIsSettingsHooksEdit" ] = true
orCtx , w := checkWebhook ( ctx )
if ctx . Written ( ) {
return
}
ctx . Data [ "Webhook" ] = w
ctx . HTML ( 200 , orCtx . NewTemplate )
}
2016-11-24 10:04:31 +03:00
// WebHooksEditPost response for editing web hook
2016-03-11 19:56:52 +03:00
func WebHooksEditPost ( ctx * context . Context , form auth . NewWebhookForm ) {
2015-12-05 21:24:13 +03:00
ctx . Data [ "Title" ] = ctx . Tr ( "repo.settings.update_webhook" )
ctx . Data [ "PageIsSettingsHooks" ] = true
ctx . Data [ "PageIsSettingsHooksEdit" ] = true
orCtx , w := checkWebhook ( ctx )
if ctx . Written ( ) {
return
}
ctx . Data [ "Webhook" ] = w
if ctx . HasError ( ) {
ctx . HTML ( 200 , orCtx . NewTemplate )
return
}
2016-11-07 23:58:22 +03:00
contentType := models . ContentTypeJSON
2016-11-07 19:53:22 +03:00
if models . HookContentType ( form . ContentType ) == models . ContentTypeForm {
contentType = models . ContentTypeForm
2015-12-05 21:24:13 +03:00
}
w . URL = form . PayloadURL
w . ContentType = contentType
w . Secret = form . Secret
w . HookEvent = ParseHookEvent ( form . WebhookForm )
w . IsActive = form . Active
if err := w . UpdateEvent ( ) ; err != nil {
ctx . Handle ( 500 , "UpdateEvent" , err )
return
} else if err := models . UpdateWebhook ( w ) ; err != nil {
ctx . Handle ( 500 , "WebHooksEditPost" , err )
return
}
ctx . Flash . Success ( ctx . Tr ( "repo.settings.update_hook_success" ) )
ctx . Redirect ( fmt . Sprintf ( "%s/settings/hooks/%d" , orCtx . Link , w . ID ) )
}
2016-11-27 14:59:12 +03:00
// SlackHooksEditPost response for editing slack hook
2016-03-11 19:56:52 +03:00
func SlackHooksEditPost ( ctx * context . Context , form auth . NewSlackHookForm ) {
2015-12-05 21:24:13 +03:00
ctx . Data [ "Title" ] = ctx . Tr ( "repo.settings" )
ctx . Data [ "PageIsSettingsHooks" ] = true
ctx . Data [ "PageIsSettingsHooksEdit" ] = true
orCtx , w := checkWebhook ( ctx )
if ctx . Written ( ) {
return
}
ctx . Data [ "Webhook" ] = w
if ctx . HasError ( ) {
ctx . HTML ( 200 , orCtx . NewTemplate )
return
}
meta , err := json . Marshal ( & models . SlackMeta {
Channel : form . Channel ,
Username : form . Username ,
IconURL : form . IconURL ,
Color : form . Color ,
} )
if err != nil {
ctx . Handle ( 500 , "Marshal" , err )
return
}
w . URL = form . PayloadURL
w . Meta = string ( meta )
w . HookEvent = ParseHookEvent ( form . WebhookForm )
w . IsActive = form . Active
if err := w . UpdateEvent ( ) ; err != nil {
ctx . Handle ( 500 , "UpdateEvent" , err )
return
} else if err := models . UpdateWebhook ( w ) ; err != nil {
ctx . Handle ( 500 , "UpdateWebhook" , err )
return
}
ctx . Flash . Success ( ctx . Tr ( "repo.settings.update_hook_success" ) )
ctx . Redirect ( fmt . Sprintf ( "%s/settings/hooks/%d" , orCtx . Link , w . ID ) )
}
2016-11-24 10:04:31 +03:00
// TestWebhook test if web hook is work fine
2016-03-11 19:56:52 +03:00
func TestWebhook ( ctx * context . Context ) {
2016-08-15 15:53:47 +03:00
// Grab latest commit or fake one if it's empty repository.
commit := ctx . Repo . Commit
if commit == nil {
ghost := models . NewGhostUser ( )
commit = & git . Commit {
2016-12-22 12:30:52 +03:00
ID : git . MustIDFromString ( git . EmptySHA ) ,
2016-08-15 15:53:47 +03:00
Author : ghost . NewGitSig ( ) ,
Committer : ghost . NewGitSig ( ) ,
CommitMessage : "This is a fake commit" ,
}
}
2016-08-14 14:17:26 +03:00
apiUser := ctx . User . APIFormat ( )
2015-12-05 21:24:13 +03:00
p := & api . PushPayload {
2016-12-22 12:30:52 +03:00
Ref : git . BranchPrefix + ctx . Repo . Repository . DefaultBranch ,
2016-08-15 15:53:47 +03:00
Before : commit . ID . String ( ) ,
After : commit . ID . String ( ) ,
2015-12-05 21:24:13 +03:00
Commits : [ ] * api . PayloadCommit {
{
2016-08-15 15:53:47 +03:00
ID : commit . ID . String ( ) ,
Message : commit . Message ( ) ,
2016-08-16 20:19:09 +03:00
URL : ctx . Repo . Repository . HTMLURL ( ) + "/commit/" + commit . ID . String ( ) ,
2016-08-14 14:17:26 +03:00
Author : & api . PayloadUser {
2016-08-15 15:53:47 +03:00
Name : commit . Author . Name ,
Email : commit . Author . Email ,
2016-08-10 08:01:57 +03:00
} ,
2016-08-14 14:17:26 +03:00
Committer : & api . PayloadUser {
2016-08-15 15:53:47 +03:00
Name : commit . Committer . Name ,
Email : commit . Committer . Email ,
2015-12-05 21:24:13 +03:00
} ,
} ,
} ,
2016-12-06 02:48:51 +03:00
Repo : ctx . Repo . Repository . APIFormat ( models . AccessModeNone ) ,
2016-08-14 14:17:26 +03:00
Pusher : apiUser ,
Sender : apiUser ,
2015-12-05 21:24:13 +03:00
}
2016-11-07 18:37:32 +03:00
if err := models . PrepareWebhooks ( ctx . Repo . Repository , models . HookEventPush , p ) ; err != nil {
2015-12-05 21:24:13 +03:00
ctx . Flash . Error ( "PrepareWebhooks: " + err . Error ( ) )
ctx . Status ( 500 )
} else {
go models . HookQueue . Add ( ctx . Repo . Repository . ID )
ctx . Flash . Info ( ctx . Tr ( "repo.settings.webhook.test_delivery_success" ) )
ctx . Status ( 200 )
}
}
2016-11-24 10:04:31 +03:00
// DeleteWebhook delete a webhook
2016-03-11 19:56:52 +03:00
func DeleteWebhook ( ctx * context . Context ) {
2016-07-17 03:33:59 +03:00
if err := models . DeleteWebhookByRepoID ( ctx . Repo . Repository . ID , ctx . QueryInt64 ( "id" ) ) ; err != nil {
ctx . Flash . Error ( "DeleteWebhookByRepoID: " + err . Error ( ) )
2015-12-05 21:24:13 +03:00
} else {
ctx . Flash . Success ( ctx . Tr ( "repo.settings.webhook_deletion_success" ) )
}
ctx . JSON ( 200 , map [ string ] interface { } {
"redirect" : ctx . Repo . RepoLink + "/settings/hooks" ,
} )
}