You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

helper.go 8.3 kB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
9 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package templates
  5. import (
  6. "container/list"
  7. "encoding/json"
  8. "fmt"
  9. "html/template"
  10. "mime"
  11. "path/filepath"
  12. "runtime"
  13. "strings"
  14. "time"
  15. "github.com/microcosm-cc/bluemonday"
  16. "golang.org/x/net/html/charset"
  17. "golang.org/x/text/transform"
  18. "gopkg.in/editorconfig/editorconfig-core-go.v1"
  19. "code.gitea.io/gitea/models"
  20. "code.gitea.io/gitea/modules/base"
  21. "code.gitea.io/gitea/modules/log"
  22. "code.gitea.io/gitea/modules/markdown"
  23. "code.gitea.io/gitea/modules/setting"
  24. )
  25. // NewFuncMap returns functions for injecting to templates
  26. func NewFuncMap() []template.FuncMap {
  27. return []template.FuncMap{map[string]interface{}{
  28. "GoVer": func() string {
  29. return strings.Title(runtime.Version())
  30. },
  31. "UseHTTPS": func() bool {
  32. return strings.HasPrefix(setting.AppURL, "https")
  33. },
  34. "AppName": func() string {
  35. return setting.AppName
  36. },
  37. "AppSubUrl": func() string {
  38. return setting.AppSubURL
  39. },
  40. "AppUrl": func() string {
  41. return setting.AppURL
  42. },
  43. "AppVer": func() string {
  44. return setting.AppVer
  45. },
  46. "AppBuiltWith": func() string {
  47. return setting.AppBuiltWith
  48. },
  49. "AppDomain": func() string {
  50. return setting.Domain
  51. },
  52. "DisableGravatar": func() bool {
  53. return setting.DisableGravatar
  54. },
  55. "ShowFooterTemplateLoadTime": func() bool {
  56. return setting.ShowFooterTemplateLoadTime
  57. },
  58. "LoadTimes": func(startTime time.Time) string {
  59. return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms"
  60. },
  61. "AvatarLink": base.AvatarLink,
  62. "Safe": Safe,
  63. "Sanitize": bluemonday.UGCPolicy().Sanitize,
  64. "Str2html": Str2html,
  65. "TimeSince": base.TimeSince,
  66. "RawTimeSince": base.RawTimeSince,
  67. "FileSize": base.FileSize,
  68. "Subtract": base.Subtract,
  69. "Add": func(a, b int) int {
  70. return a + b
  71. },
  72. "ActionIcon": ActionIcon,
  73. "DateFmtLong": func(t time.Time) string {
  74. return t.Format(time.RFC1123Z)
  75. },
  76. "DateFmtShort": func(t time.Time) string {
  77. return t.Format("Jan 02, 2006")
  78. },
  79. "List": List,
  80. "SubStr": func(str string, start, length int) string {
  81. if len(str) == 0 {
  82. return ""
  83. }
  84. end := start + length
  85. if length == -1 {
  86. end = len(str)
  87. }
  88. if len(str) < end {
  89. return str
  90. }
  91. return str[start:end]
  92. },
  93. "EllipsisString": base.EllipsisString,
  94. "DiffTypeToStr": DiffTypeToStr,
  95. "DiffLineTypeToStr": DiffLineTypeToStr,
  96. "Sha1": Sha1,
  97. "ShortSha": base.ShortSha,
  98. "MD5": base.EncodeMD5,
  99. "ActionContent2Commits": ActionContent2Commits,
  100. "EscapePound": func(str string) string {
  101. return strings.NewReplacer("%", "%25", "#", "%23", " ", "%20", "?", "%3F").Replace(str)
  102. },
  103. "RenderCommitMessage": RenderCommitMessage,
  104. "ThemeColorMetaTag": func() string {
  105. return setting.UI.ThemeColorMetaTag
  106. },
  107. "FilenameIsImage": func(filename string) bool {
  108. mimeType := mime.TypeByExtension(filepath.Ext(filename))
  109. return strings.HasPrefix(mimeType, "image/")
  110. },
  111. "TabSizeClass": func(ec *editorconfig.Editorconfig, filename string) string {
  112. if ec != nil {
  113. def := ec.GetDefinitionForFilename(filename)
  114. if def.TabWidth > 0 {
  115. return fmt.Sprintf("tab-size-%d", def.TabWidth)
  116. }
  117. }
  118. return "tab-size-8"
  119. },
  120. "SubJumpablePath": func(str string) []string {
  121. var path []string
  122. index := strings.LastIndex(str, "/")
  123. if index != -1 && index != len(str) {
  124. path = append(path, str[0:index+1])
  125. path = append(path, str[index+1:])
  126. } else {
  127. path = append(path, str)
  128. }
  129. return path
  130. },
  131. }}
  132. }
  133. // Safe render raw as HTML
  134. func Safe(raw string) template.HTML {
  135. return template.HTML(raw)
  136. }
  137. // Str2html render Markdown text to HTML
  138. func Str2html(raw string) template.HTML {
  139. return template.HTML(markdown.Sanitizer.Sanitize(raw))
  140. }
  141. // List traversings the list
  142. func List(l *list.List) chan interface{} {
  143. e := l.Front()
  144. c := make(chan interface{})
  145. go func() {
  146. for e != nil {
  147. c <- e.Value
  148. e = e.Next()
  149. }
  150. close(c)
  151. }()
  152. return c
  153. }
  154. // Sha1 returns sha1 sum of string
  155. func Sha1(str string) string {
  156. return base.EncodeSha1(str)
  157. }
  158. // ToUTF8WithErr converts content to UTF8 encoding
  159. func ToUTF8WithErr(content []byte) (string, error) {
  160. charsetLabel, err := base.DetectEncoding(content)
  161. if err != nil {
  162. return "", err
  163. } else if charsetLabel == "UTF-8" {
  164. return string(content), nil
  165. }
  166. encoding, _ := charset.Lookup(charsetLabel)
  167. if encoding == nil {
  168. return string(content), fmt.Errorf("Unknown encoding: %s", charsetLabel)
  169. }
  170. // If there is an error, we concatenate the nicely decoded part and the
  171. // original left over. This way we won't loose data.
  172. result, n, err := transform.String(encoding.NewDecoder(), string(content))
  173. if err != nil {
  174. result = result + string(content[n:])
  175. }
  176. return result, err
  177. }
  178. // ToUTF8 converts content to UTF8 encoding and ignore error
  179. func ToUTF8(content string) string {
  180. res, _ := ToUTF8WithErr([]byte(content))
  181. return res
  182. }
  183. // ReplaceLeft replaces all prefixes 'old' in 's' with 'new'.
  184. func ReplaceLeft(s, old, new string) string {
  185. oldLen, newLen, i, n := len(old), len(new), 0, 0
  186. for ; i < len(s) && strings.HasPrefix(s[i:], old); n++ {
  187. i += oldLen
  188. }
  189. // simple optimization
  190. if n == 0 {
  191. return s
  192. }
  193. // allocating space for the new string
  194. curLen := n*newLen + len(s[i:])
  195. replacement := make([]byte, curLen, curLen)
  196. j := 0
  197. for ; j < n*newLen; j += newLen {
  198. copy(replacement[j:j+newLen], new)
  199. }
  200. copy(replacement[j:], s[i:])
  201. return string(replacement)
  202. }
  203. // RenderCommitMessage renders commit message with XSS-safe and special links.
  204. func RenderCommitMessage(full bool, msg, urlPrefix string, metas map[string]string) template.HTML {
  205. cleanMsg := template.HTMLEscapeString(msg)
  206. fullMessage := string(markdown.RenderIssueIndexPattern([]byte(cleanMsg), urlPrefix, metas))
  207. msgLines := strings.Split(strings.TrimSpace(fullMessage), "\n")
  208. numLines := len(msgLines)
  209. if numLines == 0 {
  210. return template.HTML("")
  211. } else if !full {
  212. return template.HTML(msgLines[0])
  213. } else if numLines == 1 || (numLines >= 2 && len(msgLines[1]) == 0) {
  214. // First line is a header, standalone or followed by empty line
  215. header := fmt.Sprintf("<h3>%s</h3>", msgLines[0])
  216. if numLines >= 2 {
  217. fullMessage = header + fmt.Sprintf("\n<pre>%s</pre>", strings.Join(msgLines[2:], "\n"))
  218. } else {
  219. fullMessage = header
  220. }
  221. } else {
  222. // Non-standard git message, there is no header line
  223. fullMessage = fmt.Sprintf("<h4>%s</h4>", strings.Join(msgLines, "<br>"))
  224. }
  225. return template.HTML(fullMessage)
  226. }
  227. // Actioner describes an action
  228. type Actioner interface {
  229. GetOpType() int
  230. GetActUserName() string
  231. GetRepoUserName() string
  232. GetRepoName() string
  233. GetRepoPath() string
  234. GetRepoLink() string
  235. GetBranch() string
  236. GetContent() string
  237. GetCreate() time.Time
  238. GetIssueInfos() []string
  239. }
  240. // ActionIcon accepts a int that represents action operation type
  241. // and returns a icon class name.
  242. func ActionIcon(opType int) string {
  243. switch opType {
  244. case 1, 8: // Create and transfer repository
  245. return "repo"
  246. case 5, 9: // Commit repository
  247. return "git-commit"
  248. case 6: // Create issue
  249. return "issue-opened"
  250. case 7: // New pull request
  251. return "git-pull-request"
  252. case 10: // Comment issue
  253. return "comment-discussion"
  254. case 11: // Merge pull request
  255. return "git-merge"
  256. case 12, 14: // Close issue or pull request
  257. return "issue-closed"
  258. case 13, 15: // Reopen issue or pull request
  259. return "issue-reopened"
  260. default:
  261. return "invalid type"
  262. }
  263. }
  264. // ActionContent2Commits converts action content to push commits
  265. func ActionContent2Commits(act Actioner) *models.PushCommits {
  266. push := models.NewPushCommits()
  267. if err := json.Unmarshal([]byte(act.GetContent()), push); err != nil {
  268. log.Error(4, "json.Unmarshal:\n%s\nERROR: %v", act.GetContent(), err)
  269. }
  270. return push
  271. }
  272. // DiffTypeToStr returns diff type name
  273. func DiffTypeToStr(diffType int) string {
  274. diffTypes := map[int]string{
  275. 1: "add", 2: "modify", 3: "del", 4: "rename",
  276. }
  277. return diffTypes[diffType]
  278. }
  279. // DiffLineTypeToStr returns diff line type name
  280. func DiffLineTypeToStr(diffType int) string {
  281. switch diffType {
  282. case 2:
  283. return "add"
  284. case 3:
  285. return "del"
  286. case 4:
  287. return "tag"
  288. }
  289. return "same"
  290. }