diff --git a/docs/content/doc/features/comparison.en-us.md b/docs/content/doc/features/comparison.en-us.md
index c2b7b037c3..db0d3b5553 100644
--- a/docs/content/doc/features/comparison.en-us.md
+++ b/docs/content/doc/features/comparison.en-us.md
@@ -537,7 +537,7 @@ _Symbols used in table:_
Webhook support |
- ⁄ |
+ ✓ |
✓ |
✓ |
✓ |
diff --git a/models/action.go b/models/action.go
index 4f357cb2c5..c3ed9c7c02 100644
--- a/models/action.go
+++ b/models/action.go
@@ -618,6 +618,16 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
case ActionDeleteBranch: // Delete Branch
isHookEventPush = true
+ if err = PrepareWebhooks(repo, HookEventDelete, &api.DeletePayload{
+ Ref: refName,
+ RefType: "branch",
+ PusherType: api.PusherTypeUser,
+ Repo: apiRepo,
+ Sender: apiPusher,
+ }); err != nil {
+ return fmt.Errorf("PrepareWebhooks.(delete branch): %v", err)
+ }
+
case ActionPushTag: // Create
isHookEventPush = true
@@ -640,6 +650,16 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
}
case ActionDeleteTag: // Delete Tag
isHookEventPush = true
+
+ if err = PrepareWebhooks(repo, HookEventDelete, &api.DeletePayload{
+ Ref: refName,
+ RefType: "tag",
+ PusherType: api.PusherTypeUser,
+ Repo: apiRepo,
+ Sender: apiPusher,
+ }); err != nil {
+ return fmt.Errorf("PrepareWebhooks.(delete tag): %v", err)
+ }
}
if isHookEventPush {
diff --git a/models/issue_comment.go b/models/issue_comment.go
index 2c5875c29c..ad200934bc 100644
--- a/models/issue_comment.go
+++ b/models/issue_comment.go
@@ -83,9 +83,10 @@ const (
type Comment struct {
ID int64 `xorm:"pk autoincr"`
Type CommentType
- PosterID int64 `xorm:"INDEX"`
- Poster *User `xorm:"-"`
- IssueID int64 `xorm:"INDEX"`
+ PosterID int64 `xorm:"INDEX"`
+ Poster *User `xorm:"-"`
+ IssueID int64 `xorm:"INDEX"`
+ Issue *Issue `xorm:"-"`
LabelID int64
Label *Label `xorm:"-"`
OldMilestoneID int64
@@ -116,6 +117,15 @@ type Comment struct {
ShowTag CommentTag `xorm:"-"`
}
+// LoadIssue loads issue from database
+func (c *Comment) LoadIssue() (err error) {
+ if c.Issue != nil {
+ return nil
+ }
+ c.Issue, err = GetIssueByID(c.IssueID)
+ return
+}
+
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
func (c *Comment) AfterLoad(session *xorm.Session) {
var err error
@@ -146,40 +156,40 @@ func (c *Comment) AfterDelete() {
// HTMLURL formats a URL-string to the issue-comment
func (c *Comment) HTMLURL() string {
- issue, err := GetIssueByID(c.IssueID)
+ err := c.LoadIssue()
if err != nil { // Silently dropping errors :unamused:
- log.Error(4, "GetIssueByID(%d): %v", c.IssueID, err)
+ log.Error(4, "LoadIssue(%d): %v", c.IssueID, err)
return ""
}
- return fmt.Sprintf("%s#%s", issue.HTMLURL(), c.HashTag())
+ return fmt.Sprintf("%s#%s", c.Issue.HTMLURL(), c.HashTag())
}
// IssueURL formats a URL-string to the issue
func (c *Comment) IssueURL() string {
- issue, err := GetIssueByID(c.IssueID)
+ err := c.LoadIssue()
if err != nil { // Silently dropping errors :unamused:
- log.Error(4, "GetIssueByID(%d): %v", c.IssueID, err)
+ log.Error(4, "LoadIssue(%d): %v", c.IssueID, err)
return ""
}
- if issue.IsPull {
+ if c.Issue.IsPull {
return ""
}
- return issue.HTMLURL()
+ return c.Issue.HTMLURL()
}
// PRURL formats a URL-string to the pull-request
func (c *Comment) PRURL() string {
- issue, err := GetIssueByID(c.IssueID)
+ err := c.LoadIssue()
if err != nil { // Silently dropping errors :unamused:
- log.Error(4, "GetIssueByID(%d): %v", c.IssueID, err)
+ log.Error(4, "LoadIssue(%d): %v", c.IssueID, err)
return ""
}
- if !issue.IsPull {
+ if !c.Issue.IsPull {
return ""
}
- return issue.HTMLURL()
+ return c.Issue.HTMLURL()
}
// APIFormat converts a Comment to the api.Comment format
@@ -196,9 +206,14 @@ func (c *Comment) APIFormat() *api.Comment {
}
}
+// CommentHashTag returns unique hash tag for comment id.
+func CommentHashTag(id int64) string {
+ return fmt.Sprintf("issuecomment-%d", id)
+}
+
// HashTag returns unique hash tag for comment.
func (c *Comment) HashTag() string {
- return "issuecomment-" + com.ToStr(c.ID)
+ return CommentHashTag(c.ID)
}
// EventTag returns unique event hash tag for comment.
@@ -576,7 +591,7 @@ func CreateComment(opts *CreateCommentOptions) (comment *Comment, err error) {
// CreateIssueComment creates a plain issue comment.
func CreateIssueComment(doer *User, repo *Repository, issue *Issue, content string, attachments []string) (*Comment, error) {
- return CreateComment(&CreateCommentOptions{
+ comment, err := CreateComment(&CreateCommentOptions{
Type: CommentTypeComment,
Doer: doer,
Repo: repo,
@@ -584,6 +599,21 @@ func CreateIssueComment(doer *User, repo *Repository, issue *Issue, content stri
Content: content,
Attachments: attachments,
})
+ if err != nil {
+ return nil, fmt.Errorf("CreateComment: %v", err)
+ }
+
+ mode, _ := AccessLevel(doer.ID, repo)
+ if err = PrepareWebhooks(repo, HookEventIssueComment, &api.IssueCommentPayload{
+ Action: api.HookIssueCommentCreated,
+ Issue: issue.APIFormat(),
+ Comment: comment.APIFormat(),
+ Repository: repo.APIFormat(mode),
+ Sender: doer.APIFormat(),
+ }); err != nil {
+ log.Error(2, "PrepareWebhooks [comment_id: %d]: %v", comment.ID, err)
+ }
+ return comment, nil
}
// CreateRefComment creates a commit reference comment to issue.
@@ -696,17 +726,41 @@ func GetCommentsByRepoIDSince(repoID, since int64) ([]*Comment, error) {
}
// UpdateComment updates information of comment.
-func UpdateComment(c *Comment) error {
+func UpdateComment(doer *User, c *Comment, oldContent string) error {
if _, err := x.ID(c.ID).AllCols().Update(c); err != nil {
return err
} else if c.Type == CommentTypeComment {
UpdateIssueIndexer(c.IssueID)
}
+
+ if err := c.LoadIssue(); err != nil {
+ return err
+ }
+ if err := c.Issue.LoadAttributes(); err != nil {
+ return err
+ }
+
+ mode, _ := AccessLevel(doer.ID, c.Issue.Repo)
+ if err := PrepareWebhooks(c.Issue.Repo, HookEventIssueComment, &api.IssueCommentPayload{
+ Action: api.HookIssueCommentEdited,
+ Issue: c.Issue.APIFormat(),
+ Comment: c.APIFormat(),
+ Changes: &api.ChangesPayload{
+ Body: &api.ChangesFromPayload{
+ From: oldContent,
+ },
+ },
+ Repository: c.Issue.Repo.APIFormat(mode),
+ Sender: doer.APIFormat(),
+ }); err != nil {
+ log.Error(2, "PrepareWebhooks [comment_id: %d]: %v", c.ID, err)
+ }
+
return nil
}
// DeleteComment deletes the comment
-func DeleteComment(comment *Comment) error {
+func DeleteComment(doer *User, comment *Comment) error {
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
@@ -733,5 +787,25 @@ func DeleteComment(comment *Comment) error {
} else if comment.Type == CommentTypeComment {
UpdateIssueIndexer(comment.IssueID)
}
+
+ if err := comment.LoadIssue(); err != nil {
+ return err
+ }
+ if err := comment.Issue.LoadAttributes(); err != nil {
+ return err
+ }
+
+ mode, _ := AccessLevel(doer.ID, comment.Issue.Repo)
+
+ if err := PrepareWebhooks(comment.Issue.Repo, HookEventIssueComment, &api.IssueCommentPayload{
+ Action: api.HookIssueCommentDeleted,
+ Issue: comment.Issue.APIFormat(),
+ Comment: comment.APIFormat(),
+ Repository: comment.Issue.Repo.APIFormat(mode),
+ Sender: doer.APIFormat(),
+ }); err != nil {
+ log.Error(2, "PrepareWebhooks [comment_id: %d]: %v", comment.ID, err)
+ }
+
return nil
}
diff --git a/models/issue_milestone.go b/models/issue_milestone.go
index 8de1f97571..be55dc4f5b 100644
--- a/models/issue_milestone.go
+++ b/models/issue_milestone.go
@@ -5,6 +5,9 @@
package models
import (
+ "fmt"
+
+ "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
api "code.gitea.io/sdk/gitea"
@@ -358,7 +361,49 @@ func ChangeMilestoneAssign(issue *Issue, doer *User, oldMilestoneID int64) (err
if err = changeMilestoneAssign(sess, doer, issue, oldMilestoneID); err != nil {
return err
}
- return sess.Commit()
+
+ if err = sess.Commit(); err != nil {
+ return fmt.Errorf("Commit: %v", err)
+ }
+
+ var hookAction api.HookIssueAction
+ if issue.MilestoneID > 0 {
+ hookAction = api.HookIssueMilestoned
+ } else {
+ hookAction = api.HookIssueDemilestoned
+ }
+
+ if err = issue.LoadAttributes(); err != nil {
+ return err
+ }
+
+ mode, _ := AccessLevel(doer.ID, issue.Repo)
+ if issue.IsPull {
+ err = issue.PullRequest.LoadIssue()
+ if err != nil {
+ log.Error(2, "LoadIssue: %v", err)
+ return
+ }
+ err = PrepareWebhooks(issue.Repo, HookEventPullRequest, &api.PullRequestPayload{
+ Action: hookAction,
+ Index: issue.Index,
+ PullRequest: issue.PullRequest.APIFormat(),
+ Repository: issue.Repo.APIFormat(mode),
+ Sender: doer.APIFormat(),
+ })
+ } else {
+ err = PrepareWebhooks(issue.Repo, HookEventIssues, &api.IssuePayload{
+ Action: hookAction,
+ Index: issue.Index,
+ Issue: issue.APIFormat(),
+ Repository: issue.Repo.APIFormat(mode),
+ Sender: doer.APIFormat(),
+ })
+ }
+ if err != nil {
+ log.Error(2, "PrepareWebhooks [is_pull: %v]: %v", issue.IsPull, err)
+ }
+ return nil
}
// DeleteMilestoneByRepoID deletes a milestone from a repository.
diff --git a/models/issue_milestone_test.go b/models/issue_milestone_test.go
index c9b53f4f4a..3ea63d2d6b 100644
--- a/models/issue_milestone_test.go
+++ b/models/issue_milestone_test.go
@@ -232,6 +232,8 @@ func TestChangeMilestoneAssign(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
issue := AssertExistsAndLoadBean(t, &Issue{RepoID: 1}).(*Issue)
doer := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ assert.NotNil(t, issue)
+ assert.NotNil(t, doer)
oldMilestoneID := issue.MilestoneID
issue.MilestoneID = 2
diff --git a/models/release.go b/models/release.go
index 586f494e7d..bc0260c71d 100644
--- a/models/release.go
+++ b/models/release.go
@@ -10,6 +10,7 @@ import (
"strings"
"code.gitea.io/git"
+ "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
@@ -190,8 +191,27 @@ func CreateRelease(gitRepo *git.Repository, rel *Release, attachmentUUIDs []stri
}
err = addReleaseAttachments(rel.ID, attachmentUUIDs)
+ if err != nil {
+ return err
+ }
- return err
+ if !rel.IsDraft {
+ if err := rel.LoadAttributes(); err != nil {
+ log.Error(2, "LoadAttributes: %v", err)
+ } else {
+ mode, _ := AccessLevel(rel.PublisherID, rel.Repo)
+ if err := PrepareWebhooks(rel.Repo, HookEventRelease, &api.ReleasePayload{
+ Action: api.HookReleasePublished,
+ Release: rel.APIFormat(),
+ Repository: rel.Repo.APIFormat(mode),
+ Sender: rel.Publisher.APIFormat(),
+ }); err != nil {
+ log.Error(2, "PrepareWebhooks: %v", err)
+ }
+ }
+ }
+
+ return nil
}
// GetRelease returns release by given ID.
diff --git a/models/repo.go b/models/repo.go
index 4a7eb859c4..f5ec1a9fdd 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -2456,6 +2456,17 @@ func ForkRepository(doer, u *User, oldRepo *Repository, name, desc string) (_ *R
return nil, err
}
+ oldMode, _ := AccessLevel(doer.ID, oldRepo)
+ mode, _ := AccessLevel(doer.ID, repo)
+
+ if err = PrepareWebhooks(oldRepo, HookEventFork, &api.ForkPayload{
+ Forkee: repo.APIFormat(mode),
+ Repo: oldRepo.APIFormat(oldMode),
+ Sender: doer.APIFormat(),
+ }); err != nil {
+ log.Error(2, "PrepareWebhooks [repo_id: %d]: %v", oldRepo.ID, err)
+ }
+
if err = repo.UpdateSize(); err != nil {
log.Error(4, "Failed to update size for repository: %v", err)
}
diff --git a/models/webhook.go b/models/webhook.go
index 62db84f86a..c44ca2960d 100644
--- a/models/webhook.go
+++ b/models/webhook.go
@@ -66,10 +66,15 @@ func IsValidHookContentType(name string) bool {
// HookEvents is a set of web hook events
type HookEvents struct {
- Create bool `json:"create"`
- Push bool `json:"push"`
- PullRequest bool `json:"pull_request"`
- Repository bool `json:"repository"`
+ Create bool `json:"create"`
+ Delete bool `json:"delete"`
+ Fork bool `json:"fork"`
+ Issues bool `json:"issues"`
+ IssueComment bool `json:"issue_comment"`
+ Push bool `json:"push"`
+ PullRequest bool `json:"pull_request"`
+ Repository bool `json:"repository"`
+ Release bool `json:"release"`
}
// HookEvent represents events that will delivery hook.
@@ -155,6 +160,30 @@ func (w *Webhook) HasCreateEvent() bool {
(w.ChooseEvents && w.HookEvents.Create)
}
+// HasDeleteEvent returns true if hook enabled delete event.
+func (w *Webhook) HasDeleteEvent() bool {
+ return w.SendEverything ||
+ (w.ChooseEvents && w.HookEvents.Delete)
+}
+
+// HasForkEvent returns true if hook enabled fork event.
+func (w *Webhook) HasForkEvent() bool {
+ return w.SendEverything ||
+ (w.ChooseEvents && w.HookEvents.Fork)
+}
+
+// HasIssuesEvent returns true if hook enabled issues event.
+func (w *Webhook) HasIssuesEvent() bool {
+ return w.SendEverything ||
+ (w.ChooseEvents && w.HookEvents.Issues)
+}
+
+// HasIssueCommentEvent returns true if hook enabled issue_comment event.
+func (w *Webhook) HasIssueCommentEvent() bool {
+ return w.SendEverything ||
+ (w.ChooseEvents && w.HookEvents.IssueComment)
+}
+
// HasPushEvent returns true if hook enabled push event.
func (w *Webhook) HasPushEvent() bool {
return w.PushOnly || w.SendEverything ||
@@ -167,23 +196,46 @@ func (w *Webhook) HasPullRequestEvent() bool {
(w.ChooseEvents && w.HookEvents.PullRequest)
}
+// HasReleaseEvent returns if hook enabled release event.
+func (w *Webhook) HasReleaseEvent() bool {
+ return w.SendEverything ||
+ (w.ChooseEvents && w.HookEvents.Release)
+}
+
// HasRepositoryEvent returns if hook enabled repository event.
func (w *Webhook) HasRepositoryEvent() bool {
return w.SendEverything ||
(w.ChooseEvents && w.HookEvents.Repository)
}
+func (w *Webhook) eventCheckers() []struct {
+ has func() bool
+ typ HookEventType
+} {
+ return []struct {
+ has func() bool
+ typ HookEventType
+ }{
+ {w.HasCreateEvent, HookEventCreate},
+ {w.HasDeleteEvent, HookEventDelete},
+ {w.HasForkEvent, HookEventFork},
+ {w.HasPushEvent, HookEventPush},
+ {w.HasIssuesEvent, HookEventIssues},
+ {w.HasIssueCommentEvent, HookEventIssueComment},
+ {w.HasPullRequestEvent, HookEventPullRequest},
+ {w.HasRepositoryEvent, HookEventRepository},
+ {w.HasReleaseEvent, HookEventRelease},
+ }
+}
+
// EventsArray returns an array of hook events
func (w *Webhook) EventsArray() []string {
- events := make([]string, 0, 3)
- if w.HasCreateEvent() {
- events = append(events, "create")
- }
- if w.HasPushEvent() {
- events = append(events, "push")
- }
- if w.HasPullRequestEvent() {
- events = append(events, "pull_request")
+ events := make([]string, 0, 7)
+
+ for _, c := range w.eventCheckers() {
+ if c.has() {
+ events = append(events, string(c.typ))
+ }
}
return events
}
@@ -373,10 +425,15 @@ type HookEventType string
// Types of hook events
const (
- HookEventCreate HookEventType = "create"
- HookEventPush HookEventType = "push"
- HookEventPullRequest HookEventType = "pull_request"
- HookEventRepository HookEventType = "repository"
+ HookEventCreate HookEventType = "create"
+ HookEventDelete HookEventType = "delete"
+ HookEventFork HookEventType = "fork"
+ HookEventPush HookEventType = "push"
+ HookEventIssues HookEventType = "issues"
+ HookEventIssueComment HookEventType = "issue_comment"
+ HookEventPullRequest HookEventType = "pull_request"
+ HookEventRepository HookEventType = "repository"
+ HookEventRelease HookEventType = "release"
)
// HookRequest represents hook task request information.
@@ -488,22 +545,11 @@ func PrepareWebhook(w *Webhook, repo *Repository, event HookEventType, p api.Pay
}
func prepareWebhook(e Engine, w *Webhook, repo *Repository, event HookEventType, p api.Payloader) error {
- switch event {
- case HookEventCreate:
- if !w.HasCreateEvent() {
- return nil
- }
- case HookEventPush:
- if !w.HasPushEvent() {
- return nil
- }
- case HookEventPullRequest:
- if !w.HasPullRequestEvent() {
- return nil
- }
- case HookEventRepository:
- if !w.HasRepositoryEvent() {
- return nil
+ for _, e := range w.eventCheckers() {
+ if event == e.typ {
+ if !e.has() {
+ return nil
+ }
}
}
diff --git a/models/webhook_dingtalk.go b/models/webhook_dingtalk.go
index 719ffcae73..7eb189f9bb 100644
--- a/models/webhook_dingtalk.go
+++ b/models/webhook_dingtalk.go
@@ -49,6 +49,38 @@ func getDingtalkCreatePayload(p *api.CreatePayload) (*DingtalkPayload, error) {
}, nil
}
+func getDingtalkDeletePayload(p *api.DeletePayload) (*DingtalkPayload, error) {
+ // created tag/branch
+ refName := git.RefEndName(p.Ref)
+ title := fmt.Sprintf("[%s] %s %s deleted", p.Repo.FullName, p.RefType, refName)
+
+ return &DingtalkPayload{
+ MsgType: "actionCard",
+ ActionCard: dingtalk.ActionCard{
+ Text: title,
+ Title: title,
+ HideAvatar: "0",
+ SingleTitle: fmt.Sprintf("view branch %s", refName),
+ SingleURL: p.Repo.HTMLURL + "/src/" + refName,
+ },
+ }, nil
+}
+
+func getDingtalkForkPayload(p *api.ForkPayload) (*DingtalkPayload, error) {
+ title := fmt.Sprintf("%s is forked to %s", p.Forkee.FullName, p.Repo.FullName)
+
+ return &DingtalkPayload{
+ MsgType: "actionCard",
+ ActionCard: dingtalk.ActionCard{
+ Text: title,
+ Title: title,
+ HideAvatar: "0",
+ SingleTitle: fmt.Sprintf("view forked repo %s", p.Repo.FullName),
+ SingleURL: p.Repo.HTMLURL,
+ },
+ }, nil
+}
+
func getDingtalkPushPayload(p *api.PushPayload) (*DingtalkPayload, error) {
var (
branchName = git.RefEndName(p.Ref)
@@ -98,6 +130,80 @@ func getDingtalkPushPayload(p *api.PushPayload) (*DingtalkPayload, error) {
}, nil
}
+func getDingtalkIssuesPayload(p *api.IssuePayload) (*DingtalkPayload, error) {
+ var text, title string
+ switch p.Action {
+ case api.HookIssueOpened:
+ title = fmt.Sprintf("[%s] Issue opened: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title)
+ text = p.Issue.Body
+ case api.HookIssueClosed:
+ title = fmt.Sprintf("[%s] Issue closed: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title)
+ text = p.Issue.Body
+ case api.HookIssueReOpened:
+ title = fmt.Sprintf("[%s] Issue re-opened: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title)
+ text = p.Issue.Body
+ case api.HookIssueEdited:
+ title = fmt.Sprintf("[%s] Issue edited: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title)
+ text = p.Issue.Body
+ case api.HookIssueAssigned:
+ title = fmt.Sprintf("[%s] Issue assigned to %s: #%d %s", p.Repository.FullName,
+ p.Issue.Assignee.UserName, p.Index, p.Issue.Title)
+ text = p.Issue.Body
+ case api.HookIssueUnassigned:
+ title = fmt.Sprintf("[%s] Issue unassigned: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title)
+ text = p.Issue.Body
+ case api.HookIssueLabelUpdated:
+ title = fmt.Sprintf("[%s] Pull request labels updated: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title)
+ text = p.Issue.Body
+ case api.HookIssueLabelCleared:
+ title = fmt.Sprintf("[%s] Pull request labels cleared: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title)
+ text = p.Issue.Body
+ case api.HookIssueSynchronized:
+ title = fmt.Sprintf("[%s] Pull request synchronized: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title)
+ text = p.Issue.Body
+ }
+
+ return &DingtalkPayload{
+ MsgType: "actionCard",
+ ActionCard: dingtalk.ActionCard{
+ Text: text,
+ Title: title,
+ HideAvatar: "0",
+ SingleTitle: "view pull request",
+ SingleURL: p.Issue.URL,
+ },
+ }, nil
+}
+
+func getDingtalkIssueCommentPayload(p *api.IssueCommentPayload) (*DingtalkPayload, error) {
+ title := fmt.Sprintf("#%d %s", p.Issue.Index, p.Issue.Title)
+ url := fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, CommentHashTag(p.Comment.ID))
+ var content string
+ switch p.Action {
+ case api.HookIssueCommentCreated:
+ title = "New comment: " + title
+ content = p.Comment.Body
+ case api.HookIssueCommentEdited:
+ title = "Comment edited: " + title
+ content = p.Comment.Body
+ case api.HookIssueCommentDeleted:
+ title = "Comment deleted: " + title
+ url = fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Issue.Index)
+ content = p.Comment.Body
+ }
+
+ return &DingtalkPayload{
+ MsgType: "actionCard",
+ ActionCard: dingtalk.ActionCard{
+ Text: content,
+ Title: title,
+ HideAvatar: "0",
+ SingleTitle: "view pull request",
+ SingleURL: url,
+ },
+ }, nil
+}
+
func getDingtalkPullRequestPayload(p *api.PullRequestPayload) (*DingtalkPayload, error) {
var text, title string
switch p.Action {
@@ -182,6 +288,27 @@ func getDingtalkRepositoryPayload(p *api.RepositoryPayload) (*DingtalkPayload, e
return nil, nil
}
+func getDingtalkReleasePayload(p *api.ReleasePayload) (*DingtalkPayload, error) {
+ var title, url string
+ switch p.Action {
+ case api.HookReleasePublished:
+ title = fmt.Sprintf("[%s] Release created", p.Release.TagName)
+ url = p.Release.URL
+ return &DingtalkPayload{
+ MsgType: "actionCard",
+ ActionCard: dingtalk.ActionCard{
+ Text: title,
+ Title: title,
+ HideAvatar: "0",
+ SingleTitle: "view repository",
+ SingleURL: url,
+ },
+ }, nil
+ }
+
+ return nil, nil
+}
+
// GetDingtalkPayload converts a ding talk webhook into a DingtalkPayload
func GetDingtalkPayload(p api.Payloader, event HookEventType, meta string) (*DingtalkPayload, error) {
s := new(DingtalkPayload)
@@ -189,12 +316,22 @@ func GetDingtalkPayload(p api.Payloader, event HookEventType, meta string) (*Din
switch event {
case HookEventCreate:
return getDingtalkCreatePayload(p.(*api.CreatePayload))
+ case HookEventDelete:
+ return getDingtalkDeletePayload(p.(*api.DeletePayload))
+ case HookEventFork:
+ return getDingtalkForkPayload(p.(*api.ForkPayload))
+ case HookEventIssues:
+ return getDingtalkIssuesPayload(p.(*api.IssuePayload))
+ case HookEventIssueComment:
+ return getDingtalkIssueCommentPayload(p.(*api.IssueCommentPayload))
case HookEventPush:
return getDingtalkPushPayload(p.(*api.PushPayload))
case HookEventPullRequest:
return getDingtalkPullRequestPayload(p.(*api.PullRequestPayload))
case HookEventRepository:
return getDingtalkRepositoryPayload(p.(*api.RepositoryPayload))
+ case HookEventRelease:
+ return getDingtalkReleasePayload(p.(*api.ReleasePayload))
}
return s, nil
diff --git a/models/webhook_discord.go b/models/webhook_discord.go
index 40d9d58992..04ebbc293f 100644
--- a/models/webhook_discord.go
+++ b/models/webhook_discord.go
@@ -115,6 +115,51 @@ func getDiscordCreatePayload(p *api.CreatePayload, meta *DiscordMeta) (*DiscordP
}, nil
}
+func getDiscordDeletePayload(p *api.DeletePayload, meta *DiscordMeta) (*DiscordPayload, error) {
+ // deleted tag/branch
+ refName := git.RefEndName(p.Ref)
+ title := fmt.Sprintf("[%s] %s %s deleted", p.Repo.FullName, p.RefType, refName)
+
+ return &DiscordPayload{
+ Username: meta.Username,
+ AvatarURL: meta.IconURL,
+ Embeds: []DiscordEmbed{
+ {
+ Title: title,
+ URL: p.Repo.HTMLURL + "/src/" + refName,
+ Color: warnColor,
+ Author: DiscordEmbedAuthor{
+ Name: p.Sender.UserName,
+ URL: setting.AppURL + p.Sender.UserName,
+ IconURL: p.Sender.AvatarURL,
+ },
+ },
+ },
+ }, nil
+}
+
+func getDiscordForkPayload(p *api.ForkPayload, meta *DiscordMeta) (*DiscordPayload, error) {
+ // fork
+ title := fmt.Sprintf("%s is forked to %s", p.Forkee.FullName, p.Repo.FullName)
+
+ return &DiscordPayload{
+ Username: meta.Username,
+ AvatarURL: meta.IconURL,
+ Embeds: []DiscordEmbed{
+ {
+ Title: title,
+ URL: p.Repo.HTMLURL,
+ Color: successColor,
+ Author: DiscordEmbedAuthor{
+ Name: p.Sender.UserName,
+ URL: setting.AppURL + p.Sender.UserName,
+ IconURL: p.Sender.AvatarURL,
+ },
+ },
+ },
+ }, nil
+}
+
func getDiscordPushPayload(p *api.PushPayload, meta *DiscordMeta) (*DiscordPayload, error) {
var (
branchName = git.RefEndName(p.Ref)
@@ -165,6 +210,108 @@ func getDiscordPushPayload(p *api.PushPayload, meta *DiscordMeta) (*DiscordPaylo
}, nil
}
+func getDiscordIssuesPayload(p *api.IssuePayload, meta *DiscordMeta) (*DiscordPayload, error) {
+ var text, title string
+ var color int
+ switch p.Action {
+ case api.HookIssueOpened:
+ title = fmt.Sprintf("[%s] Issue opened: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title)
+ text = p.Issue.Body
+ color = warnColor
+ case api.HookIssueClosed:
+ title = fmt.Sprintf("[%s] Issue closed: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title)
+ color = failedColor
+ text = p.Issue.Body
+ case api.HookIssueReOpened:
+ title = fmt.Sprintf("[%s] Issue re-opened: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title)
+ text = p.Issue.Body
+ color = warnColor
+ case api.HookIssueEdited:
+ title = fmt.Sprintf("[%s] Issue edited: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title)
+ text = p.Issue.Body
+ color = warnColor
+ case api.HookIssueAssigned:
+ title = fmt.Sprintf("[%s] Issue assigned to %s: #%d %s", p.Repository.FullName,
+ p.Issue.Assignee.UserName, p.Index, p.Issue.Title)
+ text = p.Issue.Body
+ color = successColor
+ case api.HookIssueUnassigned:
+ title = fmt.Sprintf("[%s] Issue unassigned: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title)
+ text = p.Issue.Body
+ color = warnColor
+ case api.HookIssueLabelUpdated:
+ title = fmt.Sprintf("[%s] Issue labels updated: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title)
+ text = p.Issue.Body
+ color = warnColor
+ case api.HookIssueLabelCleared:
+ title = fmt.Sprintf("[%s] Issue labels cleared: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title)
+ text = p.Issue.Body
+ color = warnColor
+ case api.HookIssueSynchronized:
+ title = fmt.Sprintf("[%s] Issue synchronized: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title)
+ text = p.Issue.Body
+ color = warnColor
+ }
+
+ return &DiscordPayload{
+ Username: meta.Username,
+ AvatarURL: meta.IconURL,
+ Embeds: []DiscordEmbed{
+ {
+ Title: title,
+ Description: text,
+ URL: p.Issue.URL,
+ Color: color,
+ Author: DiscordEmbedAuthor{
+ Name: p.Sender.UserName,
+ URL: setting.AppURL + p.Sender.UserName,
+ IconURL: p.Sender.AvatarURL,
+ },
+ },
+ },
+ }, nil
+}
+
+func getDiscordIssueCommentPayload(p *api.IssueCommentPayload, discord *DiscordMeta) (*DiscordPayload, error) {
+ title := fmt.Sprintf("#%d %s", p.Issue.Index, p.Issue.Title)
+ url := fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, CommentHashTag(p.Comment.ID))
+ content := ""
+ var color int
+ switch p.Action {
+ case api.HookIssueCommentCreated:
+ title = "New comment: " + title
+ content = p.Comment.Body
+ color = successColor
+ case api.HookIssueCommentEdited:
+ title = "Comment edited: " + title
+ content = p.Comment.Body
+ color = warnColor
+ case api.HookIssueCommentDeleted:
+ title = "Comment deleted: " + title
+ url = fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Issue.Index)
+ content = p.Comment.Body
+ color = warnColor
+ }
+
+ return &DiscordPayload{
+ Username: discord.Username,
+ AvatarURL: discord.IconURL,
+ Embeds: []DiscordEmbed{
+ {
+ Title: title,
+ Description: content,
+ URL: url,
+ Color: color,
+ Author: DiscordEmbedAuthor{
+ Name: p.Sender.UserName,
+ URL: setting.AppURL + p.Sender.UserName,
+ IconURL: p.Sender.AvatarURL,
+ },
+ },
+ },
+ }, nil
+}
+
func getDiscordPullRequestPayload(p *api.PullRequestPayload, meta *DiscordMeta) (*DiscordPayload, error) {
var text, title string
var color int
@@ -267,6 +414,35 @@ func getDiscordRepositoryPayload(p *api.RepositoryPayload, meta *DiscordMeta) (*
}, nil
}
+func getDiscordReleasePayload(p *api.ReleasePayload, meta *DiscordMeta) (*DiscordPayload, error) {
+ var title, url string
+ var color int
+ switch p.Action {
+ case api.HookReleasePublished:
+ title = fmt.Sprintf("[%s] Release created", p.Release.TagName)
+ url = p.Release.URL
+ color = successColor
+ }
+
+ return &DiscordPayload{
+ Username: meta.Username,
+ AvatarURL: meta.IconURL,
+ Embeds: []DiscordEmbed{
+ {
+ Title: title,
+ Description: fmt.Sprintf("%s", p.Release.Note),
+ URL: url,
+ Color: color,
+ Author: DiscordEmbedAuthor{
+ Name: p.Sender.UserName,
+ URL: setting.AppURL + p.Sender.UserName,
+ IconURL: p.Sender.AvatarURL,
+ },
+ },
+ },
+ }, nil
+}
+
// GetDiscordPayload converts a discord webhook into a DiscordPayload
func GetDiscordPayload(p api.Payloader, event HookEventType, meta string) (*DiscordPayload, error) {
s := new(DiscordPayload)
@@ -279,12 +455,22 @@ func GetDiscordPayload(p api.Payloader, event HookEventType, meta string) (*Disc
switch event {
case HookEventCreate:
return getDiscordCreatePayload(p.(*api.CreatePayload), discord)
+ case HookEventDelete:
+ return getDiscordDeletePayload(p.(*api.DeletePayload), discord)
+ case HookEventFork:
+ return getDiscordForkPayload(p.(*api.ForkPayload), discord)
+ case HookEventIssues:
+ return getDiscordIssuesPayload(p.(*api.IssuePayload), discord)
+ case HookEventIssueComment:
+ return getDiscordIssueCommentPayload(p.(*api.IssueCommentPayload), discord)
case HookEventPush:
return getDiscordPushPayload(p.(*api.PushPayload), discord)
case HookEventPullRequest:
return getDiscordPullRequestPayload(p.(*api.PullRequestPayload), discord)
case HookEventRepository:
return getDiscordRepositoryPayload(p.(*api.RepositoryPayload), discord)
+ case HookEventRelease:
+ return getDiscordReleasePayload(p.(*api.ReleasePayload), discord)
}
return s, nil
diff --git a/models/webhook_slack.go b/models/webhook_slack.go
index 256819adc5..7b18fe3278 100644
--- a/models/webhook_slack.go
+++ b/models/webhook_slack.go
@@ -106,6 +106,122 @@ func getSlackCreatePayload(p *api.CreatePayload, slack *SlackMeta) (*SlackPayloa
}, nil
}
+// getSlackDeletePayload composes Slack payload for delete a branch or tag.
+func getSlackDeletePayload(p *api.DeletePayload, slack *SlackMeta) (*SlackPayload, error) {
+ refName := git.RefEndName(p.Ref)
+ repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
+ text := fmt.Sprintf("[%s:%s] %s deleted by %s", repoLink, refName, p.RefType, p.Sender.UserName)
+ return &SlackPayload{
+ Channel: slack.Channel,
+ Text: text,
+ Username: slack.Username,
+ IconURL: slack.IconURL,
+ }, nil
+}
+
+// getSlackForkPayload composes Slack payload for forked by a repository.
+func getSlackForkPayload(p *api.ForkPayload, slack *SlackMeta) (*SlackPayload, error) {
+ baseLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
+ forkLink := SlackLinkFormatter(p.Forkee.HTMLURL, p.Forkee.FullName)
+ text := fmt.Sprintf("%s is forked to %s", baseLink, forkLink)
+ return &SlackPayload{
+ Channel: slack.Channel,
+ Text: text,
+ Username: slack.Username,
+ IconURL: slack.IconURL,
+ }, nil
+}
+
+func getSlackIssuesPayload(p *api.IssuePayload, slack *SlackMeta) (*SlackPayload, error) {
+ senderLink := SlackLinkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName)
+ titleLink := SlackLinkFormatter(fmt.Sprintf("%s/pulls/%d", p.Repository.HTMLURL, p.Index),
+ fmt.Sprintf("#%d %s", p.Index, p.Issue.Title))
+ var text, title, attachmentText string
+ switch p.Action {
+ case api.HookIssueOpened:
+ text = fmt.Sprintf("[%s] Issue submitted by %s", p.Repository.FullName, senderLink)
+ title = titleLink
+ attachmentText = SlackTextFormatter(p.Issue.Body)
+ case api.HookIssueClosed:
+ text = fmt.Sprintf("[%s] Issue closed: %s by %s", p.Repository.FullName, titleLink, senderLink)
+ case api.HookIssueReOpened:
+ text = fmt.Sprintf("[%s] Issue re-opened: %s by %s", p.Repository.FullName, titleLink, senderLink)
+ case api.HookIssueEdited:
+ text = fmt.Sprintf("[%s] Issue edited: %s by %s", p.Repository.FullName, titleLink, senderLink)
+ attachmentText = SlackTextFormatter(p.Issue.Body)
+ case api.HookIssueAssigned:
+ text = fmt.Sprintf("[%s] Issue assigned to %s: %s by %s", p.Repository.FullName,
+ SlackLinkFormatter(setting.AppURL+p.Issue.Assignee.UserName, p.Issue.Assignee.UserName),
+ titleLink, senderLink)
+ case api.HookIssueUnassigned:
+ text = fmt.Sprintf("[%s] Issue unassigned: %s by %s", p.Repository.FullName, titleLink, senderLink)
+ case api.HookIssueLabelUpdated:
+ text = fmt.Sprintf("[%s] Issue labels updated: %s by %s", p.Repository.FullName, titleLink, senderLink)
+ case api.HookIssueLabelCleared:
+ text = fmt.Sprintf("[%s] Issue labels cleared: %s by %s", p.Repository.FullName, titleLink, senderLink)
+ case api.HookIssueSynchronized:
+ text = fmt.Sprintf("[%s] Issue synchronized: %s by %s", p.Repository.FullName, titleLink, senderLink)
+ }
+
+ return &SlackPayload{
+ Channel: slack.Channel,
+ Text: text,
+ Username: slack.Username,
+ IconURL: slack.IconURL,
+ Attachments: []SlackAttachment{{
+ Color: slack.Color,
+ Title: title,
+ Text: attachmentText,
+ }},
+ }, nil
+}
+
+func getSlackIssueCommentPayload(p *api.IssueCommentPayload, slack *SlackMeta) (*SlackPayload, error) {
+ senderLink := SlackLinkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName)
+ titleLink := SlackLinkFormatter(fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, CommentHashTag(p.Comment.ID)),
+ fmt.Sprintf("#%d %s", p.Issue.Index, p.Issue.Title))
+ var text, title, attachmentText string
+ switch p.Action {
+ case api.HookIssueCommentCreated:
+ text = fmt.Sprintf("[%s] New comment created by %s", p.Repository.FullName, senderLink)
+ title = titleLink
+ attachmentText = SlackTextFormatter(p.Comment.Body)
+ case api.HookIssueCommentEdited:
+ text = fmt.Sprintf("[%s] Comment edited by %s", p.Repository.FullName, senderLink)
+ title = titleLink
+ attachmentText = SlackTextFormatter(p.Comment.Body)
+ case api.HookIssueCommentDeleted:
+ text = fmt.Sprintf("[%s] Comment deleted by %s", p.Repository.FullName, senderLink)
+ title = SlackLinkFormatter(fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Issue.Index),
+ fmt.Sprintf("#%d %s", p.Issue.Index, p.Issue.Title))
+ attachmentText = SlackTextFormatter(p.Comment.Body)
+ }
+
+ return &SlackPayload{
+ Channel: slack.Channel,
+ Text: text,
+ Username: slack.Username,
+ IconURL: slack.IconURL,
+ Attachments: []SlackAttachment{{
+ Color: slack.Color,
+ Title: title,
+ Text: attachmentText,
+ }},
+ }, nil
+}
+
+func getSlackReleasePayload(p *api.ReleasePayload, slack *SlackMeta) (*SlackPayload, error) {
+ repoLink := SlackLinkFormatter(p.Repository.HTMLURL, p.Repository.Name)
+ refLink := SlackLinkFormatter(p.Repository.HTMLURL+"/src/"+p.Release.TagName, p.Release.TagName)
+ text := fmt.Sprintf("[%s] new release %s published by %s", repoLink, refLink, p.Sender.UserName)
+ return &SlackPayload{
+ Channel: slack.Channel,
+ Text: text,
+ Username: slack.Username,
+ IconURL: slack.IconURL,
+ }, nil
+}
+
func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, error) {
// n new commits
var (
@@ -238,12 +354,22 @@ func GetSlackPayload(p api.Payloader, event HookEventType, meta string) (*SlackP
switch event {
case HookEventCreate:
return getSlackCreatePayload(p.(*api.CreatePayload), slack)
+ case HookEventDelete:
+ return getSlackDeletePayload(p.(*api.DeletePayload), slack)
+ case HookEventFork:
+ return getSlackForkPayload(p.(*api.ForkPayload), slack)
+ case HookEventIssues:
+ return getSlackIssuesPayload(p.(*api.IssuePayload), slack)
+ case HookEventIssueComment:
+ return getSlackIssueCommentPayload(p.(*api.IssueCommentPayload), slack)
case HookEventPush:
return getSlackPushPayload(p.(*api.PushPayload), slack)
case HookEventPullRequest:
return getSlackPullRequestPayload(p.(*api.PullRequestPayload), slack)
case HookEventRepository:
return getSlackRepositoryPayload(p.(*api.RepositoryPayload), slack)
+ case HookEventRelease:
+ return getSlackReleasePayload(p.(*api.ReleasePayload), slack)
}
return s, nil
diff --git a/models/webhook_test.go b/models/webhook_test.go
index eeae7efbcb..50106a3792 100644
--- a/models/webhook_test.go
+++ b/models/webhook_test.go
@@ -73,7 +73,7 @@ func TestWebhook_UpdateEvent(t *testing.T) {
}
func TestWebhook_EventsArray(t *testing.T) {
- assert.Equal(t, []string{"create", "push", "pull_request"},
+ assert.Equal(t, []string{"create", "delete", "fork", "push", "issues", "issue_comment", "pull_request", "repository", "release"},
(&Webhook{
HookEvent: &HookEvent{SendEverything: true},
}).EventsArray(),
diff --git a/modules/auth/repo_form.go b/modules/auth/repo_form.go
index 431ab7f13e..e3471fff5d 100644
--- a/modules/auth/repo_form.go
+++ b/modules/auth/repo_form.go
@@ -155,12 +155,17 @@ func (f *ProtectBranchForm) Validate(ctx *macaron.Context, errs binding.Errors)
// WebhookForm form for changing web hook
type WebhookForm struct {
- Events string
- Create bool
- Push bool
- PullRequest bool
- Repository bool
- Active bool
+ Events string
+ Create bool
+ Delete bool
+ Fork bool
+ Issues bool
+ IssueComment bool
+ Release bool
+ Push bool
+ PullRequest bool
+ Repository bool
+ Active bool
}
// PushOnly if the hook will be triggered when push
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 8ef0056608..30f07dc131 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -1000,6 +1000,16 @@ settings.event_send_everything = All Events
settings.event_choose = Custom Events…
settings.event_create = Create
settings.event_create_desc = Branch or tag created.
+settings.event_delete = Delete
+settings.event_delete_desc = Branch or tag deleted
+settings.event_fork = Fork
+settings.event_fork_desc = Repository forked
+settings.event_issues = Issues
+settings.event_issues_desc = Issue opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, milestoned, or demilestoned.
+settings.event_issue_comment = Issue Comment
+settings.event_issue_comment_desc = Issue comment created, edited, or deleted.
+settings.event_release = Release
+settings.event_release_desc = Release published in a repository.
settings.event_pull_request = Pull Request
settings.event_pull_request_desc = Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared or synchronized.
settings.event_push = Push
diff --git a/routers/api/v1/repo/issue_comment.go b/routers/api/v1/repo/issue_comment.go
index a9258849ea..2865ea9165 100644
--- a/routers/api/v1/repo/issue_comment.go
+++ b/routers/api/v1/repo/issue_comment.go
@@ -261,8 +261,9 @@ func editIssueComment(ctx *context.APIContext, form api.EditIssueCommentOption)
return
}
+ oldContent := comment.Content
comment.Content = form.Body
- if err := models.UpdateComment(comment); err != nil {
+ if err := models.UpdateComment(ctx.User, comment, oldContent); err != nil {
ctx.Error(500, "UpdateComment", err)
return
}
@@ -348,7 +349,7 @@ func deleteIssueComment(ctx *context.APIContext) {
return
}
- if err = models.DeleteComment(comment); err != nil {
+ if err = models.DeleteComment(ctx.User, comment); err != nil {
ctx.Error(500, "DeleteCommentByID", err)
return
}
diff --git a/routers/api/v1/utils/hook.go b/routers/api/v1/utils/hook.go
index e1533da94c..d0538ec54f 100644
--- a/routers/api/v1/utils/hook.go
+++ b/routers/api/v1/utils/hook.go
@@ -7,12 +7,13 @@ package utils
import (
api "code.gitea.io/sdk/gitea"
+ "encoding/json"
+ "net/http"
+
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/routers/api/v1/convert"
- "encoding/json"
"github.com/Unknwon/com"
- "net/http"
)
// GetOrgHook get an organization's webhook. If there is an error, write to
@@ -98,9 +99,15 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, orgID, repoID
HookEvent: &models.HookEvent{
ChooseEvents: true,
HookEvents: models.HookEvents{
- Create: com.IsSliceContainsStr(form.Events, string(models.HookEventCreate)),
- Push: com.IsSliceContainsStr(form.Events, string(models.HookEventPush)),
- PullRequest: com.IsSliceContainsStr(form.Events, string(models.HookEventPullRequest)),
+ Create: com.IsSliceContainsStr(form.Events, string(models.HookEventCreate)),
+ Delete: com.IsSliceContainsStr(form.Events, string(models.HookEventDelete)),
+ Fork: com.IsSliceContainsStr(form.Events, string(models.HookEventFork)),
+ Issues: com.IsSliceContainsStr(form.Events, string(models.HookEventIssues)),
+ IssueComment: com.IsSliceContainsStr(form.Events, string(models.HookEventIssueComment)),
+ Push: com.IsSliceContainsStr(form.Events, string(models.HookEventPush)),
+ PullRequest: com.IsSliceContainsStr(form.Events, string(models.HookEventPullRequest)),
+ Repository: com.IsSliceContainsStr(form.Events, string(models.HookEventRepository)),
+ Release: com.IsSliceContainsStr(form.Events, string(models.HookEventRelease)),
},
},
IsActive: form.Active,
@@ -211,6 +218,16 @@ func editHook(ctx *context.APIContext, form *api.EditHookOption, w *models.Webho
w.Create = com.IsSliceContainsStr(form.Events, string(models.HookEventCreate))
w.Push = com.IsSliceContainsStr(form.Events, string(models.HookEventPush))
w.PullRequest = com.IsSliceContainsStr(form.Events, string(models.HookEventPullRequest))
+ w.Create = com.IsSliceContainsStr(form.Events, string(models.HookEventCreate))
+ w.Delete = com.IsSliceContainsStr(form.Events, string(models.HookEventDelete))
+ w.Fork = com.IsSliceContainsStr(form.Events, string(models.HookEventFork))
+ w.Issues = com.IsSliceContainsStr(form.Events, string(models.HookEventIssues))
+ w.IssueComment = com.IsSliceContainsStr(form.Events, string(models.HookEventIssueComment))
+ w.Push = com.IsSliceContainsStr(form.Events, string(models.HookEventPush))
+ w.PullRequest = com.IsSliceContainsStr(form.Events, string(models.HookEventPullRequest))
+ w.Repository = com.IsSliceContainsStr(form.Events, string(models.HookEventRepository))
+ w.Release = com.IsSliceContainsStr(form.Events, string(models.HookEventRelease))
+
if err := w.UpdateEvent(); err != nil {
ctx.Error(500, "UpdateEvent", err)
return false
diff --git a/routers/repo/issue.go b/routers/repo/issue.go
index 33ba3e0d64..18ab1691cd 100644
--- a/routers/repo/issue.go
+++ b/routers/repo/issue.go
@@ -1086,6 +1086,7 @@ func UpdateCommentContent(ctx *context.Context) {
return
}
+ oldContent := comment.Content
comment.Content = ctx.Query("content")
if len(comment.Content) == 0 {
ctx.JSON(200, map[string]interface{}{
@@ -1093,7 +1094,7 @@ func UpdateCommentContent(ctx *context.Context) {
})
return
}
- if err = models.UpdateComment(comment); err != nil {
+ if err = models.UpdateComment(ctx.User, comment, oldContent); err != nil {
ctx.ServerError("UpdateComment", err)
return
}
@@ -1119,7 +1120,7 @@ func DeleteComment(ctx *context.Context) {
return
}
- if err = models.DeleteComment(comment); err != nil {
+ if err = models.DeleteComment(ctx.User, comment); err != nil {
ctx.ServerError("DeleteCommentByID", err)
return
}
diff --git a/routers/repo/webhook.go b/routers/repo/webhook.go
index 35fdf796b5..6994aa3344 100644
--- a/routers/repo/webhook.go
+++ b/routers/repo/webhook.go
@@ -23,9 +23,9 @@ import (
)
const (
- tplHooks base.TplName = "repo/settings/hooks"
- tplHookNew base.TplName = "repo/settings/hook_new"
- tplOrgHookNew base.TplName = "org/settings/hook_new"
+ tplHooks base.TplName = "repo/settings/webhook/base"
+ tplHookNew base.TplName = "repo/settings/webhook/new"
+ tplOrgHookNew base.TplName = "org/settings/webhook/new"
)
// Webhooks render web hooks list page
@@ -118,10 +118,15 @@ func ParseHookEvent(form auth.WebhookForm) *models.HookEvent {
SendEverything: form.SendEverything(),
ChooseEvents: form.ChooseEvents(),
HookEvents: models.HookEvents{
- Create: form.Create,
- Push: form.Push,
- PullRequest: form.PullRequest,
- Repository: form.Repository,
+ Create: form.Create,
+ Delete: form.Delete,
+ Fork: form.Fork,
+ Issues: form.Issues,
+ IssueComment: form.IssueComment,
+ Release: form.Release,
+ Push: form.Push,
+ PullRequest: form.PullRequest,
+ Repository: form.Repository,
},
}
}
diff --git a/templates/repo/settings/hooks.tmpl b/templates/repo/settings/webhook/base.tmpl
similarity index 82%
rename from templates/repo/settings/hooks.tmpl
rename to templates/repo/settings/webhook/base.tmpl
index 34c5cfbb6c..6f486131f7 100644
--- a/templates/repo/settings/hooks.tmpl
+++ b/templates/repo/settings/webhook/base.tmpl
@@ -3,7 +3,7 @@
{{template "repo/header" .}}
{{template "repo/settings/navbar" .}}
- {{template "repo/settings/hook_list" .}}
+ {{template "repo/settings/webhook/list" .}}
{{template "base/footer" .}}
diff --git a/templates/repo/settings/hook_delete_modal.tmpl b/templates/repo/settings/webhook/delete_modal.tmpl
similarity index 100%
rename from templates/repo/settings/hook_delete_modal.tmpl
rename to templates/repo/settings/webhook/delete_modal.tmpl
diff --git a/templates/repo/settings/hook_dingtalk.tmpl b/templates/repo/settings/webhook/dingtalk.tmpl
similarity index 91%
rename from templates/repo/settings/hook_dingtalk.tmpl
rename to templates/repo/settings/webhook/dingtalk.tmpl
index 37271a7db5..3e6504f651 100644
--- a/templates/repo/settings/hook_dingtalk.tmpl
+++ b/templates/repo/settings/webhook/dingtalk.tmpl
@@ -6,6 +6,6 @@
- {{template "repo/settings/hook_settings" .}}
+ {{template "repo/settings/webhook/settings" .}}
{{end}}
diff --git a/templates/repo/settings/hook_discord.tmpl b/templates/repo/settings/webhook/discord.tmpl
similarity index 95%
rename from templates/repo/settings/hook_discord.tmpl
rename to templates/repo/settings/webhook/discord.tmpl
index 901e7e6311..75c31efb51 100644
--- a/templates/repo/settings/hook_discord.tmpl
+++ b/templates/repo/settings/webhook/discord.tmpl
@@ -14,6 +14,6 @@
- {{template "repo/settings/hook_settings" .}}
+ {{template "repo/settings/webhook/settings" .}}
{{end}}
diff --git a/templates/repo/settings/hook_gitea.tmpl b/templates/repo/settings/webhook/gitea.tmpl
similarity index 94%
rename from templates/repo/settings/hook_gitea.tmpl
rename to templates/repo/settings/webhook/gitea.tmpl
index fc5e35e068..87a8813d0e 100644
--- a/templates/repo/settings/hook_gitea.tmpl
+++ b/templates/repo/settings/webhook/gitea.tmpl
@@ -23,6 +23,6 @@
- {{template "repo/settings/hook_settings" .}}
+ {{template "repo/settings/webhook/settings" .}}
{{end}}
diff --git a/templates/repo/settings/hook_gogs.tmpl b/templates/repo/settings/webhook/gogs.tmpl
similarity index 96%
rename from templates/repo/settings/hook_gogs.tmpl
rename to templates/repo/settings/webhook/gogs.tmpl
index 28098d14ec..649fb54aea 100644
--- a/templates/repo/settings/hook_gogs.tmpl
+++ b/templates/repo/settings/webhook/gogs.tmpl
@@ -23,6 +23,6 @@
- {{template "repo/settings/hook_settings" .}}
+ {{template "repo/settings/webhook/settings" .}}
{{end}}
diff --git a/templates/repo/settings/hook_history.tmpl b/templates/repo/settings/webhook/history.tmpl
similarity index 100%
rename from templates/repo/settings/hook_history.tmpl
rename to templates/repo/settings/webhook/history.tmpl
diff --git a/templates/repo/settings/hook_list.tmpl b/templates/repo/settings/webhook/list.tmpl
similarity index 97%
rename from templates/repo/settings/hook_list.tmpl
rename to templates/repo/settings/webhook/list.tmpl
index 4e61ba7a07..de6bd2c5f2 100644
--- a/templates/repo/settings/hook_list.tmpl
+++ b/templates/repo/settings/webhook/list.tmpl
@@ -48,4 +48,4 @@
-{{template "repo/settings/hook_delete_modal" .}}
+{{template "repo/settings/webhook/delete_modal" .}}
diff --git a/templates/repo/settings/hook_new.tmpl b/templates/repo/settings/webhook/new.tmpl
similarity index 77%
rename from templates/repo/settings/hook_new.tmpl
rename to templates/repo/settings/webhook/new.tmpl
index 7e3cf3c8cf..1b3d114577 100644
--- a/templates/repo/settings/hook_new.tmpl
+++ b/templates/repo/settings/webhook/new.tmpl
@@ -21,14 +21,14 @@
- {{template "repo/settings/hook_gitea" .}}
- {{template "repo/settings/hook_gogs" .}}
- {{template "repo/settings/hook_slack" .}}
- {{template "repo/settings/hook_discord" .}}
- {{template "repo/settings/hook_dingtalk" .}}
+ {{template "repo/settings/webhook/gitea" .}}
+ {{template "repo/settings/webhook/gogs" .}}
+ {{template "repo/settings/webhook/slack" .}}
+ {{template "repo/settings/webhook/discord" .}}
+ {{template "repo/settings/webhook/dingtalk" .}}
- {{template "repo/settings/hook_history" .}}
+ {{template "repo/settings/webhook/history" .}}
{{template "base/footer" .}}
diff --git a/templates/repo/settings/hook_settings.tmpl b/templates/repo/settings/webhook/settings.tmpl
similarity index 63%
rename from templates/repo/settings/hook_settings.tmpl
rename to templates/repo/settings/webhook/settings.tmpl
index 7f3406588f..f04c25a0a3 100644
--- a/templates/repo/settings/hook_settings.tmpl
+++ b/templates/repo/settings/webhook/settings.tmpl
@@ -32,6 +32,26 @@
+
+
+
+
+
+
+ {{.i18n.Tr "repo.settings.event_delete_desc"}}
+
+
+
+
+
+
+
+
+
+ {{.i18n.Tr "repo.settings.event_fork_desc"}}
+
+
+
+
+
+
+
+
+
+ {{.i18n.Tr "repo.settings.event_issues_desc"}}
+
+
+
+
+
+
+
+
+
+ {{.i18n.Tr "repo.settings.event_issue_comment_desc"}}
+
+
+
+
+
+
+
+
+
+ {{.i18n.Tr "repo.settings.event_release_desc"}}
+
+
+
@@ -83,4 +133,4 @@
{{end}}
-{{template "repo/settings/hook_delete_modal" .}}
+{{template "repo/settings/webhook/delete_modal" .}}
diff --git a/templates/repo/settings/hook_slack.tmpl b/templates/repo/settings/webhook/slack.tmpl
similarity index 96%
rename from templates/repo/settings/hook_slack.tmpl
rename to templates/repo/settings/webhook/slack.tmpl
index 16e1859470..c35a679da7 100644
--- a/templates/repo/settings/hook_slack.tmpl
+++ b/templates/repo/settings/webhook/slack.tmpl
@@ -23,6 +23,6 @@
- {{template "repo/settings/hook_settings" .}}
+ {{template "repo/settings/webhook/settings" .}}
{{end}}
diff --git a/vendor/code.gitea.io/sdk/gitea/hook.go b/vendor/code.gitea.io/sdk/gitea/hook.go
index a9b0bdbd06..85d99652dc 100644
--- a/vendor/code.gitea.io/sdk/gitea/hook.go
+++ b/vendor/code.gitea.io/sdk/gitea/hook.go
@@ -172,9 +172,14 @@ type PayloadCommitVerification struct {
var (
_ Payloader = &CreatePayload{}
+ _ Payloader = &DeletePayload{}
+ _ Payloader = &ForkPayload{}
_ Payloader = &PushPayload{}
_ Payloader = &IssuePayload{}
+ _ Payloader = &IssueCommentPayload{}
_ Payloader = &PullRequestPayload{}
+ _ Payloader = &RepositoryPayload{}
+ _ Payloader = &ReleasePayload{}
)
// _________ __
@@ -224,6 +229,123 @@ func ParseCreateHook(raw []byte) (*CreatePayload, error) {
return hook, nil
}
+// ________ .__ __
+// \______ \ ____ | | _____/ |_ ____
+// | | \_/ __ \| | _/ __ \ __\/ __ \
+// | ` \ ___/| |_\ ___/| | \ ___/
+// /_______ /\___ >____/\___ >__| \___ >
+// \/ \/ \/ \/
+
+// PusherType define the type to push
+type PusherType string
+
+// describe all the PusherTypes
+const (
+ PusherTypeUser PusherType = "user"
+)
+
+// DeletePayload represents delete payload
+type DeletePayload struct {
+ Ref string `json:"ref"`
+ RefType string `json:"ref_type"`
+ PusherType PusherType `json:"pusher_type"`
+ Repo *Repository `json:"repository"`
+ Sender *User `json:"sender"`
+}
+
+// SetSecret implements Payload
+func (p *DeletePayload) SetSecret(secret string) {
+}
+
+// JSONPayload implements Payload
+func (p *DeletePayload) JSONPayload() ([]byte, error) {
+ return json.MarshalIndent(p, "", " ")
+}
+
+// ___________ __
+// \_ _____/__________| | __
+// | __)/ _ \_ __ \ |/ /
+// | \( <_> ) | \/ <
+// \___ / \____/|__| |__|_ \
+// \/ \/
+
+// ForkPayload represents fork payload
+type ForkPayload struct {
+ Forkee *Repository `json:"forkee"`
+ Repo *Repository `json:"repository"`
+ Sender *User `json:"sender"`
+}
+
+// SetSecret implements Payload
+func (p *ForkPayload) SetSecret(secret string) {
+}
+
+// JSONPayload implements Payload
+func (p *ForkPayload) JSONPayload() ([]byte, error) {
+ return json.MarshalIndent(p, "", " ")
+}
+
+// HookIssueCommentAction defines hook issue comment action
+type HookIssueCommentAction string
+
+// all issue comment actions
+const (
+ HookIssueCommentCreated HookIssueCommentAction = "created"
+ HookIssueCommentEdited HookIssueCommentAction = "edited"
+ HookIssueCommentDeleted HookIssueCommentAction = "deleted"
+)
+
+// IssueCommentPayload represents a payload information of issue comment event.
+type IssueCommentPayload struct {
+ Action HookIssueCommentAction `json:"action"`
+ Issue *Issue `json:"issue"`
+ Comment *Comment `json:"comment"`
+ Changes *ChangesPayload `json:"changes,omitempty"`
+ Repository *Repository `json:"repository"`
+ Sender *User `json:"sender"`
+}
+
+// SetSecret implements Payload
+func (p *IssueCommentPayload) SetSecret(secret string) {
+}
+
+// JSONPayload implements Payload
+func (p *IssueCommentPayload) JSONPayload() ([]byte, error) {
+ return json.MarshalIndent(p, "", " ")
+}
+
+// __________ .__
+// \______ \ ____ | | ____ _____ ______ ____
+// | _// __ \| | _/ __ \\__ \ / ___// __ \
+// | | \ ___/| |_\ ___/ / __ \_\___ \\ ___/
+// |____|_ /\___ >____/\___ >____ /____ >\___ >
+// \/ \/ \/ \/ \/ \/
+
+// HookReleaseAction defines hook release action type
+type HookReleaseAction string
+
+// all release actions
+const (
+ HookReleasePublished HookReleaseAction = "published"
+)
+
+// ReleasePayload represents a payload information of release event.
+type ReleasePayload struct {
+ Action HookReleaseAction `json:"action"`
+ Release *Release `json:"release"`
+ Repository *Repository `json:"repository"`
+ Sender *User `json:"sender"`
+}
+
+// SetSecret implements Payload
+func (p *ReleasePayload) SetSecret(secret string) {
+}
+
+// JSONPayload implements Payload
+func (p *ReleasePayload) JSONPayload() ([]byte, error) {
+ return json.MarshalIndent(p, "", " ")
+}
+
// __________ .__
// \______ \__ __ _____| |__
// | ___/ | \/ ___/ | \
diff --git a/vendor/code.gitea.io/sdk/gitea/issue.go b/vendor/code.gitea.io/sdk/gitea/issue.go
index 27809ca3b4..fee7cd6f9f 100644
--- a/vendor/code.gitea.io/sdk/gitea/issue.go
+++ b/vendor/code.gitea.io/sdk/gitea/issue.go
@@ -118,14 +118,14 @@ func (c *Client) CreateIssue(owner, repo string, opt CreateIssueOption) (*Issue,
// EditIssueOption options for editing an issue
type EditIssueOption struct {
- Title string `json:"title"`
- Body *string `json:"body"`
- Assignee *string `json:"assignee"`
- Assignees []string `json:"assignees"`
- Milestone *int64 `json:"milestone"`
- State *string `json:"state"`
+ Title string `json:"title"`
+ Body *string `json:"body"`
+ Assignee *string `json:"assignee"`
+ Assignees []string `json:"assignees"`
+ Milestone *int64 `json:"milestone"`
+ State *string `json:"state"`
// swagger:strfmt date-time
- Deadline *time.Time `json:"due_date"`
+ Deadline *time.Time `json:"due_date"`
}
// EditIssue modify an existing issue for a given repository
@@ -138,3 +138,17 @@ func (c *Client) EditIssue(owner, repo string, index int64, opt EditIssueOption)
return issue, c.getParsedResponse("PATCH", fmt.Sprintf("/repos/%s/%s/issues/%d", owner, repo, index),
jsonHeader, bytes.NewReader(body), issue)
}
+
+// EditDeadlineOption options for creating a deadline
+type EditDeadlineOption struct {
+ // required:true
+ // swagger:strfmt date-time
+ Deadline *time.Time `json:"due_date"`
+}
+
+// IssueDeadline represents an issue deadline
+// swagger:model
+type IssueDeadline struct {
+ // swagger:strfmt date-time
+ Deadline *time.Time `json:"due_date"`
+}
diff --git a/vendor/code.gitea.io/sdk/gitea/pull.go b/vendor/code.gitea.io/sdk/gitea/pull.go
index 7d38b14d7d..6fcdd1d41b 100644
--- a/vendor/code.gitea.io/sdk/gitea/pull.go
+++ b/vendor/code.gitea.io/sdk/gitea/pull.go
@@ -85,16 +85,16 @@ func (c *Client) GetPullRequest(owner, repo string, index int64) (*PullRequest,
// CreatePullRequestOption options when creating a pull request
type CreatePullRequestOption struct {
- Head string `json:"head" binding:"Required"`
- Base string `json:"base" binding:"Required"`
- Title string `json:"title" binding:"Required"`
- Body string `json:"body"`
- Assignee string `json:"assignee"`
- Assignees []string `json:"assignees"`
- Milestone int64 `json:"milestone"`
- Labels []int64 `json:"labels"`
+ Head string `json:"head" binding:"Required"`
+ Base string `json:"base" binding:"Required"`
+ Title string `json:"title" binding:"Required"`
+ Body string `json:"body"`
+ Assignee string `json:"assignee"`
+ Assignees []string `json:"assignees"`
+ Milestone int64 `json:"milestone"`
+ Labels []int64 `json:"labels"`
// swagger:strfmt date-time
- Deadline *time.Time `json:"due_date"`
+ Deadline *time.Time `json:"due_date"`
}
// CreatePullRequest create pull request with options
@@ -110,15 +110,15 @@ func (c *Client) CreatePullRequest(owner, repo string, opt CreatePullRequestOpti
// EditPullRequestOption options when modify pull request
type EditPullRequestOption struct {
- Title string `json:"title"`
- Body string `json:"body"`
- Assignee string `json:"assignee"`
- Assignees []string `json:"assignees"`
- Milestone int64 `json:"milestone"`
- Labels []int64 `json:"labels"`
- State *string `json:"state"`
+ Title string `json:"title"`
+ Body string `json:"body"`
+ Assignee string `json:"assignee"`
+ Assignees []string `json:"assignees"`
+ Milestone int64 `json:"milestone"`
+ Labels []int64 `json:"labels"`
+ State *string `json:"state"`
// swagger:strfmt date-time
- Deadline *time.Time `json:"due_date"`
+ Deadline *time.Time `json:"due_date"`
}
// EditPullRequest modify pull request with PR id and options
diff --git a/vendor/vendor.json b/vendor/vendor.json
index 8b8972b16f..712706b96e 100644
--- a/vendor/vendor.json
+++ b/vendor/vendor.json
@@ -9,10 +9,10 @@
"revisionTime": "2018-04-21T01:08:19Z"
},
{
- "checksumSHA1": "WMD6+Qh2+5hd9uiq910pF/Ihylw=",
+ "checksumSHA1": "LnxY/6xD4h9dCCJ5nxKEfZZs1Vk=",
"path": "code.gitea.io/sdk/gitea",
- "revision": "1c8d12f79a51605ed91587aa6b86cf38fc0f987f",
- "revisionTime": "2018-05-01T11:15:19Z"
+ "revision": "7fa627fa5d67d18c39d6dd3c6c4db836916bf234",
+ "revisionTime": "2018-05-10T12:54:05Z"
},
{
"checksumSHA1": "bOODD4Gbw3GfcuQPU2dI40crxxk=",