mirror of
				https://github.com/go-gitea/gitea
				synced 2025-10-30 19:08:37 +00:00 
			
		
		
		
	Telegram webhook (#4227)
This commit is contained in:
		| @@ -145,6 +145,15 @@ func (w *Webhook) GetDiscordHook() *DiscordMeta { | |||||||
| 	return s | 	return s | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // GetTelegramHook returns telegram metadata | ||||||
|  | func (w *Webhook) GetTelegramHook() *TelegramMeta { | ||||||
|  | 	s := &TelegramMeta{} | ||||||
|  | 	if err := json.Unmarshal([]byte(w.Meta), s); err != nil { | ||||||
|  | 		log.Error("webhook.GetTelegramHook(%d): %v", w.ID, err) | ||||||
|  | 	} | ||||||
|  | 	return s | ||||||
|  | } | ||||||
|  |  | ||||||
| // History returns history of webhook by given conditions. | // History returns history of webhook by given conditions. | ||||||
| func (w *Webhook) History(page int) ([]*HookTask, error) { | func (w *Webhook) History(page int) ([]*HookTask, error) { | ||||||
| 	return HookTasks(w.ID, page) | 	return HookTasks(w.ID, page) | ||||||
| @@ -456,6 +465,7 @@ const ( | |||||||
| 	GITEA | 	GITEA | ||||||
| 	DISCORD | 	DISCORD | ||||||
| 	DINGTALK | 	DINGTALK | ||||||
|  | 	TELEGRAM | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var hookTaskTypes = map[string]HookTaskType{ | var hookTaskTypes = map[string]HookTaskType{ | ||||||
| @@ -464,6 +474,7 @@ var hookTaskTypes = map[string]HookTaskType{ | |||||||
| 	"slack":    SLACK, | 	"slack":    SLACK, | ||||||
| 	"discord":  DISCORD, | 	"discord":  DISCORD, | ||||||
| 	"dingtalk": DINGTALK, | 	"dingtalk": DINGTALK, | ||||||
|  | 	"telegram": TELEGRAM, | ||||||
| } | } | ||||||
|  |  | ||||||
| // ToHookTaskType returns HookTaskType by given name. | // ToHookTaskType returns HookTaskType by given name. | ||||||
| @@ -484,6 +495,8 @@ func (t HookTaskType) Name() string { | |||||||
| 		return "discord" | 		return "discord" | ||||||
| 	case DINGTALK: | 	case DINGTALK: | ||||||
| 		return "dingtalk" | 		return "dingtalk" | ||||||
|  | 	case TELEGRAM: | ||||||
|  | 		return "telegram" | ||||||
| 	} | 	} | ||||||
| 	return "" | 	return "" | ||||||
| } | } | ||||||
| @@ -657,6 +670,11 @@ func prepareWebhook(e Engine, w *Webhook, repo *Repository, event HookEventType, | |||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return fmt.Errorf("GetDingtalkPayload: %v", err) | 			return fmt.Errorf("GetDingtalkPayload: %v", err) | ||||||
| 		} | 		} | ||||||
|  | 	case TELEGRAM: | ||||||
|  | 		payloader, err = GetTelegramPayload(p, event, w.Meta) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return fmt.Errorf("GetTelegramPayload: %v", err) | ||||||
|  | 		} | ||||||
| 	default: | 	default: | ||||||
| 		p.SetSecret(w.Secret) | 		p.SetSecret(w.Secret) | ||||||
| 		payloader = p | 		payloader = p | ||||||
|   | |||||||
							
								
								
									
										322
									
								
								models/webhook_telegram.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										322
									
								
								models/webhook_telegram.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,322 @@ | |||||||
|  | // Copyright 2019 The Gitea Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a MIT-style | ||||||
|  | // license that can be found in the LICENSE file. | ||||||
|  |  | ||||||
|  | package models | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"encoding/json" | ||||||
|  | 	"fmt" | ||||||
|  | 	"strings" | ||||||
|  |  | ||||||
|  | 	"code.gitea.io/gitea/modules/git" | ||||||
|  | 	"code.gitea.io/gitea/modules/markup" | ||||||
|  | 	api "code.gitea.io/sdk/gitea" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type ( | ||||||
|  | 	// TelegramPayload represents | ||||||
|  | 	TelegramPayload struct { | ||||||
|  | 		Message   string `json:"text"` | ||||||
|  | 		ParseMode string `json:"parse_mode"` | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// TelegramMeta contains the telegram metadata | ||||||
|  | 	TelegramMeta struct { | ||||||
|  | 		BotToken string `json:"bot_token"` | ||||||
|  | 		ChatID   string `json:"chat_id"` | ||||||
|  | 	} | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // SetSecret sets the telegram secret | ||||||
|  | func (p *TelegramPayload) SetSecret(_ string) {} | ||||||
|  |  | ||||||
|  | // JSONPayload Marshals the TelegramPayload to json | ||||||
|  | func (p *TelegramPayload) JSONPayload() ([]byte, error) { | ||||||
|  | 	p.ParseMode = "HTML" | ||||||
|  | 	p.Message = markup.Sanitize(p.Message) | ||||||
|  | 	data, err := json.MarshalIndent(p, "", "  ") | ||||||
|  | 	if err != nil { | ||||||
|  | 		return []byte{}, err | ||||||
|  | 	} | ||||||
|  | 	return data, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getTelegramCreatePayload(p *api.CreatePayload) (*TelegramPayload, error) { | ||||||
|  | 	// created tag/branch | ||||||
|  | 	refName := git.RefEndName(p.Ref) | ||||||
|  | 	title := fmt.Sprintf(`[<a href="%s">%s</a>] %s <a href="%s">%s</a> created`, p.Repo.HTMLURL, p.Repo.FullName, p.RefType, | ||||||
|  | 		p.Repo.HTMLURL+"/src/"+refName, refName) | ||||||
|  |  | ||||||
|  | 	return &TelegramPayload{ | ||||||
|  | 		Message: title, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getTelegramDeletePayload(p *api.DeletePayload) (*TelegramPayload, error) { | ||||||
|  | 	// created tag/branch | ||||||
|  | 	refName := git.RefEndName(p.Ref) | ||||||
|  | 	title := fmt.Sprintf(`[<a href="%s">%s</a>] %s <a href="%s">%s</a> deleted`, p.Repo.HTMLURL, p.Repo.FullName, p.RefType, | ||||||
|  | 		p.Repo.HTMLURL+"/src/"+refName, refName) | ||||||
|  |  | ||||||
|  | 	return &TelegramPayload{ | ||||||
|  | 		Message: title, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getTelegramForkPayload(p *api.ForkPayload) (*TelegramPayload, error) { | ||||||
|  | 	title := fmt.Sprintf(`%s is forked to <a href="%s">%s</a>`, p.Forkee.FullName, p.Repo.HTMLURL, p.Repo.FullName) | ||||||
|  |  | ||||||
|  | 	return &TelegramPayload{ | ||||||
|  | 		Message: title, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getTelegramPushPayload(p *api.PushPayload) (*TelegramPayload, error) { | ||||||
|  | 	var ( | ||||||
|  | 		branchName = git.RefEndName(p.Ref) | ||||||
|  | 		commitDesc string | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	var titleLink string | ||||||
|  | 	if len(p.Commits) == 1 { | ||||||
|  | 		commitDesc = "1 new commit" | ||||||
|  | 		titleLink = p.Commits[0].URL | ||||||
|  | 	} else { | ||||||
|  | 		commitDesc = fmt.Sprintf("%d new commits", len(p.Commits)) | ||||||
|  | 		titleLink = p.CompareURL | ||||||
|  | 	} | ||||||
|  | 	if titleLink == "" { | ||||||
|  | 		titleLink = p.Repo.HTMLURL + "/src/" + branchName | ||||||
|  | 	} | ||||||
|  | 	title := fmt.Sprintf(`[<a href="%s">%s</a>:<a href="%s">%s</a>] %s`, p.Repo.HTMLURL, p.Repo.FullName, titleLink, branchName, commitDesc) | ||||||
|  |  | ||||||
|  | 	var text string | ||||||
|  | 	// for each commit, generate attachment text | ||||||
|  | 	for i, commit := range p.Commits { | ||||||
|  | 		var authorName string | ||||||
|  | 		if commit.Author != nil { | ||||||
|  | 			authorName = " - " + commit.Author.Name | ||||||
|  | 		} | ||||||
|  | 		text += fmt.Sprintf(`[<a href="%s">%s</a>] %s`, commit.URL, commit.ID[:7], | ||||||
|  | 			strings.TrimRight(commit.Message, "\r\n")) + authorName | ||||||
|  | 		// add linebreak to each commit but the last | ||||||
|  | 		if i < len(p.Commits)-1 { | ||||||
|  | 			text += "\n" | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &TelegramPayload{ | ||||||
|  | 		Message: title + "\n" + text, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getTelegramIssuesPayload(p *api.IssuePayload) (*TelegramPayload, error) { | ||||||
|  | 	var text, title string | ||||||
|  | 	switch p.Action { | ||||||
|  | 	case api.HookIssueOpened: | ||||||
|  | 		title = fmt.Sprintf(`[<a href="%s">%s</a>] Issue opened: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 			p.Issue.URL, p.Index, p.Issue.Title) | ||||||
|  | 		text = p.Issue.Body | ||||||
|  | 	case api.HookIssueClosed: | ||||||
|  | 		title = fmt.Sprintf(`[<a href="%s">%s</a>] Issue closed: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 			p.Issue.URL, p.Index, p.Issue.Title) | ||||||
|  | 		text = p.Issue.Body | ||||||
|  | 	case api.HookIssueReOpened: | ||||||
|  | 		title = fmt.Sprintf(`[<a href="%s">%s</a>] Issue re-opened: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 			p.Issue.URL, p.Index, p.Issue.Title) | ||||||
|  | 		text = p.Issue.Body | ||||||
|  | 	case api.HookIssueEdited: | ||||||
|  | 		title = fmt.Sprintf(`[<a href="%s">%s</a>] Issue edited: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 			p.Issue.URL, p.Index, p.Issue.Title) | ||||||
|  | 		text = p.Issue.Body | ||||||
|  | 	case api.HookIssueAssigned: | ||||||
|  | 		title = fmt.Sprintf(`[<a href="%s">%s</a>] Issue assigned to %s: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 			p.Issue.Assignee.UserName, p.Issue.URL, p.Index, p.Issue.Title) | ||||||
|  | 		text = p.Issue.Body | ||||||
|  | 	case api.HookIssueUnassigned: | ||||||
|  | 		title = fmt.Sprintf(`[<a href="%s">%s</a>] Issue unassigned: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 			p.Issue.URL, p.Index, p.Issue.Title) | ||||||
|  | 		text = p.Issue.Body | ||||||
|  | 	case api.HookIssueLabelUpdated: | ||||||
|  | 		title = fmt.Sprintf(`[<a href="%s">%s</a>] Issue labels updated: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 			p.Issue.URL, p.Index, p.Issue.Title) | ||||||
|  | 		text = p.Issue.Body | ||||||
|  | 	case api.HookIssueLabelCleared: | ||||||
|  | 		title = fmt.Sprintf(`[<a href="%s">%s</a>] Issue labels cleared: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 			p.Issue.URL, p.Index, p.Issue.Title) | ||||||
|  | 		text = p.Issue.Body | ||||||
|  | 	case api.HookIssueSynchronized: | ||||||
|  | 		title = fmt.Sprintf(`[<a href="%s">%s</a>] Issue synchronized: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 			p.Issue.URL, p.Index, p.Issue.Title) | ||||||
|  | 		text = p.Issue.Body | ||||||
|  | 	case api.HookIssueMilestoned: | ||||||
|  | 		title = fmt.Sprintf(`[<a href="%s">%s</a>] Issue milestone: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 			p.Issue.URL, p.Index, p.Issue.Title) | ||||||
|  | 		text = p.Issue.Body | ||||||
|  | 	case api.HookIssueDemilestoned: | ||||||
|  | 		title = fmt.Sprintf(`[<a href="%s">%s</a>] Issue clear milestone: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 			p.Issue.URL, p.Index, p.Issue.Title) | ||||||
|  | 		text = p.Issue.Body | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &TelegramPayload{ | ||||||
|  | 		Message: title + "\n\n" + text, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getTelegramIssueCommentPayload(p *api.IssueCommentPayload) (*TelegramPayload, error) { | ||||||
|  | 	url := fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, CommentHashTag(p.Comment.ID)) | ||||||
|  | 	title := fmt.Sprintf(`<a href="%s">#%d %s</a>`, url, p.Issue.Index, p.Issue.Title) | ||||||
|  | 	var text string | ||||||
|  | 	switch p.Action { | ||||||
|  | 	case api.HookIssueCommentCreated: | ||||||
|  | 		text = "New comment: " + title | ||||||
|  | 		text += p.Comment.Body | ||||||
|  | 	case api.HookIssueCommentEdited: | ||||||
|  | 		text = "Comment edited: " + title | ||||||
|  | 		text += p.Comment.Body | ||||||
|  | 	case api.HookIssueCommentDeleted: | ||||||
|  | 		text = "Comment deleted: " + title | ||||||
|  | 		text += p.Comment.Body | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &TelegramPayload{ | ||||||
|  | 		Message: title + "\n" + text, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getTelegramPullRequestPayload(p *api.PullRequestPayload) (*TelegramPayload, error) { | ||||||
|  | 	var text, title string | ||||||
|  | 	switch p.Action { | ||||||
|  | 	case api.HookIssueOpened: | ||||||
|  | 		title = fmt.Sprintf(`[<a href="%s">%s</a>] Pull request opened: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 			p.PullRequest.HTMLURL, p.Index, p.PullRequest.Title) | ||||||
|  | 		text = p.PullRequest.Body | ||||||
|  | 	case api.HookIssueClosed: | ||||||
|  | 		if p.PullRequest.HasMerged { | ||||||
|  | 			title = fmt.Sprintf(`[<a href="%s">%s</a>] Pull request merged: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 				p.PullRequest.HTMLURL, p.Index, p.PullRequest.Title) | ||||||
|  | 		} else { | ||||||
|  | 			title = fmt.Sprintf(`[<a href="%s">%s</a>] Pull request closed: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 				p.PullRequest.HTMLURL, p.Index, p.PullRequest.Title) | ||||||
|  | 		} | ||||||
|  | 		text = p.PullRequest.Body | ||||||
|  | 	case api.HookIssueReOpened: | ||||||
|  | 		title = fmt.Sprintf(`[<a href="%s">%s</a>] Pull request re-opened: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 			p.PullRequest.HTMLURL, p.Index, p.PullRequest.Title) | ||||||
|  | 		text = p.PullRequest.Body | ||||||
|  | 	case api.HookIssueEdited: | ||||||
|  | 		title = fmt.Sprintf(`[<a href="%s">%s</a>] Pull request edited: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 			p.PullRequest.HTMLURL, p.Index, p.PullRequest.Title) | ||||||
|  | 		text = p.PullRequest.Body | ||||||
|  | 	case api.HookIssueAssigned: | ||||||
|  | 		list, err := MakeAssigneeList(&Issue{ID: p.PullRequest.ID}) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return &TelegramPayload{}, err | ||||||
|  | 		} | ||||||
|  | 		title = fmt.Sprintf(`[<a href="%s">%s</a>] Pull request assigned to %s: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 			list, p.PullRequest.HTMLURL, p.Index, p.PullRequest.Title) | ||||||
|  | 		text = p.PullRequest.Body | ||||||
|  | 	case api.HookIssueUnassigned: | ||||||
|  | 		title = fmt.Sprintf(`[<a href="%s">%s</a>] Pull request unassigned: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 			p.PullRequest.HTMLURL, p.Index, p.PullRequest.Title) | ||||||
|  | 		text = p.PullRequest.Body | ||||||
|  | 	case api.HookIssueLabelUpdated: | ||||||
|  | 		title = fmt.Sprintf(`[<a href="%s">%s</a>] Pull request labels updated: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 			p.PullRequest.HTMLURL, p.Index, p.PullRequest.Title) | ||||||
|  | 		text = p.PullRequest.Body | ||||||
|  | 	case api.HookIssueLabelCleared: | ||||||
|  | 		title = fmt.Sprintf(`[<a href="%s">%s</a>] Pull request labels cleared: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 			p.PullRequest.HTMLURL, p.Index, p.PullRequest.Title) | ||||||
|  | 		text = p.PullRequest.Body | ||||||
|  | 	case api.HookIssueSynchronized: | ||||||
|  | 		title = fmt.Sprintf(`[<a href="%s">%s</a>] Pull request synchronized: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 			p.PullRequest.HTMLURL, p.Index, p.PullRequest.Title) | ||||||
|  | 		text = p.PullRequest.Body | ||||||
|  | 	case api.HookIssueMilestoned: | ||||||
|  | 		title = fmt.Sprintf(`[<a href="%s">%s</a>] Pull request milestone: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 			p.PullRequest.HTMLURL, p.Index, p.PullRequest.Title) | ||||||
|  | 		text = p.PullRequest.Body | ||||||
|  | 	case api.HookIssueDemilestoned: | ||||||
|  | 		title = fmt.Sprintf(`[<a href="%s">%s</a>] Pull request clear milestone: <a href="%s">#%d %s</a>`, p.Repository.HTMLURL, p.Repository.FullName, | ||||||
|  | 			p.PullRequest.HTMLURL, p.Index, p.PullRequest.Title) | ||||||
|  | 		text = p.PullRequest.Body | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &TelegramPayload{ | ||||||
|  | 		Message: title + "\n" + text, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getTelegramRepositoryPayload(p *api.RepositoryPayload) (*TelegramPayload, error) { | ||||||
|  | 	var title string | ||||||
|  | 	switch p.Action { | ||||||
|  | 	case api.HookRepoCreated: | ||||||
|  | 		title = fmt.Sprintf(`[<a href="%s">%s</a>] Repository created`, p.Repository.HTMLURL, p.Repository.FullName) | ||||||
|  | 		return &TelegramPayload{ | ||||||
|  | 			Message: title, | ||||||
|  | 		}, nil | ||||||
|  | 	case api.HookRepoDeleted: | ||||||
|  | 		title = fmt.Sprintf("[%s] Repository deleted", p.Repository.FullName) | ||||||
|  | 		return &TelegramPayload{ | ||||||
|  | 			Message: title, | ||||||
|  | 		}, nil | ||||||
|  | 	} | ||||||
|  | 	return nil, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getTelegramReleasePayload(p *api.ReleasePayload) (*TelegramPayload, 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 &TelegramPayload{ | ||||||
|  | 			Message: title + "\n" + url, | ||||||
|  | 		}, nil | ||||||
|  | 	case api.HookReleaseUpdated: | ||||||
|  | 		title = fmt.Sprintf("[%s] Release updated", p.Release.TagName) | ||||||
|  | 		url = p.Release.URL | ||||||
|  | 		return &TelegramPayload{ | ||||||
|  | 			Message: title + "\n" + url, | ||||||
|  | 		}, nil | ||||||
|  |  | ||||||
|  | 	case api.HookReleaseDeleted: | ||||||
|  | 		title = fmt.Sprintf("[%s] Release deleted", p.Release.TagName) | ||||||
|  | 		url = p.Release.URL | ||||||
|  | 		return &TelegramPayload{ | ||||||
|  | 			Message: title + "\n" + url, | ||||||
|  | 		}, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // GetTelegramPayload converts a telegram webhook into a TelegramPayload | ||||||
|  | func GetTelegramPayload(p api.Payloader, event HookEventType, meta string) (*TelegramPayload, error) { | ||||||
|  | 	s := new(TelegramPayload) | ||||||
|  |  | ||||||
|  | 	switch event { | ||||||
|  | 	case HookEventCreate: | ||||||
|  | 		return getTelegramCreatePayload(p.(*api.CreatePayload)) | ||||||
|  | 	case HookEventDelete: | ||||||
|  | 		return getTelegramDeletePayload(p.(*api.DeletePayload)) | ||||||
|  | 	case HookEventFork: | ||||||
|  | 		return getTelegramForkPayload(p.(*api.ForkPayload)) | ||||||
|  | 	case HookEventIssues: | ||||||
|  | 		return getTelegramIssuesPayload(p.(*api.IssuePayload)) | ||||||
|  | 	case HookEventIssueComment: | ||||||
|  | 		return getTelegramIssueCommentPayload(p.(*api.IssueCommentPayload)) | ||||||
|  | 	case HookEventPush: | ||||||
|  | 		return getTelegramPushPayload(p.(*api.PushPayload)) | ||||||
|  | 	case HookEventPullRequest: | ||||||
|  | 		return getTelegramPullRequestPayload(p.(*api.PullRequestPayload)) | ||||||
|  | 	case HookEventRepository: | ||||||
|  | 		return getTelegramRepositoryPayload(p.(*api.RepositoryPayload)) | ||||||
|  | 	case HookEventRelease: | ||||||
|  | 		return getTelegramReleasePayload(p.(*api.ReleasePayload)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return s, nil | ||||||
|  | } | ||||||
| @@ -197,18 +197,21 @@ func TestToHookTaskType(t *testing.T) { | |||||||
| 	assert.Equal(t, GOGS, ToHookTaskType("gogs")) | 	assert.Equal(t, GOGS, ToHookTaskType("gogs")) | ||||||
| 	assert.Equal(t, SLACK, ToHookTaskType("slack")) | 	assert.Equal(t, SLACK, ToHookTaskType("slack")) | ||||||
| 	assert.Equal(t, GITEA, ToHookTaskType("gitea")) | 	assert.Equal(t, GITEA, ToHookTaskType("gitea")) | ||||||
|  | 	assert.Equal(t, TELEGRAM, ToHookTaskType("telegram")) | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestHookTaskType_Name(t *testing.T) { | func TestHookTaskType_Name(t *testing.T) { | ||||||
| 	assert.Equal(t, "gogs", GOGS.Name()) | 	assert.Equal(t, "gogs", GOGS.Name()) | ||||||
| 	assert.Equal(t, "slack", SLACK.Name()) | 	assert.Equal(t, "slack", SLACK.Name()) | ||||||
| 	assert.Equal(t, "gitea", GITEA.Name()) | 	assert.Equal(t, "gitea", GITEA.Name()) | ||||||
|  | 	assert.Equal(t, "telegram", TELEGRAM.Name()) | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestIsValidHookTaskType(t *testing.T) { | func TestIsValidHookTaskType(t *testing.T) { | ||||||
| 	assert.True(t, IsValidHookTaskType("gogs")) | 	assert.True(t, IsValidHookTaskType("gogs")) | ||||||
| 	assert.True(t, IsValidHookTaskType("slack")) | 	assert.True(t, IsValidHookTaskType("slack")) | ||||||
| 	assert.True(t, IsValidHookTaskType("gitea")) | 	assert.True(t, IsValidHookTaskType("gitea")) | ||||||
|  | 	assert.True(t, IsValidHookTaskType("telegram")) | ||||||
| 	assert.False(t, IsValidHookTaskType("invalid")) | 	assert.False(t, IsValidHookTaskType("invalid")) | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -263,6 +263,18 @@ func (f *NewDingtalkHookForm) Validate(ctx *macaron.Context, errs binding.Errors | |||||||
| 	return validate(errs, ctx.Data, f, ctx.Locale) | 	return validate(errs, ctx.Data, f, ctx.Locale) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // NewTelegramHookForm form for creating telegram hook | ||||||
|  | type NewTelegramHookForm struct { | ||||||
|  | 	BotToken string `binding:"Required"` | ||||||
|  | 	ChatID   string `binding:"Required"` | ||||||
|  | 	WebhookForm | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Validate validates the fields | ||||||
|  | func (f *NewTelegramHookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | ||||||
|  | 	return validate(errs, ctx.Data, f, ctx.Locale) | ||||||
|  | } | ||||||
|  |  | ||||||
| // .___ | // .___ | ||||||
| // |   | ______ ________ __   ____ | // |   | ______ ________ __   ____ | ||||||
| // |   |/  ___//  ___/  |  \_/ __ \ | // |   |/  ___//  ___/  |  \_/ __ \ | ||||||
|   | |||||||
| @@ -25,6 +25,6 @@ func newWebhookService() { | |||||||
| 	Webhook.QueueLength = sec.Key("QUEUE_LENGTH").MustInt(1000) | 	Webhook.QueueLength = sec.Key("QUEUE_LENGTH").MustInt(1000) | ||||||
| 	Webhook.DeliverTimeout = sec.Key("DELIVER_TIMEOUT").MustInt(5) | 	Webhook.DeliverTimeout = sec.Key("DELIVER_TIMEOUT").MustInt(5) | ||||||
| 	Webhook.SkipTLSVerify = sec.Key("SKIP_TLS_VERIFY").MustBool() | 	Webhook.SkipTLSVerify = sec.Key("SKIP_TLS_VERIFY").MustBool() | ||||||
| 	Webhook.Types = []string{"gitea", "gogs", "slack", "discord", "dingtalk"} | 	Webhook.Types = []string{"gitea", "gogs", "slack", "discord", "dingtalk", "telegram"} | ||||||
| 	Webhook.PagingNum = sec.Key("PAGING_NUM").MustInt(10) | 	Webhook.PagingNum = sec.Key("PAGING_NUM").MustInt(10) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1211,6 +1211,7 @@ settings.slack_domain = Domain | |||||||
| settings.slack_channel = Channel | settings.slack_channel = Channel | ||||||
| settings.add_discord_hook_desc = Integrate <a href="%s">Discord</a> into your repository. | settings.add_discord_hook_desc = Integrate <a href="%s">Discord</a> into your repository. | ||||||
| settings.add_dingtalk_hook_desc = Integrate <a href="%s">Dingtalk</a> into your repository. | settings.add_dingtalk_hook_desc = Integrate <a href="%s">Dingtalk</a> into your repository. | ||||||
|  | settings.add_telegram_hook_desc = Integrate <a href="%s">Telegram</a> into your repository. | ||||||
| settings.deploy_keys = Deploy Keys | settings.deploy_keys = Deploy Keys | ||||||
| settings.add_deploy_key = Add Deploy Key | settings.add_deploy_key = Add Deploy Key | ||||||
| settings.deploy_key_desc = Deploy keys have read-only pull access to the repository. | settings.deploy_key_desc = Deploy keys have read-only pull access to the repository. | ||||||
| @@ -1258,6 +1259,8 @@ settings.choose_branch = Choose a branch… | |||||||
| settings.no_protected_branch = There are no protected branches. | settings.no_protected_branch = There are no protected branches. | ||||||
| settings.edit_protected_branch = Edit | settings.edit_protected_branch = Edit | ||||||
| settings.protected_branch_required_approvals_min = Required approvals cannot be negative. | settings.protected_branch_required_approvals_min = Required approvals cannot be negative. | ||||||
|  | settings.bot_token = Bot Token | ||||||
|  | settings.chat_id = Chat ID | ||||||
| settings.archive.button = Archive Repo | settings.archive.button = Archive Repo | ||||||
| settings.archive.header = Archive This Repo | settings.archive.header = Archive This Repo | ||||||
| settings.archive.text = Archiving the repo will make it entirely read-only. It is hidden from the dashboard, cannot be committed to and no issues or pull-requests can be created. | settings.archive.text = Archiving the repo will make it entirely read-only. It is hidden from the dashboard, cannot be committed to and no issues or pull-requests can be created. | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								public/img/telegram.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/img/telegram.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 12 KiB | 
| @@ -331,6 +331,55 @@ func DingtalkHooksNewPost(ctx *context.Context, form auth.NewDingtalkHookForm) { | |||||||
| 	ctx.Redirect(orCtx.Link) | 	ctx.Redirect(orCtx.Link) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // TelegramHooksNewPost response for creating telegram hook | ||||||
|  | func TelegramHooksNewPost(ctx *context.Context, form auth.NewTelegramHookForm) { | ||||||
|  | 	ctx.Data["Title"] = ctx.Tr("repo.settings") | ||||||
|  | 	ctx.Data["PageIsSettingsHooks"] = true | ||||||
|  | 	ctx.Data["PageIsSettingsHooksNew"] = true | ||||||
|  | 	ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}} | ||||||
|  |  | ||||||
|  | 	orCtx, err := getOrgRepoCtx(ctx) | ||||||
|  | 	if err != nil { | ||||||
|  | 		ctx.ServerError("getOrgRepoCtx", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if ctx.HasError() { | ||||||
|  | 		ctx.HTML(200, orCtx.NewTemplate) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	meta, err := json.Marshal(&models.TelegramMeta{ | ||||||
|  | 		BotToken: form.BotToken, | ||||||
|  | 		ChatID:   form.ChatID, | ||||||
|  | 	}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		ctx.ServerError("Marshal", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	w := &models.Webhook{ | ||||||
|  | 		RepoID:       orCtx.RepoID, | ||||||
|  | 		URL:          fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s", form.BotToken, form.ChatID), | ||||||
|  | 		ContentType:  models.ContentTypeJSON, | ||||||
|  | 		HookEvent:    ParseHookEvent(form.WebhookForm), | ||||||
|  | 		IsActive:     form.Active, | ||||||
|  | 		HookTaskType: models.TELEGRAM, | ||||||
|  | 		Meta:         string(meta), | ||||||
|  | 		OrgID:        orCtx.OrgID, | ||||||
|  | 	} | ||||||
|  | 	if err := w.UpdateEvent(); err != nil { | ||||||
|  | 		ctx.ServerError("UpdateEvent", err) | ||||||
|  | 		return | ||||||
|  | 	} else if err := models.CreateWebhook(w); err != nil { | ||||||
|  | 		ctx.ServerError("CreateWebhook", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success")) | ||||||
|  | 	ctx.Redirect(orCtx.Link) | ||||||
|  | } | ||||||
|  |  | ||||||
| // SlackHooksNewPost response for creating slack hook | // SlackHooksNewPost response for creating slack hook | ||||||
| func SlackHooksNewPost(ctx *context.Context, form auth.NewSlackHookForm) { | func SlackHooksNewPost(ctx *context.Context, form auth.NewSlackHookForm) { | ||||||
| 	ctx.Data["Title"] = ctx.Tr("repo.settings") | 	ctx.Data["Title"] = ctx.Tr("repo.settings") | ||||||
| @@ -421,6 +470,8 @@ func checkWebhook(ctx *context.Context) (*orgRepoCtx, *models.Webhook) { | |||||||
| 		ctx.Data["SlackHook"] = w.GetSlackHook() | 		ctx.Data["SlackHook"] = w.GetSlackHook() | ||||||
| 	case models.DISCORD: | 	case models.DISCORD: | ||||||
| 		ctx.Data["DiscordHook"] = w.GetDiscordHook() | 		ctx.Data["DiscordHook"] = w.GetDiscordHook() | ||||||
|  | 	case models.TELEGRAM: | ||||||
|  | 		ctx.Data["TelegramHook"] = w.GetTelegramHook() | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	ctx.Data["History"], err = w.History(1) | 	ctx.Data["History"], err = w.History(1) | ||||||
| @@ -647,6 +698,46 @@ func DingtalkHooksEditPost(ctx *context.Context, form auth.NewDingtalkHookForm) | |||||||
| 	ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID)) | 	ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID)) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // TelegramHooksEditPost response for editing discord hook | ||||||
|  | func TelegramHooksEditPost(ctx *context.Context, form auth.NewTelegramHookForm) { | ||||||
|  | 	ctx.Data["Title"] = ctx.Tr("repo.settings") | ||||||
|  | 	ctx.Data["PageIsSettingsHooks"] = true | ||||||
|  | 	ctx.Data["PageIsSettingsHooksEdit"] = true | ||||||
|  |  | ||||||
|  | 	orCtx, w := checkWebhook(ctx) | ||||||
|  | 	if ctx.Written() { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	ctx.Data["Webhook"] = w | ||||||
|  |  | ||||||
|  | 	if ctx.HasError() { | ||||||
|  | 		ctx.HTML(200, orCtx.NewTemplate) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	meta, err := json.Marshal(&models.TelegramMeta{ | ||||||
|  | 		BotToken: form.BotToken, | ||||||
|  | 		ChatID:   form.ChatID, | ||||||
|  | 	}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		ctx.ServerError("Marshal", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	w.Meta = string(meta) | ||||||
|  | 	w.URL = fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s", form.BotToken, form.ChatID) | ||||||
|  | 	w.HookEvent = ParseHookEvent(form.WebhookForm) | ||||||
|  | 	w.IsActive = form.Active | ||||||
|  | 	if err := w.UpdateEvent(); err != nil { | ||||||
|  | 		ctx.ServerError("UpdateEvent", err) | ||||||
|  | 		return | ||||||
|  | 	} else if err := models.UpdateWebhook(w); err != nil { | ||||||
|  | 		ctx.ServerError("UpdateWebhook", err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success")) | ||||||
|  | 	ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID)) | ||||||
|  | } | ||||||
|  |  | ||||||
| // TestWebhook test if web hook is work fine | // TestWebhook test if web hook is work fine | ||||||
| func TestWebhook(ctx *context.Context) { | func TestWebhook(ctx *context.Context) { | ||||||
| 	hookID := ctx.ParamsInt64(":id") | 	hookID := ctx.ParamsInt64(":id") | ||||||
|   | |||||||
| @@ -559,12 +559,14 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||||
| 					m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) | 					m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) | ||||||
| 					m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) | 					m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) | ||||||
| 					m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost) | 					m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost) | ||||||
|  | 					m.Post("/telegram/new", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksNewPost) | ||||||
| 					m.Get("/:id", repo.WebHooksEdit) | 					m.Get("/:id", repo.WebHooksEdit) | ||||||
| 					m.Post("/gitea/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost) | 					m.Post("/gitea/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost) | ||||||
| 					m.Post("/gogs/:id", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksEditPost) | 					m.Post("/gogs/:id", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksEditPost) | ||||||
| 					m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost) | 					m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost) | ||||||
| 					m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost) | 					m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost) | ||||||
| 					m.Post("/dingtalk/:id", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost) | 					m.Post("/dingtalk/:id", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost) | ||||||
|  | 					m.Post("/telegram/:id", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksEditPost) | ||||||
| 				}) | 				}) | ||||||
|  |  | ||||||
| 				m.Route("/delete", "GET,POST", org.SettingsDelete) | 				m.Route("/delete", "GET,POST", org.SettingsDelete) | ||||||
| @@ -612,6 +614,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||||
| 				m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) | 				m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) | ||||||
| 				m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) | 				m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) | ||||||
| 				m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost) | 				m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost) | ||||||
|  | 				m.Post("/telegram/new", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksNewPost) | ||||||
| 				m.Get("/:id", repo.WebHooksEdit) | 				m.Get("/:id", repo.WebHooksEdit) | ||||||
| 				m.Post("/:id/test", repo.TestWebhook) | 				m.Post("/:id/test", repo.TestWebhook) | ||||||
| 				m.Post("/gitea/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost) | 				m.Post("/gitea/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost) | ||||||
| @@ -619,6 +622,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||||
| 				m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost) | 				m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost) | ||||||
| 				m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost) | 				m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost) | ||||||
| 				m.Post("/dingtalk/:id", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost) | 				m.Post("/dingtalk/:id", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost) | ||||||
|  | 				m.Post("/telegram/:id", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksEditPost) | ||||||
|  |  | ||||||
| 				m.Group("/git", func() { | 				m.Group("/git", func() { | ||||||
| 					m.Get("", repo.GitHooks) | 					m.Get("", repo.GitHooks) | ||||||
|   | |||||||
| @@ -19,6 +19,8 @@ | |||||||
| 							<img class="img-13" src="{{AppSubUrl}}/img/discord.png"> | 							<img class="img-13" src="{{AppSubUrl}}/img/discord.png"> | ||||||
| 						{{else if eq .HookType "dingtalk"}} | 						{{else if eq .HookType "dingtalk"}} | ||||||
| 							<img class="img-13" src="{{AppSubUrl}}/img/dingtalk.png"> | 							<img class="img-13" src="{{AppSubUrl}}/img/dingtalk.png"> | ||||||
|  | 						{{else if eq .HookType "telegram"}} | ||||||
|  | 							<img class="img-13" src="{{AppSubUrl}}/img/telegram.png"> | ||||||
| 						{{end}} | 						{{end}} | ||||||
| 					</div> | 					</div> | ||||||
| 				</h4> | 				</h4> | ||||||
| @@ -28,6 +30,7 @@ | |||||||
| 					{{template "repo/settings/webhook/slack" .}} | 					{{template "repo/settings/webhook/slack" .}} | ||||||
| 					{{template "repo/settings/webhook/discord" .}} | 					{{template "repo/settings/webhook/discord" .}} | ||||||
| 					{{template "repo/settings/webhook/dingtalk" .}} | 					{{template "repo/settings/webhook/dingtalk" .}} | ||||||
|  | 					{{template "repo/settings/webhook/telegram" .}} | ||||||
| 				</div> | 				</div> | ||||||
|  |  | ||||||
| 				{{template "repo/settings/webhook/history" .}} | 				{{template "repo/settings/webhook/history" .}} | ||||||
|   | |||||||
| @@ -20,6 +20,9 @@ | |||||||
| 				<a class="item" href="{{.BaseLink}}/dingtalk/new"> | 				<a class="item" href="{{.BaseLink}}/dingtalk/new"> | ||||||
| 					<img class="img-10" src="{{AppSubUrl}}/img/dingtalk.ico">Dingtalk | 					<img class="img-10" src="{{AppSubUrl}}/img/dingtalk.ico">Dingtalk | ||||||
| 				</a> | 				</a> | ||||||
|  | 				<a class="item" href="{{.BaseLink}}/telegram/new"> | ||||||
|  | 					<img class="img-10" src="{{AppSubUrl}}/img/telegram.png">Telegram | ||||||
|  | 				</a> | ||||||
| 			</div> | 			</div> | ||||||
| 		</div> | 		</div> | ||||||
| 	</div> | 	</div> | ||||||
|   | |||||||
| @@ -17,6 +17,8 @@ | |||||||
| 					<img class="img-13" src="{{AppSubUrl}}/img/discord.png"> | 					<img class="img-13" src="{{AppSubUrl}}/img/discord.png"> | ||||||
| 				{{else if eq .HookType "dingtalk"}} | 				{{else if eq .HookType "dingtalk"}} | ||||||
| 					<img class="img-13" src="{{AppSubUrl}}/img/dingtalk.ico"> | 					<img class="img-13" src="{{AppSubUrl}}/img/dingtalk.ico"> | ||||||
|  | 				{{else if eq .HookType "telegram"}} | ||||||
|  | 					<img class="img-13" src="{{AppSubUrl}}/img/telegram.png"> | ||||||
| 				{{end}} | 				{{end}} | ||||||
| 			</div> | 			</div> | ||||||
| 		</h4> | 		</h4> | ||||||
| @@ -26,6 +28,7 @@ | |||||||
| 			{{template "repo/settings/webhook/slack" .}} | 			{{template "repo/settings/webhook/slack" .}} | ||||||
| 			{{template "repo/settings/webhook/discord" .}} | 			{{template "repo/settings/webhook/discord" .}} | ||||||
| 			{{template "repo/settings/webhook/dingtalk" .}} | 			{{template "repo/settings/webhook/dingtalk" .}} | ||||||
|  | 			{{template "repo/settings/webhook/telegram" .}} | ||||||
| 		</div> | 		</div> | ||||||
|  |  | ||||||
| 		{{template "repo/settings/webhook/history" .}} | 		{{template "repo/settings/webhook/history" .}} | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								templates/repo/settings/webhook/telegram.tmpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								templates/repo/settings/webhook/telegram.tmpl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | {{if eq .HookType "telegram"}} | ||||||
|  | 	<p>{{.i18n.Tr "repo.settings.add_telegram_hook_desc" "https://core.telegram.org/bots" | Str2html}}</p> | ||||||
|  | 	<form class="ui form" action="{{.BaseLink}}/telegram/{{or .Webhook.ID "new"}}" method="post"> | ||||||
|  | 		{{.CsrfTokenHtml}} | ||||||
|  | 		<div class="required field {{if .Err_BotToken}}error{{end}}"> | ||||||
|  | 			<label for="bot_token">{{.i18n.Tr "repo.settings.bot_token"}}</label> | ||||||
|  | 			<input id="bot_token" name="bot_token" type="text" value="{{.TelegramHook.BotToken}}" autofocus required> | ||||||
|  | 		</div> | ||||||
|  |     <div class="required field {{if .Err_ChatID}}error{{end}}"> | ||||||
|  |       <label for="chat_id">{{.i18n.Tr "repo.settings.chat_id"}}</label> | ||||||
|  |       <input id="chat_id" name="chat_id" type="text" value="{{.TelegramHook.ChatID}}" required> | ||||||
|  |     </div> | ||||||
|  | 		{{template "repo/settings/webhook/settings" .}} | ||||||
|  | 	</form> | ||||||
|  | {{end}} | ||||||
		Reference in New Issue
	
	Block a user