Finish new web hook pages

This commit is contained in:
Unknwon 2014-08-09 15:40:10 -07:00
parent 9820b8e134
commit 9a1d5d2489
23 changed files with 249 additions and 265 deletions

View file

@ -11,10 +11,10 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"strings" "strings"
"time"
"github.com/codegangsta/cli"
"github.com/Unknwon/com" "github.com/Unknwon/com"
"github.com/codegangsta/cli"
"github.com/gogits/gogs/models" "github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/log" "github.com/gogits/gogs/modules/log"
@ -184,19 +184,29 @@ func runServ(k *cli.Context) {
if isWrite { if isWrite {
tasks, err := models.GetUpdateTasksByUuid(uuid) tasks, err := models.GetUpdateTasksByUuid(uuid)
if err != nil { if err != nil {
log.GitLogger.Fatal(2, "Fail to get update task: %v", err) log.GitLogger.Fatal(2, "GetUpdateTasksByUuid: %v", err)
} }
for _, task := range tasks { for _, task := range tasks {
err = models.Update(task.RefName, task.OldCommitId, task.NewCommitId, err = models.Update(task.RefName, task.OldCommitId, task.NewCommitId,
user.Name, repoUserName, repoName, user.Id) user.Name, repoUserName, repoName, user.Id)
if err != nil { if err != nil {
log.GitLogger.Fatal(2, "Fail to update: %v", err) log.GitLogger.Error(2, "Fail to update: %v", err)
} }
} }
if err = models.DelUpdateTasksByUuid(uuid); err != nil { if err = models.DelUpdateTasksByUuid(uuid); err != nil {
log.GitLogger.Fatal(2, "Fail to del update task: %v", err) log.GitLogger.Fatal(2, "DelUpdateTasksByUuid: %v", err)
} }
} }
// Update key activity.
key, err := models.GetPublicKeyById(keyId)
if err != nil {
log.GitLogger.Fatal(2, "GetPublicKeyById: %v", err)
}
key.Updated = time.Now()
if err = models.UpdatePublicKey(key); err != nil {
log.GitLogger.Fatal(2, "UpdatePublicKey: %v", err)
}
} }

View file

