forked from gitea/gitea
		
	new create webhook event
This commit is contained in:
		
							parent
							
								
									a541ca16b6
								
							
						
					
					
						commit
						f509c59ac1
					
				| @ -531,6 +531,12 @@ settings.content_type = Content Type | ||||
| settings.secret = Secret | ||||
| settings.event_desc = Upon which events should this webhook be triggered? | ||||
| settings.event_push_only = Just the <code>push</code> event. | ||||
| settings.event_send_everything = I need <strong>everything</strong>. | ||||
| settings.event_choose = Let me choose what I need. | ||||
| settings.event_create = Create | ||||
| settings.event_create_desc = Branch, or tag created | ||||
| settings.event_push = Push | ||||
| settings.event_push_desc = Git push to a repository | ||||
| settings.active = Active | ||||
| settings.active_helper = Details regarding the event which triggered the hook will be delivered as well. | ||||
| settings.add_hook_success = New webhook has been added. | ||||
|  | ||||
							
								
								
									
										229
									
								
								models/action.go
									
									
									
									
									
								
							
							
						
						
									
										229
									
								
								models/action.go
									
									
									
									
									
								
							| @ -16,6 +16,8 @@ import ( | ||||
| 
 | ||||
| 	"github.com/go-xorm/xorm" | ||||
| 
 | ||||
| 	api "github.com/gogits/go-gogs-client" | ||||
| 
 | ||||
| 	"github.com/gogits/gogs/modules/base" | ||||
| 	"github.com/gogits/gogs/modules/git" | ||||
| 	"github.com/gogits/gogs/modules/log" | ||||
| @ -290,20 +292,50 @@ func updateIssuesCommit(u *User, repo *Repository, repoUserName, repoName string | ||||
| } | ||||
| 
 | ||||
| // CommitRepoAction adds new action for committing repository. | ||||
| func CommitRepoAction(userID, repoUserID int64, userName, actEmail string, | ||||
| 	repoID int64, repoUserName, repoName string, refFullName string, commit *base.PushCommits, oldCommitID string, newCommitID string) error { | ||||
| func CommitRepoAction( | ||||
| 	userID, repoUserID int64, | ||||
| 	userName, actEmail string, | ||||
| 	repoID int64, | ||||
| 	repoUserName, repoName string, | ||||
| 	refFullName string, | ||||
| 	commit *base.PushCommits, | ||||
| 	oldCommitID string, newCommitID string) error { | ||||
| 
 | ||||
| 	u, err := GetUserByID(userID) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("GetUserByID: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	repo, err := GetRepositoryByName(repoUserID, repoName) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("GetRepositoryByName: %v", err) | ||||
| 	} else if err = repo.GetOwner(); err != nil { | ||||
| 		return fmt.Errorf("GetOwner: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	isNewBranch := false | ||||
| 	opType := COMMIT_REPO | ||||
| 	// Check it's tag push or branch. | ||||
| 	if strings.HasPrefix(refFullName, "refs/tags/") { | ||||
| 		opType = PUSH_TAG | ||||
| 		commit = &base.PushCommits{} | ||||
| 	} | ||||
| 	} else { | ||||
| 		// if not the first commit, set the compareUrl | ||||
| 		if !strings.HasPrefix(oldCommitID, "0000000") { | ||||
| 			commit.CompareUrl = fmt.Sprintf("%s/%s/compare/%s...%s", repoUserName, repoName, oldCommitID, newCommitID) | ||||
| 		} else { | ||||
| 			isNewBranch = true | ||||
| 		} | ||||
| 
 | ||||
| 	repoLink := fmt.Sprintf("%s%s/%s", setting.AppUrl, repoUserName, repoName) | ||||
| 	// if not the first commit, set the compareUrl | ||||
| 	if !strings.HasPrefix(oldCommitID, "0000000") { | ||||
| 		commit.CompareUrl = fmt.Sprintf("%s/%s/compare/%s...%s", repoUserName, repoName, oldCommitID, newCommitID) | ||||
| 		// Change repository bare status and update last updated time. | ||||
| 		repo.IsBare = false | ||||
| 		if err = UpdateRepository(repo, false); err != nil { | ||||
| 			return fmt.Errorf("UpdateRepository: %v", err) | ||||
| 		} | ||||
| 
 | ||||
| 		if err = updateIssuesCommit(u, repo, repoUserName, repoName, commit.Commits); err != nil { | ||||
| 			log.Debug("updateIssuesCommit: %v", err) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	bs, err := json.Marshal(commit) | ||||
| @ -313,26 +345,6 @@ func CommitRepoAction(userID, repoUserID int64, userName, actEmail string, | ||||
| 
 | ||||
| 	refName := git.RefEndName(refFullName) | ||||
| 
 | ||||
| 	// Change repository bare status and update last updated time. | ||||
| 	repo, err := GetRepositoryByName(repoUserID, repoName) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("GetRepositoryByName: %v", err) | ||||
| 	} | ||||
| 	repo.IsBare = false | ||||
| 	if err = UpdateRepository(repo, false); err != nil { | ||||
| 		return fmt.Errorf("UpdateRepository: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	u, err := GetUserByID(userID) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("GetUserByID: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	err = updateIssuesCommit(u, repo, repoUserName, repoName, commit.Commits) | ||||
| 	if err != nil { | ||||
| 		log.Debug("updateIssuesCommit: ", err) | ||||
| 	} | ||||
| 
 | ||||
| 	if err = NotifyWatchers(&Action{ | ||||
| 		ActUserID:    u.Id, | ||||
| 		ActUserName:  userName, | ||||
| @ -345,32 +357,24 @@ func CommitRepoAction(userID, repoUserID int64, userName, actEmail string, | ||||
| 		RefName:      refName, | ||||
| 		IsPrivate:    repo.IsPrivate, | ||||
| 	}); err != nil { | ||||
| 		return errors.New("NotifyWatchers: " + err.Error()) | ||||
| 		return fmt.Errorf("NotifyWatchers: %v", err) | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	// New push event hook. | ||||
| 	if err := repo.GetOwner(); err != nil { | ||||
| 		return errors.New("GetOwner: " + err.Error()) | ||||
| 	} | ||||
| 
 | ||||
| 	ws, err := GetActiveWebhooksByRepoId(repo.ID) | ||||
| 	if err != nil { | ||||
| 		return errors.New("GetActiveWebhooksByRepoId: " + err.Error()) | ||||
| 	} | ||||
| 
 | ||||
| 	// check if repo belongs to org and append additional webhooks | ||||
| 	if repo.Owner.IsOrganization() { | ||||
| 		// get hooks for org | ||||
| 		orgws, err := GetActiveWebhooksByOrgId(repo.OwnerID) | ||||
| 		if err != nil { | ||||
| 			return errors.New("GetActiveWebhooksByOrgId: " + err.Error()) | ||||
| 		} | ||||
| 		ws = append(ws, orgws...) | ||||
| 	} | ||||
| 
 | ||||
| 	if len(ws) == 0 { | ||||
| 		return nil | ||||
| 	repoLink := fmt.Sprintf("%s%s/%s", setting.AppUrl, repoUserName, repoName) | ||||
| 	payloadRepo := &api.PayloadRepo{ | ||||
| 		ID:          repo.ID, | ||||
| 		Name:        repo.LowerName, | ||||
| 		URL:         repoLink, | ||||
| 		Description: repo.Description, | ||||
| 		Website:     repo.Website, | ||||
| 		Watchers:    repo.NumWatches, | ||||
| 		Owner: &api.PayloadAuthor{ | ||||
| 			Name:     repo.Owner.DisplayName(), | ||||
| 			Email:    repo.Owner.Email, | ||||
| 			UserName: repo.Owner.Name, | ||||
| 		}, | ||||
| 		Private: repo.IsPrivate, | ||||
| 	} | ||||
| 
 | ||||
| 	pusher_email, pusher_name := "", "" | ||||
| @ -379,83 +383,66 @@ func CommitRepoAction(userID, repoUserID int64, userName, actEmail string, | ||||
| 		pusher_email = pusher.Email | ||||
| 		pusher_name = pusher.DisplayName() | ||||
| 	} | ||||
| 
 | ||||
| 	commits := make([]*PayloadCommit, len(commit.Commits)) | ||||
| 	for i, cmt := range commit.Commits { | ||||
| 		author_username := "" | ||||
| 		author, err := GetUserByEmail(cmt.AuthorEmail) | ||||
| 		if err == nil { | ||||
| 			author_username = author.Name | ||||
| 		} | ||||
| 		commits[i] = &PayloadCommit{ | ||||
| 			Id:      cmt.Sha1, | ||||
| 			Message: cmt.Message, | ||||
| 			Url:     fmt.Sprintf("%s/commit/%s", repoLink, cmt.Sha1), | ||||
| 			Author: &PayloadAuthor{ | ||||
| 				Name:     cmt.AuthorName, | ||||
| 				Email:    cmt.AuthorEmail, | ||||
| 				UserName: author_username, | ||||
| 			}, | ||||
| 		} | ||||
| 	} | ||||
| 	p := &Payload{ | ||||
| 		Ref:     refFullName, | ||||
| 		Commits: commits, | ||||
| 		Repo: &PayloadRepo{ | ||||
| 			Id:          repo.ID, | ||||
| 			Name:        repo.LowerName, | ||||
| 			Url:         repoLink, | ||||
| 			Description: repo.Description, | ||||
| 			Website:     repo.Website, | ||||
| 			Watchers:    repo.NumWatches, | ||||
| 			Owner: &PayloadAuthor{ | ||||
| 				Name:     repo.Owner.DisplayName(), | ||||
| 				Email:    repo.Owner.Email, | ||||
| 				UserName: repo.Owner.Name, | ||||
| 			}, | ||||
| 			Private: repo.IsPrivate, | ||||
| 		}, | ||||
| 		Pusher: &PayloadAuthor{ | ||||
| 			Name:     pusher_name, | ||||
| 			Email:    pusher_email, | ||||
| 			UserName: userName, | ||||
| 		}, | ||||
| 		Before:     oldCommitID, | ||||
| 		After:      newCommitID, | ||||
| 		CompareUrl: setting.AppUrl + commit.CompareUrl, | ||||
| 	payloadSender := &api.PayloadUser{ | ||||
| 		UserName:  pusher.Name, | ||||
| 		ID:        pusher.Id, | ||||
| 		AvatarUrl: setting.AppUrl + pusher.RelAvatarLink(), | ||||
| 	} | ||||
| 
 | ||||
| 	for _, w := range ws { | ||||
| 		w.GetEvent() | ||||
| 		if !w.HasPushEvent() { | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		var payload BasePayload | ||||
| 		switch w.HookTaskType { | ||||
| 		case SLACK: | ||||
| 			s, err := GetSlackPayload(p, w.Meta) | ||||
| 			if err != nil { | ||||
| 				return errors.New("action.GetSlackPayload: " + err.Error()) | ||||
| 	switch opType { | ||||
| 	case COMMIT_REPO: // Push | ||||
| 		commits := make([]*api.PayloadCommit, len(commit.Commits)) | ||||
| 		for i, cmt := range commit.Commits { | ||||
| 			author_username := "" | ||||
| 			author, err := GetUserByEmail(cmt.AuthorEmail) | ||||
| 			if err == nil { | ||||
| 				author_username = author.Name | ||||
| 			} | ||||
| 			payload = s | ||||
| 		default: | ||||
| 			payload = p | ||||
| 			p.Secret = w.Secret | ||||
| 			commits[i] = &api.PayloadCommit{ | ||||
| 				ID:      cmt.Sha1, | ||||
| 				Message: cmt.Message, | ||||
| 				URL:     fmt.Sprintf("%s/commit/%s", repoLink, cmt.Sha1), | ||||
| 				Author: &api.PayloadAuthor{ | ||||
| 					Name:     cmt.AuthorName, | ||||
| 					Email:    cmt.AuthorEmail, | ||||
| 					UserName: author_username, | ||||
| 				}, | ||||
| 			} | ||||
| 		} | ||||
| 		p := &api.PushPayload{ | ||||
| 			Ref:        refFullName, | ||||
| 			Before:     oldCommitID, | ||||
| 			After:      newCommitID, | ||||
| 			CompareUrl: setting.AppUrl + commit.CompareUrl, | ||||
| 			Commits:    commits, | ||||
| 			Repo:       payloadRepo, | ||||
| 			Pusher: &api.PayloadAuthor{ | ||||
| 				Name:     pusher_name, | ||||
| 				Email:    pusher_email, | ||||
| 				UserName: userName, | ||||
| 			}, | ||||
| 			Sender: payloadSender, | ||||
| 		} | ||||
| 		if err = PrepareWebhooks(repo, HOOK_EVENT_PUSH, p); err != nil { | ||||
| 			return fmt.Errorf("PrepareWebhooks: %v", err) | ||||
| 		} | ||||
| 
 | ||||
| 		if err = CreateHookTask(&HookTask{ | ||||
| 			RepoID:      repo.ID, | ||||
| 			HookID:      w.ID, | ||||
| 			Type:        w.HookTaskType, | ||||
| 			URL:         w.URL, | ||||
| 			BasePayload: payload, | ||||
| 			ContentType: w.ContentType, | ||||
| 			EventType:   HOOK_EVENT_PUSH, | ||||
| 			IsSSL:       w.IsSSL, | ||||
| 		}); err != nil { | ||||
| 			return fmt.Errorf("CreateHookTask: %v", err) | ||||
| 		if isNewBranch { | ||||
| 			return PrepareWebhooks(repo, HOOK_EVENT_CREATE, &api.CreatePayload{ | ||||
| 				Ref:     refName, | ||||
| 				RefType: "branch", | ||||
| 				Repo:    payloadRepo, | ||||
| 				Sender:  payloadSender, | ||||
| 			}) | ||||
| 		} | ||||
| 
 | ||||
| 	case PUSH_TAG: // Create | ||||
| 		return PrepareWebhooks(repo, HOOK_EVENT_CREATE, &api.CreatePayload{ | ||||
| 			Ref:     refName, | ||||
| 			RefType: "tag", | ||||
| 			Repo:    payloadRepo, | ||||
| 			Sender:  payloadSender, | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
|  | ||||
| @ -122,9 +122,8 @@ func (u *User) HomeLink() string { | ||||
| 	return setting.AppSubUrl + "/" + u.Name | ||||
| } | ||||
| 
 | ||||
| // AvatarLink returns user gravatar link. | ||||
| func (u *User) AvatarLink() string { | ||||
| 	defaultImgUrl := setting.AppSubUrl + "/img/avatar_default.jpg" | ||||
| func (u *User) RelAvatarLink() string { | ||||
| 	defaultImgUrl := "/img/avatar_default.jpg" | ||||
| 	if u.Id == -1 { | ||||
| 		return defaultImgUrl | ||||
| 	} | ||||
| @ -135,7 +134,7 @@ func (u *User) AvatarLink() string { | ||||
| 		if !com.IsExist(imgPath) { | ||||
| 			return defaultImgUrl | ||||
| 		} | ||||
| 		return setting.AppSubUrl + "/avatars/" + com.ToStr(u.Id) | ||||
| 		return "/avatars/" + com.ToStr(u.Id) | ||||
| 	case setting.DisableGravatar, setting.OfflineMode: | ||||
| 		if !com.IsExist(imgPath) { | ||||
| 			img, err := avatar.RandomImage([]byte(u.Email)) | ||||
| @ -161,13 +160,22 @@ func (u *User) AvatarLink() string { | ||||
| 			log.Info("New random avatar created: %d", u.Id) | ||||
| 		} | ||||
| 
 | ||||
| 		return setting.AppSubUrl + "/avatars/" + com.ToStr(u.Id) | ||||
| 		return "/avatars/" + com.ToStr(u.Id) | ||||
| 	case setting.Service.EnableCacheAvatar: | ||||
| 		return setting.AppSubUrl + "/avatar/" + u.Avatar | ||||
| 		return "/avatar/" + u.Avatar | ||||
| 	} | ||||
| 	return setting.GravatarSource + u.Avatar | ||||
| } | ||||
| 
 | ||||
| // AvatarLink returns user gravatar link. | ||||
| func (u *User) AvatarLink() string { | ||||
| 	link := u.RelAvatarLink() | ||||
| 	if link[0] == '/' { | ||||
| 		return setting.AppSubUrl + link | ||||
| 	} | ||||
| 	return link | ||||
| } | ||||
| 
 | ||||
| // NewGitSig generates and returns the signature of given user. | ||||
| func (u *User) NewGitSig() *git.Signature { | ||||
| 	return &git.Signature{ | ||||
|  | ||||
| @ -15,6 +15,8 @@ import ( | ||||
| 
 | ||||
| 	"github.com/go-xorm/xorm" | ||||
| 
 | ||||
| 	api "github.com/gogits/go-gogs-client" | ||||
| 
 | ||||
| 	"github.com/gogits/gogs/modules/httplib" | ||||
| 	"github.com/gogits/gogs/modules/log" | ||||
| 	"github.com/gogits/gogs/modules/setting" | ||||
| @ -54,9 +56,18 @@ func IsValidHookContentType(name string) bool { | ||||
| 	return ok | ||||
| } | ||||
| 
 | ||||
| type HookEvents struct { | ||||
| 	Create bool `json:"create"` | ||||
| 	Push   bool `json:"push"` | ||||
| } | ||||
| 
 | ||||
| // HookEvent represents events that will delivery hook. | ||||
| type HookEvent struct { | ||||
| 	PushOnly bool `json:"push_only"` | ||||
| 	PushOnly       bool `json:"push_only"` | ||||
| 	SendEverything bool `json:"send_everything"` | ||||
| 	ChooseEvents   bool `json:"choose_events"` | ||||
| 
 | ||||
| 	HookEvents `json:"events"` | ||||
| } | ||||
| 
 | ||||
| type HookStatus int | ||||
| @ -94,8 +105,8 @@ func (w *Webhook) GetEvent() { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (w *Webhook) GetSlackHook() *Slack { | ||||
| 	s := &Slack{} | ||||
| func (w *Webhook) GetSlackHook() *SlackMeta { | ||||
| 	s := &SlackMeta{} | ||||
| 	if err := json.Unmarshal([]byte(w.Meta), s); err != nil { | ||||
| 		log.Error(4, "webhook.GetSlackHook(%d): %v", w.ID, err) | ||||
| 	} | ||||
| @ -114,12 +125,16 @@ func (w *Webhook) UpdateEvent() error { | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| // HasCreateEvent returns true if hook enabled create event. | ||||
| func (w *Webhook) HasCreateEvent() bool { | ||||
| 	return w.SendEverything || | ||||
| 		(w.ChooseEvents && w.HookEvents.Create) | ||||
| } | ||||
| 
 | ||||
| // HasPushEvent returns true if hook enabled push event. | ||||
| func (w *Webhook) HasPushEvent() bool { | ||||
| 	if w.PushOnly { | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| 	return w.PushOnly || w.SendEverything || | ||||
| 		(w.ChooseEvents && w.HookEvents.Push) | ||||
| } | ||||
| 
 | ||||
| // CreateWebhook creates a new web hook. | ||||
| @ -140,9 +155,9 @@ func GetWebhookByID(id int64) (*Webhook, error) { | ||||
| 	return w, nil | ||||
| } | ||||
| 
 | ||||
| // GetActiveWebhooksByRepoId returns all active webhooks of repository. | ||||
| func GetActiveWebhooksByRepoId(repoId int64) (ws []*Webhook, err error) { | ||||
| 	err = x.Where("repo_id=?", repoId).And("is_active=?", true).Find(&ws) | ||||
| // GetActiveWebhooksByRepoID returns all active webhooks of repository. | ||||
| func GetActiveWebhooksByRepoID(repoID int64) (ws []*Webhook, err error) { | ||||
| 	err = x.Where("repo_id=?", repoID).And("is_active=?", true).Find(&ws) | ||||
| 	return ws, err | ||||
| } | ||||
| 
 | ||||
| @ -181,9 +196,9 @@ func GetWebhooksByOrgId(orgID int64) (ws []*Webhook, err error) { | ||||
| 	return ws, err | ||||
| } | ||||
| 
 | ||||
| // GetActiveWebhooksByOrgId returns all active webhooks for an organization. | ||||
| func GetActiveWebhooksByOrgId(orgId int64) (ws []*Webhook, err error) { | ||||
| 	err = x.Where("org_id=?", orgId).And("is_active=?", true).Find(&ws) | ||||
| // GetActiveWebhooksByOrgID returns all active webhooks for an organization. | ||||
| func GetActiveWebhooksByOrgID(orgID int64) (ws []*Webhook, err error) { | ||||
| 	err = x.Where("org_id=?", orgID).And("is_active=?", true).Find(&ws) | ||||
| 	return ws, err | ||||
| } | ||||
| 
 | ||||
| @ -230,58 +245,10 @@ func IsValidHookTaskType(name string) bool { | ||||
| type HookEventType string | ||||
| 
 | ||||
| const ( | ||||
| 	HOOK_EVENT_PUSH HookEventType = "push" | ||||
| 	HOOK_EVENT_CREATE HookEventType = "create" | ||||
| 	HOOK_EVENT_PUSH   HookEventType = "push" | ||||
| ) | ||||
| 
 | ||||
| // FIXME: just use go-gogs-client structs maybe? | ||||
| type PayloadAuthor struct { | ||||
| 	Name     string `json:"name"` | ||||
| 	Email    string `json:"email"` | ||||
| 	UserName string `json:"username"` | ||||
| } | ||||
| 
 | ||||
| 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:"owner"` | ||||
| 	Private     bool           `json:"private"` | ||||
| } | ||||
| 
 | ||||
| type BasePayload interface { | ||||
| 	GetJSONPayload() ([]byte, error) | ||||
| } | ||||
| 
 | ||||
| // 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"` | ||||
| 	Before     string           `json:"before"` | ||||
| 	After      string           `json:"after"` | ||||
| 	CompareUrl string           `json:"compare_url"` | ||||
| } | ||||
| 
 | ||||
| func (p Payload) GetJSONPayload() ([]byte, error) { | ||||
| 	data, err := json.MarshalIndent(p, "", "  ") | ||||
| 	if err != nil { | ||||
| 		return []byte{}, err | ||||
| 	} | ||||
| 	return data, nil | ||||
| } | ||||
| 
 | ||||
| // HookRequest represents hook task request information. | ||||
| type HookRequest struct { | ||||
| 	Headers map[string]string `json:"headers"` | ||||
| @ -302,7 +269,7 @@ type HookTask struct { | ||||
| 	UUID            string | ||||
| 	Type            HookTaskType | ||||
| 	URL             string | ||||
| 	BasePayload     `xorm:"-"` | ||||
| 	api.Payloader   `xorm:"-"` | ||||
| 	PayloadContent  string `xorm:"TEXT"` | ||||
| 	ContentType     HookContentType | ||||
| 	EventType       HookEventType | ||||
| @ -367,13 +334,13 @@ func (t *HookTask) MarshalJSON(v interface{}) string { | ||||
| // HookTasks returns a list of hook tasks by given conditions. | ||||
| func HookTasks(hookID int64, page int) ([]*HookTask, error) { | ||||
| 	tasks := make([]*HookTask, 0, setting.Webhook.PagingNum) | ||||
| 	return tasks, x.Limit(setting.Webhook.PagingNum, (page-1)*setting.Webhook.PagingNum).Desc("id").Find(&tasks) | ||||
| 	return tasks, x.Limit(setting.Webhook.PagingNum, (page-1)*setting.Webhook.PagingNum).Where("hook_id=?", hookID).Desc("id").Find(&tasks) | ||||
| } | ||||
| 
 | ||||
| // CreateHookTask creates a new hook task, | ||||
| // it handles conversion from Payload to PayloadContent. | ||||
| func CreateHookTask(t *HookTask) error { | ||||
| 	data, err := t.BasePayload.GetJSONPayload() | ||||
| 	data, err := t.Payloader.JSONPayload() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @ -389,6 +356,71 @@ func UpdateHookTask(t *HookTask) error { | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| // PrepareWebhooks adds new webhooks to task queue for given payload. | ||||
| func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) error { | ||||
| 	if err := repo.GetOwner(); err != nil { | ||||
| 		return fmt.Errorf("GetOwner: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	ws, err := GetActiveWebhooksByRepoID(repo.ID) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("GetActiveWebhooksByRepoID: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	// check if repo belongs to org and append additional webhooks | ||||
| 	if repo.Owner.IsOrganization() { | ||||
| 		// get hooks for org | ||||
| 		orgws, err := GetActiveWebhooksByOrgID(repo.OwnerID) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("GetActiveWebhooksByOrgID: %v", err) | ||||
| 		} | ||||
| 		ws = append(ws, orgws...) | ||||
| 	} | ||||
| 
 | ||||
| 	if len(ws) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	for _, w := range ws { | ||||
| 		w.GetEvent() | ||||
| 
 | ||||
| 		switch event { | ||||
| 		case HOOK_EVENT_CREATE: | ||||
| 			if !w.HasCreateEvent() { | ||||
| 				continue | ||||
| 			} | ||||
| 		case HOOK_EVENT_PUSH: | ||||
| 			if !w.HasPushEvent() { | ||||
| 				continue | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		switch w.HookTaskType { | ||||
| 		case SLACK: | ||||
| 			p, err = GetSlackPayload(p, event, w.Meta) | ||||
| 			if err != nil { | ||||
| 				return fmt.Errorf("GetSlackPayload: %v", err) | ||||
| 			} | ||||
| 		default: | ||||
| 			p.SetSecret(w.Secret) | ||||
| 		} | ||||
| 
 | ||||
| 		if err = CreateHookTask(&HookTask{ | ||||
| 			RepoID:      repo.ID, | ||||
| 			HookID:      w.ID, | ||||
| 			Type:        w.HookTaskType, | ||||
| 			URL:         w.URL, | ||||
| 			Payloader:   p, | ||||
| 			ContentType: w.ContentType, | ||||
| 			EventType:   HOOK_EVENT_PUSH, | ||||
| 			IsSSL:       w.IsSSL, | ||||
| 		}); err != nil { | ||||
| 			return fmt.Errorf("CreateHookTask: %v", err) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| type hookQueue struct { | ||||
| 	// Make sure one repository only occur once in the queue. | ||||
| 	lock    sync.Mutex | ||||
|  | ||||
| @ -9,13 +9,18 @@ import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	api "github.com/gogits/go-gogs-client" | ||||
| 
 | ||||
| 	"github.com/gogits/gogs/modules/git" | ||||
| 	"github.com/gogits/gogs/modules/setting" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	SLACK_COLOR string = "#dd4b39" | ||||
| ) | ||||
| 
 | ||||
| type Slack struct { | ||||
| type SlackMeta struct { | ||||
| 	Channel string `json:"channel"` | ||||
| } | ||||
| 
 | ||||
| @ -34,7 +39,9 @@ type SlackAttachment struct { | ||||
| 	Text  string `json:"text"` | ||||
| } | ||||
| 
 | ||||
| func (p SlackPayload) GetJSONPayload() ([]byte, error) { | ||||
| func (p *SlackPayload) SetSecret(_ string) {} | ||||
| 
 | ||||
| func (p *SlackPayload) JSONPayload() ([]byte, error) { | ||||
| 	data, err := json.Marshal(p) | ||||
| 	if err != nil { | ||||
| 		return []byte{}, err | ||||
| @ -42,63 +49,6 @@ func (p SlackPayload) GetJSONPayload() ([]byte, error) { | ||||
| 	return data, nil | ||||
| } | ||||
| 
 | ||||
| func GetSlackPayload(p *Payload, meta string) (*SlackPayload, error) { | ||||
| 	slack := &Slack{} | ||||
| 	slackPayload := &SlackPayload{} | ||||
| 	if err := json.Unmarshal([]byte(meta), &slack); err != nil { | ||||
| 		return slackPayload, errors.New("GetSlackPayload meta json:" + err.Error()) | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO: handle different payload types: push, new branch, delete branch etc. | ||||
| 	// when they are added to gogs. Only handles push now | ||||
| 	return getSlackPushPayload(p, slack) | ||||
| } | ||||
| 
 | ||||
| func getSlackPushPayload(p *Payload, slack *Slack) (*SlackPayload, error) { | ||||
| 	// n new commits | ||||
| 	refSplit := strings.Split(p.Ref, "/") | ||||
| 	branchName := refSplit[len(refSplit)-1] | ||||
| 	var commitString string | ||||
| 
 | ||||
| 	if len(p.Commits) == 1 { | ||||
| 		commitString = "1 new commit" | ||||
| 		if p.CompareUrl != "" { | ||||
| 			commitString = SlackLinkFormatter(p.CompareUrl, commitString) | ||||
| 		} | ||||
| 	} else { | ||||
| 		commitString = fmt.Sprintf("%d new commits", len(p.Commits)) | ||||
| 		if p.CompareUrl != "" { | ||||
| 			commitString = SlackLinkFormatter(p.CompareUrl, commitString) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	repoLink := SlackLinkFormatter(p.Repo.Url, p.Repo.Name) | ||||
| 	branchLink := SlackLinkFormatter(p.Repo.Url+"/src/"+branchName, branchName) | ||||
| 	text := fmt.Sprintf("[%s:%s] %s pushed by %s", repoLink, branchLink, commitString, p.Pusher.Name) | ||||
| 	var attachmentText string | ||||
| 
 | ||||
| 	// for each commit, generate attachment text | ||||
| 	for i, commit := range p.Commits { | ||||
| 		attachmentText += fmt.Sprintf("%s: %s - %s", SlackLinkFormatter(commit.Url, commit.Id[:7]), SlackTextFormatter(commit.Message), SlackTextFormatter(commit.Author.Name)) | ||||
| 		// add linebreak to each commit but the last | ||||
| 		if i < len(p.Commits)-1 { | ||||
| 			attachmentText += "\n" | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	slackAttachments := []SlackAttachment{{Color: SLACK_COLOR, Text: attachmentText}} | ||||
| 
 | ||||
| 	return &SlackPayload{ | ||||
| 		Channel:     slack.Channel, | ||||
| 		Text:        text, | ||||
| 		Username:    "gogs", | ||||
| 		IconUrl:     "https://raw.githubusercontent.com/gogits/gogs/master/public/img/favicon.png", | ||||
| 		UnfurlLinks: 0, | ||||
| 		LinkNames:   0, | ||||
| 		Attachments: slackAttachments, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| // see: https://api.slack.com/docs/formatting | ||||
| func SlackTextFormatter(s string) string { | ||||
| 	// take only first line of commit | ||||
| @ -113,3 +63,81 @@ func SlackTextFormatter(s string) string { | ||||
| func SlackLinkFormatter(url string, text string) string { | ||||
| 	return fmt.Sprintf("<%s|%s>", url, SlackTextFormatter(text)) | ||||
| } | ||||
| 
 | ||||
| func getSlackCreatePayload(p *api.CreatePayload, slack *SlackMeta) (*SlackPayload, error) { | ||||
| 	// created tag/branch | ||||
| 	refName := git.RefEndName(p.Ref) | ||||
| 
 | ||||
| 	repoLink := SlackLinkFormatter(p.Repo.URL, p.Repo.Name) | ||||
| 	refLink := SlackLinkFormatter(p.Repo.URL+"/src/"+refName, refName) | ||||
| 	text := fmt.Sprintf("[%s:%s] %s created by %s", repoLink, refLink, p.RefType, p.Sender.UserName) | ||||
| 
 | ||||
| 	return &SlackPayload{ | ||||
| 		Channel:  slack.Channel, | ||||
| 		Text:     text, | ||||
| 		Username: setting.AppName, | ||||
| 		IconUrl:  setting.AppUrl + "/img/favicon.png", | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, error) { | ||||
| 	// n new commits | ||||
| 	var ( | ||||
| 		branchName   = git.RefEndName(p.Ref) | ||||
| 		commitString string | ||||
| 	) | ||||
| 
 | ||||
| 	if len(p.Commits) == 1 { | ||||
| 		commitString = "1 new commit" | ||||
| 		if len(p.CompareUrl) > 0 { | ||||
| 			commitString = SlackLinkFormatter(p.CompareUrl, commitString) | ||||
| 		} | ||||
| 	} else { | ||||
| 		commitString = fmt.Sprintf("%d new commits", len(p.Commits)) | ||||
| 		if p.CompareUrl != "" { | ||||
| 			commitString = SlackLinkFormatter(p.CompareUrl, commitString) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	repoLink := SlackLinkFormatter(p.Repo.URL, p.Repo.Name) | ||||
| 	branchLink := SlackLinkFormatter(p.Repo.URL+"/src/"+branchName, branchName) | ||||
| 	text := fmt.Sprintf("[%s:%s] %s pushed by %s", repoLink, branchLink, commitString, p.Pusher.Name) | ||||
| 
 | ||||
| 	var attachmentText string | ||||
| 	// for each commit, generate attachment text | ||||
| 	for i, commit := range p.Commits { | ||||
| 		attachmentText += fmt.Sprintf("%s: %s - %s", SlackLinkFormatter(commit.URL, commit.ID[:7]), SlackTextFormatter(commit.Message), SlackTextFormatter(commit.Author.Name)) | ||||
| 		// add linebreak to each commit but the last | ||||
| 		if i < len(p.Commits)-1 { | ||||
| 			attachmentText += "\n" | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	slackAttachments := []SlackAttachment{{Color: SLACK_COLOR, Text: attachmentText}} | ||||
| 
 | ||||
| 	return &SlackPayload{ | ||||
| 		Channel:     slack.Channel, | ||||
| 		Text:        text, | ||||
| 		Username:    setting.AppName, | ||||
| 		IconUrl:     setting.AppUrl + "/img/favicon.png", | ||||
| 		Attachments: slackAttachments, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| func GetSlackPayload(p api.Payloader, event HookEventType, meta string) (*SlackPayload, error) { | ||||
| 	s := new(SlackPayload) | ||||
| 
 | ||||
| 	slack := &SlackMeta{} | ||||
| 	if err := json.Unmarshal([]byte(meta), &slack); err != nil { | ||||
| 		return s, errors.New("GetSlackPayload meta json:" + err.Error()) | ||||
| 	} | ||||
| 
 | ||||
| 	switch event { | ||||
| 	case HOOK_EVENT_CREATE: | ||||
| 		return getSlackCreatePayload(p.(*api.CreatePayload), slack) | ||||
| 	case HOOK_EVENT_PUSH: | ||||
| 		return getSlackPushPayload(p.(*api.PushPayload), slack) | ||||
| 	} | ||||
| 
 | ||||
| 	return s, nil | ||||
| } | ||||
|  | ||||
| @ -67,8 +67,22 @@ func (f *RepoSettingForm) Validate(ctx *macaron.Context, errs binding.Errors) bi | ||||
| //        \/       \/    \/     \/     \/            \/ | ||||
| 
 | ||||
| type WebhookForm struct { | ||||
| 	PushOnly bool | ||||
| 	Active   bool | ||||
| 	Events string | ||||
| 	Create bool | ||||
| 	Push   bool | ||||
| 	Active bool | ||||
| } | ||||
| 
 | ||||
| func (f WebhookForm) PushOnly() bool { | ||||
| 	return f.Events == "push_only" | ||||
| } | ||||
| 
 | ||||
| func (f WebhookForm) SendEverything() bool { | ||||
| 	return f.Events == "send_everything" | ||||
| } | ||||
| 
 | ||||
| func (f WebhookForm) ChooseEvents() bool { | ||||
| 	return f.Events == "choose_events" | ||||
| } | ||||
| 
 | ||||
| type NewWebhookForm struct { | ||||
|  | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								public/css/gogs.min.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								public/css/gogs.min.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -367,6 +367,23 @@ function initRepository() { | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| function initWebhook() { | ||||
|     if ($('.new.webhook').length == 0) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     $('.events.checkbox input').change(function () { | ||||
|         if ($(this).is(':checked')) { | ||||
|             $('.events.fields').show(); | ||||
|         } | ||||
|     }); | ||||
|     $('.non-events.checkbox input').change(function () { | ||||
|         if ($(this).is(':checked')) { | ||||
|             $('.events.fields').hide(); | ||||
|         } | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| $(document).ready(function () { | ||||
|     csrf = $('meta[name=_csrf]').attr("content"); | ||||
| 
 | ||||
| @ -473,4 +490,5 @@ $(document).ready(function () { | ||||
|     initCommentForm(); | ||||
|     initInstall(); | ||||
|     initRepository(); | ||||
|     initWebhook(); | ||||
| }); | ||||
| @ -76,4 +76,12 @@ | ||||
| 			margin-left: 25px; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| .new.webhook { | ||||
| 	.events.fields { | ||||
| 		.column { | ||||
| 			padding-left: 40px; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -83,7 +83,7 @@ func CreateRepoHook(ctx *middleware.Context, form api.CreateHookOption) { | ||||
| 			ctx.JSON(422, &base.ApiJsonErr{"missing config option: channel", base.DOC_URL}) | ||||
| 			return | ||||
| 		} | ||||
| 		meta, err := json.Marshal(&models.Slack{ | ||||
| 		meta, err := json.Marshal(&models.SlackMeta{ | ||||
| 			Channel: channel, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| @ -141,7 +141,7 @@ func EditRepoHook(ctx *middleware.Context, form api.EditHookOption) { | ||||
| 
 | ||||
| 		if w.HookTaskType == models.SLACK { | ||||
| 			if channel, ok := form.Config["channel"]; ok { | ||||
| 				meta, err := json.Marshal(&models.Slack{ | ||||
| 				meta, err := json.Marshal(&models.SlackMeta{ | ||||
| 					Channel: channel, | ||||
| 				}) | ||||
| 				if err != nil { | ||||
|  | ||||
| @ -320,6 +320,18 @@ func WebhooksNew(ctx *middleware.Context) { | ||||
| 	ctx.HTML(200, orCtx.NewTemplate) | ||||
| } | ||||
| 
 | ||||
| func ParseHookEvent(form auth.WebhookForm) *models.HookEvent { | ||||
| 	return &models.HookEvent{ | ||||
| 		PushOnly:       form.PushOnly(), | ||||
| 		SendEverything: form.SendEverything(), | ||||
| 		ChooseEvents:   form.ChooseEvents(), | ||||
| 		HookEvents: models.HookEvents{ | ||||
| 			Create: form.Create, | ||||
| 			Push:   form.Push, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func WebHooksNewPost(ctx *middleware.Context, form auth.NewWebhookForm) { | ||||
| 	ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook") | ||||
| 	ctx.Data["PageIsSettingsHooks"] = true | ||||
| @ -345,13 +357,11 @@ func WebHooksNewPost(ctx *middleware.Context, form auth.NewWebhookForm) { | ||||
| 	} | ||||
| 
 | ||||
| 	w := &models.Webhook{ | ||||
| 		RepoID:      orCtx.RepoID, | ||||
| 		URL:         form.PayloadURL, | ||||
| 		ContentType: contentType, | ||||
| 		Secret:      form.Secret, | ||||
| 		HookEvent: &models.HookEvent{ | ||||
| 			PushOnly: form.PushOnly, | ||||
| 		}, | ||||
| 		RepoID:       orCtx.RepoID, | ||||
| 		URL:          form.PayloadURL, | ||||
| 		ContentType:  contentType, | ||||
| 		Secret:       form.Secret, | ||||
| 		HookEvent:    ParseHookEvent(form.WebhookForm), | ||||
| 		IsActive:     form.Active, | ||||
| 		HookTaskType: models.GOGS, | ||||
| 		OrgID:        orCtx.OrgID, | ||||
| @ -385,7 +395,7 @@ func SlackHooksNewPost(ctx *middleware.Context, form auth.NewSlackHookForm) { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	meta, err := json.Marshal(&models.Slack{ | ||||
| 	meta, err := json.Marshal(&models.SlackMeta{ | ||||
| 		Channel: form.Channel, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| @ -394,12 +404,10 @@ func SlackHooksNewPost(ctx *middleware.Context, form auth.NewSlackHookForm) { | ||||
| 	} | ||||
| 
 | ||||
| 	w := &models.Webhook{ | ||||
| 		RepoID:      orCtx.RepoID, | ||||
| 		URL:         form.PayloadURL, | ||||
| 		ContentType: models.JSON, | ||||
| 		HookEvent: &models.HookEvent{ | ||||
| 			PushOnly: form.PushOnly, | ||||
| 		}, | ||||
| 		RepoID:       orCtx.RepoID, | ||||
| 		URL:          form.PayloadURL, | ||||
| 		ContentType:  models.JSON, | ||||
| 		HookEvent:    ParseHookEvent(form.WebhookForm), | ||||
| 		IsActive:     form.Active, | ||||
| 		HookTaskType: models.SLACK, | ||||
| 		Meta:         string(meta), | ||||
| @ -491,9 +499,7 @@ func WebHooksEditPost(ctx *middleware.Context, form auth.NewWebhookForm) { | ||||
| 	w.URL = form.PayloadURL | ||||
| 	w.ContentType = contentType | ||||
| 	w.Secret = form.Secret | ||||
| 	w.HookEvent = &models.HookEvent{ | ||||
| 		PushOnly: form.PushOnly, | ||||
| 	} | ||||
| 	w.HookEvent = ParseHookEvent(form.WebhookForm) | ||||
| 	w.IsActive = form.Active | ||||
| 	if err := w.UpdateEvent(); err != nil { | ||||
| 		ctx.Handle(500, "UpdateEvent", err) | ||||
| @ -523,7 +529,7 @@ func SlackHooksEditPost(ctx *middleware.Context, form auth.NewSlackHookForm) { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	meta, err := json.Marshal(&models.Slack{ | ||||
| 	meta, err := json.Marshal(&models.SlackMeta{ | ||||
| 		Channel: form.Channel, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| @ -533,9 +539,7 @@ func SlackHooksEditPost(ctx *middleware.Context, form auth.NewSlackHookForm) { | ||||
| 
 | ||||
| 	w.URL = form.PayloadURL | ||||
| 	w.Meta = string(meta) | ||||
| 	w.HookEvent = &models.HookEvent{ | ||||
| 		PushOnly: form.PushOnly, | ||||
| 	} | ||||
| 	w.HookEvent = ParseHookEvent(form.WebhookForm) | ||||
| 	w.IsActive = form.Active | ||||
| 	if err := w.UpdateEvent(); err != nil { | ||||
| 		ctx.Handle(500, "UpdateEvent", err) | ||||
|  | ||||
| @ -26,4 +26,22 @@ | ||||
| 		</div> | ||||
| 	</footer> | ||||
| </body> | ||||
| 
 | ||||
| 	<!-- Third-party libraries --> | ||||
| 	{{if .RequireHighlightJS}} | ||||
| 	<link rel="stylesheet" href="{{AppSubUrl}}/css/highlight-8.7/default.css"> | ||||
| 	<script src="{{AppSubUrl}}/js/libs/highlight-8.7.pack.js"></script> | ||||
| 	{{end}} | ||||
| 	{{if .RequireMinicolors}} | ||||
| 	<link rel="stylesheet" href="{{AppSubUrl}}/css/jquery.minicolors-2.1.12.css"> | ||||
| 	<script src="{{AppSubUrl}}/js/libs/jquery.minicolors-2.1.12.min.js"></script> | ||||
| 	{{end}} | ||||
| 	{{if .RequireDatetimepicker}} | ||||
| 	<link rel="stylesheet" href="{{AppSubUrl}}/css/jquery.datetimepicker-2.4.5.css"> | ||||
| 	<script src="{{AppSubUrl}}/js/libs/jquery.datetimepicker-2.4.5.js"></script> | ||||
| 	{{end}} | ||||
| 	{{if .RequireDropzone}} | ||||
| 	<link rel="stylesheet" href="{{AppSubUrl}}/css/dropzone-4.0.1.css"> | ||||
| 	<script src="{{AppSubUrl}}/js/libs/dropzone-4.0.1.js"></script> | ||||
| 	{{end}} | ||||
| </html> | ||||
| @ -25,24 +25,6 @@ | ||||
| 	<script src="{{AppSubUrl}}/js/semantic-2.0.8.min.js"></script> | ||||
| 	<script src="{{AppSubUrl}}/js/gogs.js?v={{AppVer}}"></script> | ||||
| 
 | ||||
| 	<!-- Third-party libraries --> | ||||
| 	{{if .RequireHighlightJS}} | ||||
| 	<link rel="stylesheet" href="{{AppSubUrl}}/css/highlight-8.7/default.css"> | ||||
| 	<script src="{{AppSubUrl}}/js/libs/highlight-8.7.pack.js"></script> | ||||
| 	{{end}} | ||||
| 	{{if .RequireMinicolors}} | ||||
| 	<link rel="stylesheet" href="{{AppSubUrl}}/css/jquery.minicolors-2.1.12.css"> | ||||
| 	<script src="{{AppSubUrl}}/js/libs/jquery.minicolors-2.1.12.min.js"></script> | ||||
| 	{{end}} | ||||
| 	{{if .RequireDatetimepicker}} | ||||
| 	<link rel="stylesheet" href="{{AppSubUrl}}/css/jquery.datetimepicker-2.4.5.css"> | ||||
| 	<script src="{{AppSubUrl}}/js/libs/jquery.datetimepicker-2.4.5.js"></script> | ||||
| 	{{end}} | ||||
| 	{{if .RequireDropzone}} | ||||
| 	<link rel="stylesheet" href="{{AppSubUrl}}/css/dropzone-4.0.1.css"> | ||||
| 	<script src="{{AppSubUrl}}/js/libs/dropzone-4.0.1.js"></script> | ||||
| 	{{end}} | ||||
| 
 | ||||
| 	<title>{{if .Title}}{{.Title}} - {{end}}{{AppName}}</title> | ||||
| </head> | ||||
| <body> | ||||
|  | ||||
| @ -28,7 +28,7 @@ | ||||
| 					  	{{if .IsSucceed}} | ||||
| 					  	<span class="ui green label">{{.ResponseInfo.Status}}</span> | ||||
| 					  	{{else}} | ||||
| 					  	<span class="ui red label">500</span> | ||||
| 					  	<span class="ui red label">{{.ResponseInfo.Status}}</span> | ||||
| 					  	{{end}} | ||||
| 				  	{{else}} | ||||
| 				  		<span class="ui label">N/A</span> | ||||
|  | ||||
| @ -1,14 +1,52 @@ | ||||
| <div class="field"> | ||||
|   <h4>{{.i18n.Tr "repo.settings.event_desc"}}</h4> | ||||
| 	<div class="grouped fields"> | ||||
| 		<div class="field"> | ||||
| 		  <div class="ui radio checkbox checked"> | ||||
| 		    <input class="hidden" name="push_only" type="radio" {{if or .PageIsSettingsHooksNew .Webhook.PushOnly}}checked{{end}}> | ||||
| 		    <label>{{.i18n.Tr "repo.settings.event_push_only" | Str2html}}</label> | ||||
| 		  </div> | ||||
| 		</div> | ||||
| 	<div class="grouped event type fields"> | ||||
|     <div class="field"> | ||||
|       <div class="ui radio non-events checkbox"> | ||||
|         <input class="hidden" name="events" type="radio" value="push_only" {{if or .PageIsSettingsHooksNew .Webhook.PushOnly}}checked{{end}}> | ||||
|         <label>{{.i18n.Tr "repo.settings.event_push_only" | Str2html}}</label> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="field"> | ||||
|       <div class="ui radio non-events checkbox"> | ||||
|         <input class="hidden" name="events" type="radio" value="send_everything" {{if .Webhook.SendEverything}}checked{{end}}> | ||||
|         <label>{{.i18n.Tr "repo.settings.event_send_everything" | Str2html}}</label> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="field"> | ||||
|       <div class="ui radio events checkbox"> | ||||
|         <input class="hidden" name="events" type="radio" value="choose_events" {{if .Webhook.ChooseEvents}}checked{{end}}> | ||||
|         <label>{{.i18n.Tr "repo.settings.event_choose" | Str2html}}</label> | ||||
|       </div> | ||||
|     </div> | ||||
| 	</div> | ||||
| 
 | ||||
|   <div class="events fields ui grid" {{if not .Webhook.ChooseEvents}}style="display:none"{{end}}> | ||||
|     <!-- Create --> | ||||
|     <div class="seven wide column"> | ||||
|       <div class="field"> | ||||
|         <div class="ui checkbox"> | ||||
|           <input class="hidden" name="create" type="checkbox" tabindex="0" {{if .Webhook.Create}}checked{{end}}> | ||||
|           <label>{{.i18n.Tr "repo.settings.event_create"}}</label> | ||||
|           <span class="help">{{.i18n.Tr "repo.settings.event_create_desc"}}</span> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <!-- Push --> | ||||
|     <div class="seven wide column"> | ||||
|       <div class="field"> | ||||
|         <div class="ui checkbox"> | ||||
|           <input class="hidden" name="push" type="checkbox" tabindex="0" {{if .Webhook.Push}}checked{{end}}> | ||||
|           <label>{{.i18n.Tr "repo.settings.event_push"}}</label> | ||||
|             <span class="help">{{.i18n.Tr "repo.settings.event_push_desc"}}</span> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </div> | ||||
| 
 | ||||
| <div class="ui divider"></div> | ||||
| 
 | ||||
| <div class="inline field"> | ||||
|   <div class="ui checkbox"> | ||||
|     <input class="hidden" name="active" type="checkbox" tabindex="0" {{if or .PageIsSettingsHooksNew .Webhook.IsActive}}checked{{end}}> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Unknwon
						Unknwon