aboutsummaryrefslogtreecommitdiff
path: root/models
diff options
context:
space:
mode:
Diffstat (limited to 'models')
-rw-r--r--models/action.go23
-rw-r--r--models/login.go83
-rw-r--r--models/models.go7
-rw-r--r--models/publickey.go14
-rw-r--r--models/repo.go69
-rw-r--r--models/user.go2
-rw-r--r--models/webhook.go133
7 files changed, 219 insertions, 112 deletions
diff --git a/models/action.go b/models/action.go
index 9fc9d89b..e39b04a1 100644
--- a/models/action.go
+++ b/models/action.go
@@ -15,7 +15,6 @@ import (
qlog "github.com/qiniu/log"
"github.com/gogits/gogs/modules/base"
- "github.com/gogits/gogs/modules/hooks"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/setting"
)
@@ -131,35 +130,35 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string,
}
repoLink := fmt.Sprintf("%s%s/%s", setting.AppUrl, repoUserName, repoName)
- commits := make([]*hooks.PayloadCommit, len(commit.Commits))
+ commits := make([]*PayloadCommit, len(commit.Commits))
for i, cmt := range commit.Commits {
- commits[i] = &hooks.PayloadCommit{
+ commits[i] = &PayloadCommit{
Id: cmt.Sha1,
Message: cmt.Message,
Url: fmt.Sprintf("%s/commit/%s", repoLink, cmt.Sha1),
- Author: &hooks.PayloadAuthor{
+ Author: &PayloadAuthor{
Name: cmt.AuthorName,
Email: cmt.AuthorEmail,
},
}
}
- p := &hooks.Payload{
+ p := &Payload{
Ref: refFullName,
Commits: commits,
- Repo: &hooks.PayloadRepo{
+ Repo: &PayloadRepo{
Id: repo.Id,
Name: repo.LowerName,
Url: repoLink,
Description: repo.Description,
Website: repo.Website,
Watchers: repo.NumWatches,
- Owner: &hooks.PayloadAuthor{
+ Owner: &PayloadAuthor{
Name: repoUserName,
Email: actEmail,
},
Private: repo.IsPrivate,
},
- Pusher: &hooks.PayloadAuthor{
+ Pusher: &PayloadAuthor{
Name: repo.Owner.LowerName,
Email: repo.Owner.Email,
},
@@ -172,7 +171,13 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string,
}
p.Secret = w.Secret
- hooks.AddHookTask(&hooks.HookTask{hooks.HTT_WEBHOOK, w.Url, p, w.ContentType, w.IsSsl})
+ CreateHookTask(&HookTask{
+ Type: WEBHOOK,
+ Url: w.Url,
+ Payload: p,
+ ContentType: w.ContentType,
+ IsSsl: w.IsSsl,
+ })
}
return nil
}
diff --git a/models/login.go b/models/login.go
index 984a9f8c..863ba44e 100644
--- a/models/login.go
+++ b/models/login.go
@@ -1,4 +1,4 @@
-// Copyright github.com/juju2013. All rights reserved.
+// Copyright 2014 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.
@@ -20,12 +20,13 @@ import (
"github.com/gogits/gogs/modules/log"
)
-// Login types.
+type LoginType int
+
const (
- LT_NOTYPE = iota
- LT_PLAIN
- LT_LDAP
- LT_SMTP
+ NOTYPE LoginType = iota
+ PLAIN
+ LDAP
+ SMTP
)
var (
@@ -34,9 +35,9 @@ var (
ErrAuthenticationUserUsed = errors.New("Authentication has been used by some users")
)
-var LoginTypes = map[int]string{
- LT_LDAP: "LDAP",
- LT_SMTP: "SMTP",
+var LoginTypes = map[LoginType]string{
+ LDAP: "LDAP",
+ SMTP: "SMTP",
}
// Ensure structs implmented interface.
@@ -49,7 +50,6 @@ type LDAPConfig struct {
ldap.Ldapsource
}
-// implement
func (cfg *LDAPConfig) FromDB(bs []byte) error {
return json.Unmarshal(bs, &cfg.Ldapsource)
}
@@ -65,7 +65,6 @@ type SMTPConfig struct {
TLS bool
}
-// implement
func (cfg *SMTPConfig) FromDB(bs []byte) error {
return json.Unmarshal(bs, cfg)
}
@@ -76,13 +75,13 @@ func (cfg *SMTPConfig) ToDB() ([]byte, error) {
type LoginSource struct {
Id int64
- Type int
- Name string `xorm:"unique"`
- IsActived bool `xorm:"not null default false"`
+ Type LoginType
+ Name string `xorm:"UNIQUE"`
+ IsActived bool `xorm:"NOT NULL DEFAULT false"`
Cfg core.Conversion `xorm:"TEXT"`
- Created time.Time `xorm:"created"`
- Updated time.Time `xorm:"updated"`
- AllowAutoRegister bool `xorm:"not null default false"`
+ AllowAutoRegister bool `xorm:"NOT NULL DEFAULT false"`
+ Created time.Time `xorm:"CREATED"`
+ Updated time.Time `xorm:"UPDATED"`
}
func (source *LoginSource) TypeString() string {
@@ -97,21 +96,25 @@ func (source *LoginSource) SMTP() *SMTPConfig {
return source.Cfg.(*SMTPConfig)
}
-// for xorm callback
func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) {
if colName == "type" {
ty := (*val).(int64)
- switch ty {
- case LT_LDAP:
+ switch LoginType(ty) {
+ case LDAP:
source.Cfg = new(LDAPConfig)
- case LT_SMTP:
+ case SMTP:
source.Cfg = new(SMTPConfig)
}
}
}
+func CreateSource(source *LoginSource) error {
+ _, err := orm.Insert(source)
+ return err
+}
+
func GetAuths() ([]*LoginSource, error) {
- var auths = make([]*LoginSource, 0)
+ var auths = make([]*LoginSource, 0, 5)
err := orm.Find(&auths)
return auths, err
}
@@ -121,18 +124,12 @@ func GetLoginSourceById(id int64) (*LoginSource, error) {
has, err := orm.Id(id).Get(source)
if err != nil {
return nil, err
- }
- if !has {
+ } else if !has {
return nil, ErrAuthenticationNotExist
}
return source, nil
}
-func AddSource(source *LoginSource) error {
- _, err := orm.Insert(source)
- return err
-}
-
func UpdateSource(source *LoginSource) error {
_, err := orm.Id(source.Id).AllCols().Update(source)
return err
@@ -164,14 +161,14 @@ func UserSignIn(uname, passwd string) (*User, error) {
return nil, err
}
- if u.LoginType == LT_NOTYPE {
+ if u.LoginType == NOTYPE {
if has {
- u.LoginType = LT_PLAIN
+ u.LoginType = PLAIN
}
}
// for plain login, user must have existed.
- if u.LoginType == LT_PLAIN {
+ if u.LoginType == PLAIN {
if !has {
return nil, ErrUserNotExist
}
@@ -191,22 +188,20 @@ func UserSignIn(uname, passwd string) (*User, error) {
}
for _, source := range sources {
- if source.Type == LT_LDAP {
+ if source.Type == LDAP {
u, err := LoginUserLdapSource(nil, uname, passwd,
source.Id, source.Cfg.(*LDAPConfig), true)
if err == nil {
return u, nil
- } else {
- log.Warn("Fail to login(%s) by LDAP(%s): %v", uname, source.Name, err)
}
- } else if source.Type == LT_SMTP {
+ log.Warn("Fail to login(%s) by LDAP(%s): %v", uname, source.Name, err)
+ } else if source.Type == SMTP {
u, err := LoginUserSMTPSource(nil, uname, passwd,
source.Id, source.Cfg.(*SMTPConfig), true)
if err == nil {
return u, nil
- } else {
- log.Warn("Fail to login(%s) by SMTP(%s): %v", uname, source.Name, err)
}
+ log.Warn("Fail to login(%s) by SMTP(%s): %v", uname, source.Name, err)
}
}
@@ -224,10 +219,10 @@ func UserSignIn(uname, passwd string) (*User, error) {
}
switch u.LoginType {
- case LT_LDAP:
+ case LDAP:
return LoginUserLdapSource(u, u.LoginName, passwd,
source.Id, source.Cfg.(*LDAPConfig), false)
- case LT_SMTP:
+ case SMTP:
return LoginUserSMTPSource(u, u.LoginName, passwd,
source.Id, source.Cfg.(*SMTPConfig), false)
}
@@ -252,7 +247,7 @@ func LoginUserLdapSource(user *User, name, passwd string, sourceId int64, cfg *L
user = &User{
LowerName: strings.ToLower(name),
Name: strings.ToLower(name),
- LoginType: LT_LDAP,
+ LoginType: LDAP,
LoginSource: sourceId,
LoginName: name,
IsActive: true,
@@ -320,9 +315,8 @@ func SmtpAuth(host string, port int, a smtp.Auth, useTls bool) error {
return err
}
return nil
- } else {
- return ErrUnsupportedLoginType
}
+ return ErrUnsupportedLoginType
}
// Query if name/passwd can login against the LDAP direcotry pool
@@ -358,13 +352,12 @@ func LoginUserSMTPSource(user *User, name, passwd string, sourceId int64, cfg *S
user = &User{
LowerName: strings.ToLower(loginName),
Name: strings.ToLower(loginName),
- LoginType: LT_SMTP,
+ LoginType: SMTP,
LoginSource: sourceId,
LoginName: name,
IsActive: true,
Passwd: passwd,
Email: name,
}
-
return RegisterUser(user)
}
diff --git a/models/models.go b/models/models.go
index fa65ef30..a59c0517 100644
--- a/models/models.go
+++ b/models/models.go
@@ -35,7 +35,7 @@ func init() {
tables = append(tables, new(User), new(PublicKey), new(Repository), new(Watch),
new(Action), new(Access), new(Issue), new(Comment), new(Oauth2), new(Follow),
new(Mirror), new(Release), new(LoginSource), new(Webhook), new(IssueUser),
- new(Milestone), new(Label))
+ new(Milestone), new(Label), new(HookTask))
}
func LoadModelsConfig() {
@@ -46,7 +46,9 @@ func LoadModelsConfig() {
DbCfg.Host = setting.Cfg.MustValue("database", "HOST")
DbCfg.Name = setting.Cfg.MustValue("database", "NAME")
DbCfg.User = setting.Cfg.MustValue("database", "USER")
- DbCfg.Pwd = setting.Cfg.MustValue("database", "PASSWD")
+ if len(DbCfg.Pwd) == 0 {
+ DbCfg.Pwd = setting.Cfg.MustValue("database", "PASSWD")
+ }
DbCfg.SslMode = setting.Cfg.MustValue("database", "SSL_MODE")
DbCfg.Path = setting.Cfg.MustValue("database", "PATH", "data/gogs.db")
}
@@ -67,7 +69,6 @@ func NewTestEngine(x *xorm.Engine) (err error) {
}
cnnstr := fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s sslmode=%s",
DbCfg.User, DbCfg.Pwd, host, port, DbCfg.Name, DbCfg.SslMode)
- //fmt.Println(cnnstr)
x, err = xorm.NewEngine("postgres", cnnstr)
case "sqlite3":
if !EnableSQLite3 {
diff --git a/models/publickey.go b/models/publickey.go
index 556db964..76dc0cc7 100644
--- a/models/publickey.go
+++ b/models/publickey.go
@@ -37,7 +37,7 @@ var (
var sshOpLocker = sync.Mutex{}
var (
- sshPath string // SSH directory.
+ SshPath string // SSH directory.
appPath string // Execution(binary) path.
)
@@ -67,9 +67,9 @@ func init() {
}
// Determine and create .ssh path.
- sshPath = filepath.Join(homeDir(), ".ssh")
- if err = os.MkdirAll(sshPath, os.ModePerm); err != nil {
- qlog.Fatalf("publickey.init(fail to create sshPath(%s)): %v\n", sshPath, err)
+ SshPath = filepath.Join(homeDir(), ".ssh")
+ if err = os.MkdirAll(SshPath, os.ModePerm); err != nil {
+ qlog.Fatalf("publickey.init(fail to create SshPath(%s)): %v\n", SshPath, err)
}
}
@@ -94,7 +94,7 @@ func saveAuthorizedKeyFile(key *PublicKey) error {
sshOpLocker.Lock()
defer sshOpLocker.Unlock()
- fpath := filepath.Join(sshPath, "authorized_keys")
+ fpath := filepath.Join(SshPath, "authorized_keys")
f, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if err != nil {
return err
@@ -216,8 +216,8 @@ func DeletePublicKey(key *PublicKey) error {
return err
}
- fpath := filepath.Join(sshPath, "authorized_keys")
- tmpPath := filepath.Join(sshPath, "authorized_keys.tmp")
+ fpath := filepath.Join(SshPath, "authorized_keys")
+ tmpPath := filepath.Join(SshPath, "authorized_keys.tmp")
log.Trace("publickey.DeletePublicKey(authorized_keys): %s", fpath)
if err = rewriteAuthorizedKeys(key, fpath, tmpPath); err != nil {
diff --git a/models/repo.go b/models/repo.go
index 869059fa..7eab83c2 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -28,6 +28,10 @@ import (
"github.com/gogits/gogs/modules/setting"
)
+const (
+ TPL_UPDATE_HOOK = "#!/usr/bin/env %s\n%s update $1 $2 $3\n"
+)
+
var (
ErrRepoAlreadyExist = errors.New("Repository already exist")
ErrRepoNotExist = errors.New("Repository does not exist")
@@ -109,11 +113,11 @@ func NewRepoContext() {
// Repository represents a git repository.
type Repository struct {
Id int64
- OwnerId int64 `xorm:"unique(s)"`
+ OwnerId int64 `xorm:"UNIQUE(s)"`
Owner *User `xorm:"-"`
ForkId int64
- LowerName string `xorm:"unique(s) index not null"`
- Name string `xorm:"index not null"`
+ LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"`
+ Name string `xorm:"INDEX NOT NULL"`
Description string
Website string
NumWatches int
@@ -131,8 +135,8 @@ type Repository struct {
IsBare bool
IsGoget bool
DefaultBranch string
- Created time.Time `xorm:"created"`
- Updated time.Time `xorm:"updated"`
+ Created time.Time `xorm:"CREATED"`
+ Updated time.Time `xorm:"UPDATED"`
}
func (repo *Repository) GetOwner() (err error) {
@@ -184,6 +188,25 @@ type Mirror struct {
NextUpdate time.Time
}
+// MirrorRepository creates a mirror repository from source.
+func MirrorRepository(repoId int64, userName, repoName, repoPath, url string) error {
+ _, stderr, err := com.ExecCmd("git", "clone", "--mirror", url, repoPath)
+ if err != nil {
+ return errors.New("git clone --mirror: " + stderr)
+ }
+
+ if _, err = orm.InsertOne(&Mirror{
+ RepoId: repoId,
+ RepoName: strings.ToLower(userName + "/" + repoName),
+ Interval: 24,
+ NextUpdate: time.Now().Add(24 * time.Hour),
+ }); err != nil {
+ return err
+ }
+
+ return git.UnpackRefs(repoPath)
+}
+
func GetMirror(repoId int64) (*Mirror, error) {
m := &Mirror{RepoId: repoId}
has, err := orm.Get(m)
@@ -223,25 +246,6 @@ func MirrorUpdate() {
}
}
-// MirrorRepository creates a mirror repository from source.
-func MirrorRepository(repoId int64, userName, repoName, repoPath, url string) error {
- _, stderr, err := com.ExecCmd("git", "clone", "--mirror", url, repoPath)
- if err != nil {
- return errors.New("git clone --mirror: " + stderr)
- }
-
- if _, err = orm.InsertOne(&Mirror{
- RepoId: repoId,
- RepoName: strings.ToLower(userName + "/" + repoName),
- Interval: 24,
- NextUpdate: time.Now().Add(24 * time.Hour),
- }); err != nil {
- return err
- }
-
- return git.UnpackRefs(repoPath)
-}
-
// MigrateRepository migrates a existing repository from other project hosting.
func MigrateRepository(user *User, name, desc string, private, mirror bool, url string) (*Repository, error) {
repo, err := CreateRepository(user, name, desc, "", "", private, mirror, false)
@@ -450,7 +454,7 @@ func initRepository(f string, user *User, repo *Repository, initReadme bool, rep
rp := strings.NewReplacer("\\", "/", " ", "\\ ")
// hook/post-update
if err := createHookUpdate(filepath.Join(repoPath, "hooks", "update"),
- fmt.Sprintf("#!/usr/bin/env %s\n%s update $1 $2 $3\n", setting.ScriptType,
+ fmt.Sprintf(TPL_UPDATE_HOOK, setting.ScriptType,
rp.Replace(appPath))); err != nil {
return err
}
@@ -746,16 +750,11 @@ func DeleteRepository(userId, repoId int64, userName string) (err error) {
sess.Rollback()
return err
}
- if err = sess.Commit(); err != nil {
- sess.Rollback()
- return err
- }
if err = os.RemoveAll(RepoPath(userName, repo.Name)); err != nil {
- // TODO: log and delete manully
- log.Error("delete repo %s/%s failed: %v", userName, repo.Name, err)
+ sess.Rollback()
return err
}
- return nil
+ return sess.Commit()
}
// GetRepositoryByName returns the repository by given name under user if exists.
@@ -832,11 +831,11 @@ func GetCollaborativeRepos(uname string) ([]*Repository, error) {
repos := make([]*Repository, 0, 10)
for _, access := range accesses {
- if strings.HasPrefix(access.RepoName, uname) {
+ infos := strings.Split(access.RepoName, "/")
+ if infos[0] == uname {
continue
}
-
- infos := strings.Split(access.RepoName, "/")
+
u, err := GetUserByName(infos[0])
if err != nil {
return nil, err
diff --git a/models/user.go b/models/user.go
index 78ab4642..04ea1fd6 100644
--- a/models/user.go
+++ b/models/user.go
@@ -47,7 +47,7 @@ type User struct {
FullName string
Email string `xorm:"unique not null"`
Passwd string `xorm:"not null"`
- LoginType int
+ LoginType LoginType
LoginSource int64 `xorm:"not null default 0"`
LoginName string
Type int
diff --git a/models/webhook.go b/models/webhook.go
index f10fa213..ffd47c8f 100644
--- a/models/webhook.go
+++ b/models/webhook.go
@@ -7,29 +7,35 @@ package models
import (
"encoding/json"
"errors"
+ "time"
+ "github.com/gogits/gogs/modules/httplib"
"github.com/gogits/gogs/modules/log"
+ "github.com/gogits/gogs/modules/setting"
)
var (
ErrWebhookNotExist = errors.New("Webhook does not exist")
)
-// Content types.
+type HookContentType int
+
const (
- CT_JSON = iota + 1
- CT_FORM
+ JSON HookContentType = iota + 1
+ FORM
)
+// HookEvent represents events that will delivery hook.
type HookEvent struct {
PushOnly bool `json:"push_only"`
}
+// Webhook represents a web hook object.
type Webhook struct {
Id int64
RepoId int64
Url string `xorm:"TEXT"`
- ContentType int
+ ContentType HookContentType
Secret string `xorm:"TEXT"`
Events string `xorm:"TEXT"`
*HookEvent `xorm:"-"`
@@ -37,6 +43,7 @@ type Webhook struct {
IsActive bool
}
+// GetEvent handles conversion from Events to HookEvent.
func (w *Webhook) GetEvent() {
w.HookEvent = &HookEvent{}
if err := json.Unmarshal([]byte(w.Events), w.HookEvent); err != nil {
@@ -44,12 +51,14 @@ func (w *Webhook) GetEvent() {
}
}
-func (w *Webhook) SaveEvent() error {
+// UpdateEvent handles conversion from HookEvent to Events.
+func (w *Webhook) UpdateEvent() error {
data, err := json.Marshal(w.HookEvent)
w.Events = string(data)
return err
}
+// HasPushEvent returns true if hook enbaled push event.
func (w *Webhook) HasPushEvent() bool {
if w.PushOnly {
return true
@@ -57,18 +66,12 @@ func (w *Webhook) HasPushEvent() bool {
return false
}
-// CreateWebhook creates new webhook.
+// CreateWebhook creates a new web hook.
func CreateWebhook(w *Webhook) error {
_, err := orm.Insert(w)
return err
}
-// UpdateWebhook updates information of webhook.
-func UpdateWebhook(w *Webhook) error {
- _, err := orm.AllCols().Update(w)
- return err
-}
-
// GetWebhookById returns webhook by given ID.
func GetWebhookById(hookId int64) (*Webhook, error) {
w := &Webhook{Id: hookId}
@@ -93,8 +96,114 @@ func GetWebhooksByRepoId(repoId int64) (ws []*Webhook, err error) {
return ws, err
}
+// UpdateWebhook updates information of webhook.
+func UpdateWebhook(w *Webhook) error {
+ _, err := orm.AllCols().Update(w)
+ return err
+}
+
// DeleteWebhook deletes webhook of repository.
func DeleteWebhook(hookId int64) error {
_, err := orm.Delete(&Webhook{Id: hookId})
return err
}
+
+// ___ ___ __ ___________ __
+// / | \ ____ ____ | | _\__ ___/____ _____| | __
+// / ~ \/ _ \ / _ \| |/ / | | \__ \ / ___/ |/ /
+// \ Y ( <_> | <_> ) < | | / __ \_\___ \| <
+// \___|_ / \____/ \____/|__|_ \ |____| (____ /____ >__|_ \
+// \/ \/ \/ \/ \/
+
+type HookTaskType int
+
+const (
+ WEBHOOK HookTaskType = iota + 1
+ SERVICE
+)
+
+type PayloadAuthor struct {
+ Name string `json:"name"`
+ Email string `json:"email"`
+}
+
+type PayloadCommit struct {
+ Id string `json:"id"`
+ Message string `json:"message"`
+ Url string `json:"url"`
+ Author *PayloadAuthor `json:"author"`
+}
+
+type PayloadRepo struct {
+ Id int64 `json:"id"`
+ Name string `json:"name"`
+ Url string `json:"url"`
+ Description string `json:"description"`
+ Website string `json:"website"`
+ Watchers int `json:"watchers"`
+ Owner *PayloadAuthor `json:"author"`
+ Private bool `json:"private"`
+}
+
+// Payload represents a payload information of hook.
+type Payload struct {
+ Secret string `json:"secret"`
+ Ref string `json:"ref"`
+ Commits []*PayloadCommit `json:"commits"`
+ Repo *PayloadRepo `json:"repository"`
+ Pusher *PayloadAuthor `json:"pusher"`
+}
+
+// HookTask represents a hook task.
+type HookTask struct {
+ Id int64
+ Type HookTaskType
+ Url string
+ *Payload `xorm:"-"`
+ PayloadContent string `xorm:"TEXT"`
+ ContentType HookContentType
+ IsSsl bool
+ IsDeliveried bool
+}
+
+// CreateHookTask creates a new hook task,
+// it handles conversion from Payload to PayloadContent.
+func CreateHookTask(t *HookTask) error {
+ data, err := json.Marshal(t.Payload)
+ if err != nil {
+ return err
+ }
+ t.PayloadContent = string(data)
+ _, err = orm.Insert(t)
+ return err
+}
+
+// UpdateHookTask updates information of hook task.
+func UpdateHookTask(t *HookTask) error {
+ _, err := orm.AllCols().Update(t)
+ return err
+}
+
+// DeliverHooks checks and delivers undelivered hooks.
+func DeliverHooks() {
+ timeout := time.Duration(setting.WebhookDeliverTimeout) * time.Second
+ orm.Where("is_deliveried=?", false).Iterate(new(HookTask),
+ func(idx int, bean interface{}) error {
+ t := bean.(*HookTask)
+ // Only support JSON now.
+ if _, err := httplib.Post(t.Url).SetTimeout(timeout, timeout).
+ Body([]byte(t.PayloadContent)).Response(); err != nil {
+ log.Error("webhook.DeliverHooks(Delivery): %v", err)
+ return nil
+ }
+
+ t.IsDeliveried = true
+ if err := UpdateHookTask(t); err != nil {
+ log.Error("webhook.DeliverHooks(UpdateHookTask): %v", err)
+ return nil
+ }
+
+ log.Trace("Hook delivered: %s", t.PayloadContent)
+ return nil
+ })
+}