@ -256,8 +256,8 @@ func runWeb(*cli.Context) {
m.Group("/settings", func(r *macaron.Router) { m.Group("/settings", func(r *macaron.Router) {
r.Route("/collaboration", "GET,POST", repo.SettingsCollaboration) r.Route("/collaboration", "GET,POST", repo.SettingsCollaboration)
r.Get("/hooks", repo.Webhooks) r.Get("/hooks", repo.Webhooks)
r.Get("/hooks/new", repo.WebHooksAdd) r.Get("/hooks/new", repo.WebHooksNew)
r.Post("/hooks/add", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksAddPost) r.Post("/hooks/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost)
r.Get("/hooks/:id", repo.WebHooksEdit) r.Get("/hooks/:id", repo.WebHooksEdit)
r.Post("/hooks/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost) r.Post("/hooks/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
}) })

View file

@ -62,6 +62,7 @@ Password = Password
Retype = Re-type password Retype = Re-type password
SSHTitle = SSH key name SSHTitle = SSH key name
HttpsUrl = HTTPS URL HttpsUrl = HTTPS URL
PayloadUrl = Payload URL
require_error = ` cannot be empty.` require_error = ` cannot be empty.`
alpha_dash_error = ` must be valid alpha or numeric or dash(-_) characters.` alpha_dash_error = ` must be valid alpha or numeric or dash(-_) characters.`
@ -181,6 +182,19 @@ settings.remove_collaborator_success = Collaborator has been removed.
settings.add_webhook = Add Webhook settings.add_webhook = Add Webhook
settings.hooks_desc = Webhooks allow external services to be notified when certain events happen on Gogs. When the specified events happen, we'll send a POST request to each of the URLs you provide. Learn more in our <a target="_blank" href="http://gogs.io/docs/features/webhook.html">Webhooks Guide</a>. settings.hooks_desc = Webhooks allow external services to be notified when certain events happen on Gogs. When the specified events happen, we'll send a POST request to each of the URLs you provide. Learn more in our <a target="_blank" href="http://gogs.io/docs/features/webhook.html">Webhooks Guide</a>.
settings.remove_hook_success = Webhook has been removed. settings.remove_hook_success = Webhook has been removed.
settings.add_webhook_desc = Well send a <code>POST</code> request to the URL below with details of any subscribed events. You can also specify which data format you'd like to receive (JSON, <code>x-www-form-urlencoded</code>, <em>etc</em>). More information can be found in <a target="_blank" href="http://gogs.io/docs/features/webhook.html">Webhooks Guide</a>.
settings.payload_url = Payload URL
settings.content_type = Content Type
settings.secret = Secret
settings.event_desc = Which events would you like to trigger this webhook?
settings.event_push_only = Just the <code>push</code> event.
settings.active = Active
settings.active_helper = We will deliver event details when this hook is triggered.
settings.add_hook_success = New webhook has been added.
settings.update_webhook = Update Webhook
settings.update_hook_success = Webhook has been updated.
settings.delete_webhook = Delete Webhook
settings.recent_deliveries = Recent Deliveries
[org] [org]
org_name_holder = Organization Name org_name_holder = Organization Name

View file

@ -62,6 +62,7 @@ Password = 密码
Retype = 确认密码 Retype = 确认密码
SSHTitle = SSH 密钥名称 SSHTitle = SSH 密钥名称
HttpsUrl = HTTPS URL 地址 HttpsUrl = HTTPS URL 地址
PayloadUrl = 推送地址
require_error = 不能为空。 require_error = 不能为空。
alpha_dash_error = 必须为英文字母、阿拉伯数字或横线(-_ alpha_dash_error = 必须为英文字母、阿拉伯数字或横线(-_
@ -181,6 +182,19 @@ settings.remove_collaborator_success = 被操作的协作者已经被收回权
settings.add_webhook = 添加 Web 钩子 settings.add_webhook = 添加 Web 钩子
settings.hooks_desc = Web 钩子允许您设定在 Gogs 上发生指定事件时对指定 URL 发送 POST 通知。查看 <a target="_blank" href="http://gogs.io/docs/features/webhook.html">Webhooks 文档</a> 获取更多信息。 settings.hooks_desc = Web 钩子允许您设定在 Gogs 上发生指定事件时对指定 URL 发送 POST 通知。查看 <a target="_blank" href="http://gogs.io/docs/features/webhook.html">Webhooks 文档</a> 获取更多信息。
settings.remove_hook_success = Web 钩子删除成功! settings.remove_hook_success = Web 钩子删除成功!
settings.add_webhook_desc = 我们会通过 <code>POST</code> 请求将订阅事件信息发送至向指定 URL 地址。您可以设置不同的数据接收方式JSON 或 <code>x-www-form-urlencoded</code>)。 请查阅 <a target="_blank" href="http://gogs.io/docs/features/webhook.html">Webhooks 文档</a> 获取更多信息。
settings.payload_url = 推送地址
settings.content_type = 数据格式
settings.secret = 密钥文本
settings.event_desc = 请设置您希望触发 Web 钩子的事件:
settings.event_push_only = 只推送 <code>push</code> 事件。
settings.active = 是否激活
settings.active_helper = 当指定事件发生时我们将会触发此 Web 钩子。
settings.add_hook_success = Web 钩子添加成功!
settings.update_webhook = 更新 Web 钩子
settings.update_hook_success = Web 钩子更新成功!
settings.delete_webhook = 删除 Web 钩子
settings.recent_deliveries = 最近推送记录
[org] [org]
org_name_holder = 组织名称 org_name_holder = 组织名称

View file

@ -209,6 +209,18 @@ func AddPublicKey(key *PublicKey) (err error) {
return nil return nil
} }
// GetPublicKeyById returns public key by given ID.
func GetPublicKeyById(keyId int64) (*PublicKey, error) {
key := new(PublicKey)
has, err := x.Id(keyId).Get(key)
if err != nil {
return nil, err
} else if !has {
return nil, ErrKeyNotExist
}
return key, nil
}
// ListPublicKey returns a list of all public keys that user has. // ListPublicKey returns a list of all public keys that user has.
func ListPublicKey(uid int64) ([]*PublicKey, error) { func ListPublicKey(uid int64) ([]*PublicKey, error) {
keys := make([]*PublicKey, 0, 5) keys := make([]*PublicKey, 0, 5)
@ -277,6 +289,12 @@ func rewriteAuthorizedKeys(key *PublicKey, p, tmpP string) error {
return nil return nil
} }
// UpdatePublicKey updates given public key.
func UpdatePublicKey(key *PublicKey) error {
_, err := x.Id(key.Id).AllCols().Update(key)
return err
}
// DeletePublicKey deletes SSH key information both in database and authorized_keys file. // DeletePublicKey deletes SSH key information both in database and authorized_keys file.
func DeletePublicKey(key *PublicKey) error { func DeletePublicKey(key *PublicKey) error {
has, err := x.Get(key) has, err := x.Get(key)

View file

@ -12,6 +12,7 @@ import (
"github.com/gogits/gogs/modules/httplib" "github.com/gogits/gogs/modules/httplib"
"github.com/gogits/gogs/modules/log" "github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
"github.com/gogits/gogs/modules/uuid"
) )
var ( var (
@ -122,6 +123,12 @@ const (
SERVICE SERVICE
) )
type HookEventType string
const (
PUSH HookEventType = "push"
)
type PayloadAuthor struct { type PayloadAuthor struct {
Name string `json:"name"` Name string `json:"name"`
Email string `json:"email"` Email string `json:"email"`
@ -157,13 +164,16 @@ type Payload struct {
// HookTask represents a hook task. // HookTask represents a hook task.
type HookTask struct { type HookTask struct {
Id int64 Id int64
Uuid string
Type HookTaskType Type HookTaskType
Url string Url string
*Payload `xorm:"-"` *Payload `xorm:"-"`
PayloadContent string `xorm:"TEXT"` PayloadContent string `xorm:"TEXT"`
ContentType HookContentType ContentType HookContentType
EventType HookEventType
IsSsl bool IsSsl bool
IsDeliveried bool IsDeliveried bool
IsSucceed bool
} }
// CreateHookTask creates a new hook task, // CreateHookTask creates a new hook task,
@ -173,6 +183,7 @@ func CreateHookTask(t *HookTask) error {
if err != nil { if err != nil {
return err return err
} }
t.Uuid = uuid.NewV4().String()
t.PayloadContent = string(data) t.PayloadContent = string(data)
_, err = x.Insert(t) _, err = x.Insert(t)
return err return err
@ -190,20 +201,32 @@ func DeliverHooks() {
x.Where("is_deliveried=?", false).Iterate(new(HookTask), x.Where("is_deliveried=?", false).Iterate(new(HookTask),
func(idx int, bean interface{}) error { func(idx int, bean interface{}) error {
t := bean.(*HookTask) t := bean.(*HookTask)
// Only support JSON now. req := httplib.Post(t.Url).SetTimeout(timeout, timeout).
if _, err := httplib.Post(t.Url).SetTimeout(timeout, timeout). Header("X-Gogs-Delivery", t.Uuid).
Body([]byte(t.PayloadContent)).Response(); err != nil { Header("X-Gogs-Event", string(t.EventType))
log.Error(4, "webhook.DeliverHooks(Delivery): %v", err)
return nil switch t.ContentType {
case JSON:
req = req.Header("Content-Type", "application/json").Body(t.PayloadContent)
case FORM:
req.Param("payload", t.PayloadContent)
} }
t.IsDeliveried = true t.IsDeliveried = true
// TODO: record response.
if _, err := req.Response(); err != nil {
log.Error(4, "Delivery: %v", err)
} else {
t.IsSucceed = true
}
if err := UpdateHookTask(t); err != nil { if err := UpdateHookTask(t); err != nil {
log.Error(4, "webhook.DeliverHooks(UpdateHookTask): %v", err) log.Error(4, "UpdateHookTask: %v", err)
return nil return nil
} }
log.Trace("Hook delivered: %s", t.PayloadContent) log.Trace("Hook delivered(%s): %s", t.Uuid, t.PayloadContent)
return nil return nil
}) })
} }

View file

@ -69,7 +69,7 @@ func (f *RepoSettingForm) Validate(ctx *macaron.Context, errs *binding.Errors, l
// \/ \/ \/ \/ \/ \/ // \/ \/ \/ \/ \/ \/
type NewWebhookForm struct { type NewWebhookForm struct {
Url string `form:"url" binding:"Required;Url"` PayloadUrl string `form:"payload_url" binding:"Required;Url"`
ContentType string `form:"content_type" binding:"Required"` ContentType string `form:"content_type" binding:"Required"`
Secret string `form:"secret"` Secret string `form:"secret"`
PushOnly bool `form:"push_only"` PushOnly bool `form:"push_only"`

View file

@ -112,7 +112,7 @@ func (repo *Repository) getCommit(id sha1) (*Commit, error) {
data, bytErr, err := com.ExecCmdDirBytes(repo.Path, "git", "cat-file", "-p", id.String()) data, bytErr, err := com.ExecCmdDirBytes(repo.Path, "git", "cat-file", "-p", id.String())
if err != nil { if err != nil {
return nil, errors.New(string(bytErr)) return nil, errors.New(err.Error() + ": " + string(bytErr))
} }
commit, err := parseCommitData(data) commit, err := parseCommitData(data)

View file

@ -1,62 +0,0 @@
# httplib
httplib is an libs help you to curl remote url.
# How to use?
## GET
you can use Get to crawl data.
import "httplib"
str, err := httplib.Get("http://beego.me/").String()
if err != nil {
t.Fatal(err)
}
fmt.Println(str)
## POST
POST data to remote url
b:=httplib.Post("http://beego.me/")
b.Param("username","astaxie")
b.Param("password","123456")
str, err := b.String()
if err != nil {
t.Fatal(err)
}
fmt.Println(str)
## set timeout
you can set timeout in request.default is 60 seconds.
set Get timeout:
httplib.Get("http://beego.me/").SetTimeout(100 * time.Second, 30 * time.Second)
set post timeout:
httplib.Post("http://beego.me/").SetTimeout(100 * time.Second, 30 * time.Second)
- first param is connectTimeout.
- second param is readWriteTimeout
## debug
if you want to debug the request info, set the debug on
httplib.Get("http://beego.me/").Debug(true)
## support HTTPS client
if request url is https. You can set the client support TSL:
httplib.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
more info about the tls.Config please visit http://golang.org/pkg/crypto/tls/#Config
## set cookie
some http request need setcookie. So set it like this:
cookie := &http.Cookie{}
cookie.Name = "username"
cookie.Value = "astaxie"
httplib.Get("http://beego.me/").SetCookie(cookie)

View file

@ -223,6 +223,9 @@ img.avatar-48 {
.text-red { .text-red {
color: #DD4B39; color: #DD4B39;
} }
.text-grey {
color: #999999;
}
.markdown { .markdown {
background-color: white; background-color: white;
font-size: 16px; font-size: 16px;
@ -1361,27 +1364,33 @@ The register and sign-in page style
margin-bottom: 24px; margin-bottom: 24px;
} }
#repo-hooks-panel, #repo-hooks-panel,
#repo-hooks-history-panel,
#user-ssh-panel { #user-ssh-panel {
margin-bottom: 20px; margin-bottom: 20px;
} }
#repo-hooks-panel .setting-list, #repo-hooks-panel .setting-list,
#repo-hooks-history-panel .setting-list,
#user-ssh-panel .setting-list { #user-ssh-panel .setting-list {
background-color: #FFF; background-color: #FFF;
} }
#repo-hooks-panel .setting-list li, #repo-hooks-panel .setting-list li,
#repo-hooks-history-panel .setting-list li,
#user-ssh-panel .setting-list li { #user-ssh-panel .setting-list li {
padding: 8px 20px; padding: 8px 20px;
border-bottom: 1px solid #eaeaea; border-bottom: 1px solid #eaeaea;
} }
#repo-hooks-panel .setting-list li.ssh:hover, #repo-hooks-panel .setting-list li.ssh:hover,
#repo-hooks-history-panel .setting-list li.ssh:hover,
#user-ssh-panel .setting-list li.ssh:hover { #user-ssh-panel .setting-list li.ssh:hover {
background-color: #ffffEE; background-color: #ffffEE;
} }
#repo-hooks-panel .setting-list li i, #repo-hooks-panel .setting-list li i,
#repo-hooks-history-panel .setting-list li i,
#user-ssh-panel .setting-list li i { #user-ssh-panel .setting-list li i {
padding-right: 5px; padding-right: 5px;
} }
#repo-hooks-panel .active-icon, #repo-hooks-panel .active-icon,
#repo-hooks-history-panel .active-icon,
#user-ssh-panel .active-icon { #user-ssh-panel .active-icon {
width: 10px; width: 10px;
height: 10px; height: 10px;
@ -1391,20 +1400,25 @@ The register and sign-in page style
margin-top: 10px; margin-top: 10px;
} }
#repo-hooks-panel .ssh-content, #repo-hooks-panel .ssh-content,
#repo-hooks-history-panel .ssh-content,
#user-ssh-panel .ssh-content { #user-ssh-panel .ssh-content {
margin-left: 24px; margin-left: 24px;
} }
#repo-hooks-panel .ssh-content .octicon, #repo-hooks-panel .ssh-content .octicon,
#repo-hooks-history-panel .ssh-content .octicon,
#user-ssh-panel .ssh-content .octicon { #user-ssh-panel .ssh-content .octicon {
margin-right: 4px; margin-right: 4px;
} }
#repo-hooks-panel .ssh-content .print, #repo-hooks-panel .ssh-content .print,
#repo-hooks-history-panel .ssh-content .print,
#user-ssh-panel .ssh-content .print, #user-ssh-panel .ssh-content .print,
#repo-hooks-panel .ssh-content .activity, #repo-hooks-panel .ssh-content .activity,
#repo-hooks-history-panel .ssh-content .activity,
#user-ssh-panel .ssh-content .activity { #user-ssh-panel .ssh-content .activity {
color: #888; color: #888;
} }
#repo-hooks-panel .ssh-delete-btn, #repo-hooks-panel .ssh-delete-btn,
#repo-hooks-history-panel .ssh-delete-btn,
#user-ssh-panel .ssh-delete-btn { #user-ssh-panel .ssh-delete-btn {
margin-top: 6px; margin-top: 6px;
} }

View file

@ -392,6 +392,7 @@ dt {
color: #FFF; color: #FFF;
} }
.btn-red { .btn-red {
color: #FFF;
background-color: #d9453d; background-color: #d9453d;
border: 1px solid #d9453d; border: 1px solid #d9453d;
} }
@ -432,6 +433,10 @@ dt {
color: white; color: white;
padding: 0 10px; padding: 0 10px;
} }
.btn-link {
overflow: visible;
padding: .6em 1.2em;
}
.btn-radius { .btn-radius {
border-radius: .25em; border-radius: .25em;
} }
@ -673,6 +678,7 @@ ul.menu-radius > li:last-child > a {
background-color: white; background-color: white;
} }
.panel .panel-body .panel-desc { .panel .panel-body .panel-desc {
padding: 0 40px;
margin-bottom: 20px; margin-bottom: 20px;
} }
.panel .panel-content { .panel .panel-content {

View file

@ -239,4 +239,7 @@ clear: both;
} }
.text-red { .text-red {
color: #DD4B39; color: #DD4B39;
}
.text-grey {
color: #999999;
} }

View file

@ -52,6 +52,7 @@
} }
#repo-hooks-panel, #repo-hooks-panel,
#repo-hooks-history-panel,
#user-ssh-panel { #user-ssh-panel {
margin-bottom: 20px; margin-bottom: 20px;
.setting-list { .setting-list {

View file

@ -32,16 +32,15 @@
color: #FFF; color: #FFF;
} }
} }
.btn-red { .btn-red {
background-color: @btnRedColor;
border: 1px solid @btnRedColor;
&:hover {
background-color: @btnHoverRedColor;
color: #FFF; color: #FFF;
} background-color: @btnRedColor;
border: 1px solid @btnRedColor;
&:hover {
background-color: @btnHoverRedColor;
color: #FFF;
}
} }
.btn-orange { .btn-orange {
background-color: @btnOrangeColor; background-color: @btnOrangeColor;
border: 1px solid @btnOrangeColor; border: 1px solid @btnOrangeColor;
@ -73,33 +72,33 @@
// status buttons // status buttons
.btn-active { .btn-active {
box-shadow: 0 0 0 1px rgba(0, 0, 0, .1) inset, 0 0 4px rgba(0, 0, 0, .15) inset box-shadow: 0 0 0 1px rgba(0, 0, 0, .1) inset, 0 0 4px rgba(0, 0, 0, .15) inset
} }
.btn-header { .btn-header {
margin-top: -1px; margin-top: -1px;
color: white; color: white;
padding: 0 10px; padding: 0 10px;
} }
.btn-link {
overflow: visible;
padding: .6em 1.2em;
}
.btn-radius { .btn-radius {
border-radius: .25em; border-radius: .25em;
} }
.btn-left-radius { .btn-left-radius {
border-top-left-radius: .25em; border-top-left-radius: .25em;
border-bottom-left-radius: .25em; border-bottom-left-radius: .25em;
} }
.btn-right-radius { .btn-right-radius {
border-top-right-radius: .25em; border-top-right-radius: .25em;
border-bottom-right-radius: .25em; border-bottom-right-radius: .25em;
} }
.btn-block { .btn-block {
display: block; display: block;
width: 100%; width: 100%;
box-sizing: content-box; box-sizing: content-box;
text-align: center; text-align: center;
} }
.btn-disabled { .btn-disabled {

View file

@ -10,6 +10,7 @@
.panel-body { .panel-body {
background-color: white; background-color: white;
.panel-desc { .panel-desc {
padding: 0 40px;
margin-bottom: 20px; margin-bottom: 20px;
} }
} }

View file

@ -24,9 +24,7 @@ const (
SETTINGS_OPTIONS base.TplName = "repo/settings/options" SETTINGS_OPTIONS base.TplName = "repo/settings/options"
COLLABORATION base.TplName = "repo/settings/collaboration" COLLABORATION base.TplName = "repo/settings/collaboration"
HOOKS base.TplName = "repo/settings/hooks" HOOKS base.TplName = "repo/settings/hooks"
HOOK_NEW base.TplName = "repo/settings/hook_new"
HOOK_ADD base.TplName = "repo/hook_add"
HOOK_EDIT base.TplName = "repo/hook_edit"
) )
func Settings(ctx *middleware.Context) { func Settings(ctx *middleware.Context) {
@ -241,18 +239,22 @@ func Webhooks(ctx *middleware.Context) {
ctx.HTML(200, HOOKS) ctx.HTML(200, HOOKS)
} }
func WebHooksAdd(ctx *middleware.Context) { func WebHooksNew(ctx *middleware.Context) {
ctx.Data["IsRepoToolbarWebHooks"] = true ctx.Data["Title"] = ctx.Tr("repo.settings")
ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - Add Webhook" ctx.Data["PageIsSettingsHooks"] = true
ctx.HTML(200, HOOK_ADD) ctx.Data["PageIsSettingsHooksNew"] = true
ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
ctx.HTML(200, HOOK_NEW)
} }
func WebHooksAddPost(ctx *middleware.Context, form auth.NewWebhookForm) { func WebHooksNewPost(ctx *middleware.Context, form auth.NewWebhookForm) {
ctx.Data["IsRepoToolbarWebHooks"] = true ctx.Data["Title"] = ctx.Tr("repo.settings")
ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - Add Webhook" ctx.Data["PageIsSettingsHooks"] = true
ctx.Data["PageIsSettingsHooksNew"] = true
ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
if ctx.HasError() { if ctx.HasError() {
ctx.HTML(200, HOOK_ADD) ctx.HTML(200, HOOK_NEW)
return return
} }
@ -263,7 +265,7 @@ func WebHooksAddPost(ctx *middleware.Context, form auth.NewWebhookForm) {
w := &models.Webhook{ w := &models.Webhook{
RepoId: ctx.Repo.Repository.Id, RepoId: ctx.Repo.Repository.Id,
Url: form.Url, Url: form.PayloadUrl,
ContentType: ct, ContentType: ct,
Secret: form.Secret, Secret: form.Secret,
HookEvent: &models.HookEvent{ HookEvent: &models.HookEvent{
@ -272,20 +274,21 @@ func WebHooksAddPost(ctx *middleware.Context, form auth.NewWebhookForm) {
IsActive: form.Active, IsActive: form.Active,
} }
if err := w.UpdateEvent(); err != nil { if err := w.UpdateEvent(); err != nil {
ctx.Handle(500, "setting.WebHooksAddPost(UpdateEvent)", err) ctx.Handle(500, "UpdateEvent", err)
return return
} else if err := models.CreateWebhook(w); err != nil { } else if err := models.CreateWebhook(w); err != nil {
ctx.Handle(500, "setting.WebHooksAddPost(CreateWebhook)", err) ctx.Handle(500, "CreateWebhook", err)
return return
} }
ctx.Flash.Success("New webhook has been added.") ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success"))
ctx.Redirect(ctx.Repo.RepoLink + "/settings/hooks") ctx.Redirect(ctx.Repo.RepoLink + "/settings/hooks")
} }
func WebHooksEdit(ctx *middleware.Context) { func WebHooksEdit(ctx *middleware.Context) {
ctx.Data["IsRepoToolbarWebHooks"] = true ctx.Data["Title"] = ctx.Tr("repo.settings")
ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - Webhook" ctx.Data["PageIsSettingsHooks"] = true
ctx.Data["PageIsSettingsHooksEdit"] = true
hookId := com.StrTo(ctx.Params(":id")).MustInt64() hookId := com.StrTo(ctx.Params(":id")).MustInt64()
if hookId == 0 { if hookId == 0 {
@ -296,21 +299,21 @@ func WebHooksEdit(ctx *middleware.Context) {
w, err := models.GetWebhookById(hookId) w, err := models.GetWebhookById(hookId)
if err != nil { if err != nil {
if err == models.ErrWebhookNotExist { if err == models.ErrWebhookNotExist {
ctx.Handle(404, "setting.WebHooksEdit(GetWebhookById)", nil) ctx.Handle(404, "GetWebhookById", nil)
} else { } else {
ctx.Handle(500, "setting.WebHooksEdit(GetWebhookById)", err) ctx.Handle(500, "GetWebhookById", err)
} }
return return
} }
w.GetEvent() w.GetEvent()
ctx.Data["Webhook"] = w ctx.Data["Webhook"] = w
ctx.HTML(200, HOOK_EDIT) ctx.HTML(200, HOOK_NEW)
} }
func WebHooksEditPost(ctx *middleware.Context, form auth.NewWebhookForm) { func WebHooksEditPost(ctx *middleware.Context, form auth.NewWebhookForm) {
ctx.Data["IsRepoToolbarWebHooks"] = true ctx.Data["Title"] = ctx.Tr("repo.settings")
ctx.Data["Title"] = strings.TrimPrefix(ctx.Repo.RepoLink, "/") + " - Webhook" ctx.Data["PageIsSettingsHooks"] = true
ctx.Data["PageIsSettingsHooksEdit"] = true
hookId := com.StrTo(ctx.Params(":id")).MustInt64() hookId := com.StrTo(ctx.Params(":id")).MustInt64()
if hookId == 0 { if hookId == 0 {
@ -327,9 +330,11 @@ func WebHooksEditPost(ctx *middleware.Context, form auth.NewWebhookForm) {
} }
return return
} }
w.GetEvent()
ctx.Data["Webhook"] = w
if ctx.HasError() { if ctx.HasError() {
ctx.HTML(200, HOOK_EDIT) ctx.HTML(200, HOOK_NEW)
return return
} }
@ -338,7 +343,7 @@ func WebHooksEditPost(ctx *middleware.Context, form auth.NewWebhookForm) {
ct = models.FORM ct = models.FORM
} }
w.Url = form.Url w.Url = form.PayloadUrl
w.ContentType = ct w.ContentType = ct
w.Secret = form.Secret w.Secret = form.Secret
w.HookEvent = &models.HookEvent{ w.HookEvent = &models.HookEvent{
@ -353,6 +358,6 @@ func WebHooksEditPost(ctx *middleware.Context, form auth.NewWebhookForm) {
return return
} }
ctx.Flash.Success("Webhook has been updated.") ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
ctx.Redirect(fmt.Sprintf("%s/settings/hooks/%d", ctx.Repo.RepoLink, hookId)) ctx.Redirect(fmt.Sprintf("%s/settings/hooks/%d", ctx.Repo.RepoLink, hookId))
} }

View file

@ -71,8 +71,8 @@
<strong>{{.i18n.Tr "repo.init_readme"}}</strong> <strong>{{.i18n.Tr "repo.init_readme"}}</strong>
</div> </div>
<div class="field"> <div class="field">
<label for="repo-create-submit"></label> <label></label>
<button class="btn btn-large btn-blue btn-radius" id="repo-create-submit">{{.i18n.Tr "repo.create_repo"}}</button> <button class="btn btn-large btn-blue btn-radius">{{.i18n.Tr "repo.create_repo"}}</button>
<a class="btn btn-small btn-gray btn-radius" id="repo-create-cancel" href="/"><strong>{{.i18n.Tr "cancel"}}</strong></a> <a class="btn btn-small btn-gray btn-radius" id="repo-create-cancel" href="/"><strong>{{.i18n.Tr "cancel"}}</strong></a>
</div> </div>
</div> </div>

View file

@ -1,62 +0,0 @@
{{template "base/head" .}}
{{template "base/navbar" .}}
{{template "repo/nav" .}}
{{template "repo/toolbar" .}}
<div id="body" class="container">
{{template "repo/setting_nav" .}}
<div id="repo-setting-container" class="col-md-10">
{{template "base/alert" .}}
<form id="repo-hooks-add-form" action="{{.RepoLink}}/settings/hooks/add" method="post">
{{.CsrfTokenHtml}}
<div class="panel panel-default">
<div class="panel-heading">
Add Webhook
</div>
<div class="panel-body">
<div class="col-md-7">
<p>Well send a POST request to the URL below with details of any subscribed events.</p>
<hr/>
<div class="form-group">
<label for="payload-url">Payload URL</label>
<input id="payload-url" name="url" class="form-control" type="url" required="required"/>
</div>
<div class="form-group">
<label for="content-type">Content type</label>
<select id="content-type" name="content_type" class="form-control">
<option value="1">application/json</option>
</select>
</div>
<div class="form-group">
<label for="payload-secret">Secret</label>
<input id="payload-secret" name="secret" class="form-control" type="text"/>
</div>
<hr/>
<div class="form-group">
<label>Which events would you like to trigger this webhook?</label>
<div class="radio">
<label>
<input class="form-control" name="push_only" type="radio" checked name="trigger"/> Just the <i>push</i> event.
</label>
</div>
</div>
<hr/>
<div class="form-group">
<label>
<input type="checkbox" name="active" checked/>&nbsp;&nbsp;Active
</label>
<p class="help-block">We will deliver event details when this hook is triggered.</p>
</div>
</div>
</div>
<div class="panel-footer">
<button class="btn btn-success">Add Webhook</button>
</div>
</div>
</form>
</div>
</div>
{{template "base/footer" .}}

View file

@ -1,72 +0,0 @@
{{template "base/head" .}}
{{template "base/navbar" .}}
{{template "repo/nav" .}}
{{template "repo/toolbar" .}}
<div id="body" class="container">
{{template "repo/setting_nav" .}}
<div id="repo-setting-container" class="col-md-10">
{{template "base/alert" .}}
<form id="repo-hooks-edit-form" action="{{.RepoLink}}/settings/hooks/{{.Webhook.Id}}" method="post">
{{.CsrfTokenHtml}}
<div class="panel panel-default">
<div class="panel-heading">
Manage Webhook
</div>
<div class="panel-body">
<div class="col-md-7">
<p>Well send a POST request to the URL below with details of any subscribed events.</p>
<hr/>
<div class="form-group">
<label for="payload-url">Payload URL</label>
<input id="payload-url" name="url" class="form-control" type="url" required="required" value="{{.Webhook.Url}}" />
</div>
<div class="form-group">
<label for="payload-version">Content type</label>
<select id="content-type" name="content_type" class="form-control">
<option value="1">application/json</option>
</select>
</div>
<div class="form-group">
<label for="payload-secret">Secret</label>
<input id="payload-secret" name="secret" class="form-control" type="text" value="{{.Webhook.Secret}}" />
</div>
<hr/>
<div class="form-group">
<label>Which events would you like to trigger this webhook?</label>
<div class="radio">
<label>
<input class="form-control" name="push_only" type="radio" {{if .Webhook.HookEvent.PushOnly}}checked {{end}}name="trigger"/> Just the <i>push</i> event.
</label>
</div>
</div>
<hr/>
<div class="form-group">
<label>
<input type="checkbox" name="active" {{if .Webhook.IsActive}}checked{{end}}/>&nbsp;&nbsp;Active
</label>
<p class="help-block">We will deliver event details when this hook is triggered.</p>
</div>
</div>
</div>
<div class="panel-footer">
<button class="btn btn-primary">Update Webhook</button>&nbsp;&nbsp;
<a type="button" href="{{.RepoLink}}/settings/hooks?remove={{.Webhook.Id}}" class="btn btn-danger">Delete Webhook</a>
</div>
</div>
</form>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Recent Deliveries</h3>
</div>
<div class="panel-body">
Coming soon
</div>
</div>
</div>
</div>
{{template "base/footer" .}}

View file

@ -0,0 +1,68 @@
{{template "ng/base/head" .}}
{{template "ng/base/header" .}}
<div id="repo-wrapper">
{{template "repo/header" .}}
<div id="setting-wrapper" class="main-wrapper">
<div id="repo-setting" class="container clear">
{{template "repo/settings/nav" .}}
<div class="grid-4-5 left">
<div class="setting-content">
{{template "ng/base/alert" .}}
<div id="setting-content">
<div id="repo-hooks-panel" class="panel panel-radius">
<div class="panel-header">
<strong>{{if .PageIsSettingsHooksNew}}{{.i18n.Tr "repo.settings.add_webhook"}}{{else}}{{.i18n.Tr "repo.settings.update_webhook"}}{{end}}</strong>
</div>
<form class="form form-align panel-body" id="repo-setting-form" action="{{.RepoLink}}/settings/hooks/{{if .PageIsSettingsHooksNew}}new{{else}}{{.Webhook.Id}}{{end}}" method="post">
{{.CsrfTokenHtml}}
<div class="text-center panel-desc">{{.i18n.Tr "repo.settings.add_webhook_desc" | Str2html}}</div>
<div class="field">
<label class="req" for="payload-url">{{.i18n.Tr "repo.settings.payload_url"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_UserName}}ipt-error{{end}}" id="payload-url" name="payload_url" type="url" value="{{.Webhook.Url}}" required />
</div>
<div class="field">
<label class="req">{{.i18n.Tr "repo.settings.content_type"}}</label>
<select name="content_type">
<option value="1" {{if or .PageIsSettingsHooksNew (eq .Webhook.ContentType 1)}}selected{{end}}>application/json</option>
<option value="2" {{if eq .Webhook.ContentType 2}}selected{{end}}>application/x-www-form-urlencoded</option>
</select>
</div>
<div class="field">
<label for="secret">{{.i18n.Tr "repo.settings.secret"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_UserName}}ipt-error{{end}}" id="secret" name="secret" type="password" value="{{.Webhook.Secret}}" autocomplete="off" />
</div>
<div class="field">
<h4 class="text-center">{{.i18n.Tr "repo.settings.event_desc"}}</h4>
<label></label>
<input name="push_only" type="radio" {{if or .PageIsSettingsHooksNew .Webhook.PushOnly}}checked{{end}}> {{.i18n.Tr "repo.settings.event_push_only" | Str2html}}
</div>
<div class="field">
<label for="active">{{.i18n.Tr "repo.settings.active"}}</label>
<input class="ipt-chk" id="active" name="active" type="checkbox" {{if or .PageIsSettingsHooksNew .Webhook.IsActive}}checked{{end}} />
<span>{{.i18n.Tr "repo.settings.active_helper"}}</span>
</div>
<div class="field">
<label></label>
<button class="btn btn-green btn-large btn-radius">{{if .PageIsSettingsHooksNew}}{{.i18n.Tr "repo.settings.add_webhook"}}{{else}}{{.i18n.Tr "repo.settings.update_webhook"}}{{end}}</button>
{{if .PageIsSettingsHooksEdit}}<a class="btn btn-red btn-large btn-link btn-radius" href="{{.RepoLink}}/settings/hooks?remove={{.Webhook.Id}}"><strong>{{.i18n.Tr "repo.settings.delete_webhook"}}</strong></a>{{end}}
</div>
</form>
</div>
</div>
<br>
<div id="setting-content">
<div id="repo-hooks-history-panel" class="panel panel-radius">
<div class="panel-header">
<strong>{{.i18n.Tr "repo.settings.recent_deliveries"}}</strong>
</div>
<ul class="panel-body setting-list">
<li>Coming soon!</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{{template "ng/base/footer" .}}

View file

@ -18,7 +18,11 @@
<li>{{.i18n.Tr "repo.settings.hooks_desc" | Str2html}}</li> <li>{{.i18n.Tr "repo.settings.hooks_desc" | Str2html}}</li>
{{range .Webhooks}} {{range .Webhooks}}
<li> <li>
{{if .IsActive}}<span class="left text-success"><i class="fa fa-check"></i></span>{{else}}<span class="pull-left status"><i class="fa fa-times"></i></span>{{end}} {{if .IsActive}}
<span class="left text-success"><i class="octicon octicon-check"></i></span>
{{else}}
<span class="left text-grey"><i class="octicon octicon-primitive-dot"></i></span>
{{end}}
<a class="link" href="{{$.RepoLink}}/settings/hooks/{{.Id}}">{{.Url}}</a> <a class="link" href="{{$.RepoLink}}/settings/hooks/{{.Id}}">{{.Url}}</a>
<a href="{{$.RepoLink}}/settings/hooks?remove={{.Id}}" class="text-red right"><i class="fa fa-times"></i></a> <a href="{{$.RepoLink}}/settings/hooks?remove={{.Id}}" class="text-red right"><i class="fa fa-times"></i></a>
<a href="{{$.RepoLink}}/settings/hooks/{{.Id}}" class="text-blue right"><i class="fa fa-pencil"></i></a> <a href="{{$.RepoLink}}/settings/hooks/{{.Id}}" class="text-blue right"><i class="fa fa-pencil"></i></a>

View file

@ -31,8 +31,8 @@
<hr> <hr>
<br> <br>
<div class="field"> <div class="field">
<label for="lang">{{.i18n.Tr "repo.default_branch"}}</label> <label>{{.i18n.Tr "repo.default_branch"}}</label>
<select id="lang" name="gitignore"> <select name="branch">
{{if .Repository.DefaultBranch}}<option value="{{.Repository.DefaultBranch}}">{{.Repository.DefaultBranch}}</option>{{end}} {{if .Repository.DefaultBranch}}<option value="{{.Repository.DefaultBranch}}">{{.Repository.DefaultBranch}}</option>{{end}}
{{range .Branches}} {{range .Branches}}
{{if not (eq . $.Repository.DefaultBranch)}}<option value="{{.}}">{{.}}</option>{{end}} {{if not (eq . $.Repository.DefaultBranch)}}<option value="{{.}}">{{.}}</option>{{end}}

View file

@ -16,7 +16,7 @@
<li>{{.i18n.Tr "settings.ssh_desc"}}</li> <li>{{.i18n.Tr "settings.ssh_desc"}}</li>
{{range .Keys}} {{range .Keys}}
<li class="ssh clear"> <li class="ssh clear">
<span class="active-icon left label {{if .HasRecentActivity}}label-green{{end}} label-radius"></span> <span class="active-icon left label label-{{if .HasRecentActivity}}green{{else}}gray{{end}} label-radius"></span>
<i class="mega-octicon octicon-key left"></i> <i class="mega-octicon octicon-key left"></i>
<div class="ssh-content left"> <div class="ssh-content left">
<p><strong>{{.Name}}</strong></p> <p><strong>{{.Name}}</strong></p>