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.

template.go 6.9 kB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
9 years ago
9 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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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 template
  5. import (
  6. "container/list"
  7. "encoding/json"
  8. "fmt"
  9. "html/template"
  10. "runtime"
  11. "strings"
  12. "time"
  13. "golang.org/x/net/html/charset"
  14. "golang.org/x/text/transform"
  15. "github.com/gogits/gogs/models"
  16. "github.com/gogits/gogs/modules/base"
  17. "github.com/gogits/gogs/modules/markdown"
  18. "github.com/gogits/gogs/modules/setting"
  19. )
  20. func NewFuncMap() []template.FuncMap {
  21. return []template.FuncMap{map[string]interface{}{
  22. "GoVer": func() string {
  23. return strings.Title(runtime.Version())
  24. },
  25. "UseHTTPS": func() bool {
  26. return strings.HasPrefix(setting.AppUrl, "https")
  27. },
  28. "AppName": func() string {
  29. return setting.AppName
  30. },
  31. "AppSubUrl": func() string {
  32. return setting.AppSubUrl
  33. },
  34. "AppUrl": func() string {
  35. return setting.AppUrl
  36. },
  37. "AppVer": func() string {
  38. return setting.AppVer
  39. },
  40. "AppDomain": func() string {
  41. return setting.Domain
  42. },
  43. "DisableGravatar": func() bool {
  44. return setting.DisableGravatar
  45. },
  46. "LoadTimes": func(startTime time.Time) string {
  47. return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms"
  48. },
  49. "AvatarLink": base.AvatarLink,
  50. "Safe": Safe,
  51. "Str2html": Str2html,
  52. "TimeSince": base.TimeSince,
  53. "RawTimeSince": base.RawTimeSince,
  54. "FileSize": base.FileSize,
  55. "Subtract": base.Subtract,
  56. "Add": func(a, b int) int {
  57. return a + b
  58. },
  59. "ActionIcon": ActionIcon,
  60. "DateFmtLong": func(t time.Time) string {
  61. return t.Format(time.RFC1123Z)
  62. },
  63. "DateFmtShort": func(t time.Time) string {
  64. return t.Format("Jan 02, 2006")
  65. },
  66. "List": List,
  67. "Mail2Domain": func(mail string) string {
  68. if !strings.Contains(mail, "@") {
  69. return "try.gogs.io"
  70. }
  71. return strings.SplitN(mail, "@", 2)[1]
  72. },
  73. "SubStr": func(str string, start, length int) string {
  74. if len(str) == 0 {
  75. return ""
  76. }
  77. end := start + length
  78. if length == -1 {
  79. end = len(str)
  80. }
  81. if len(str) < end {
  82. return str
  83. }
  84. return str[start:end]
  85. },
  86. "DiffTypeToStr": DiffTypeToStr,
  87. "DiffLineTypeToStr": DiffLineTypeToStr,
  88. "Sha1": Sha1,
  89. "ShortSha": base.ShortSha,
  90. "MD5": base.EncodeMD5,
  91. "ActionContent2Commits": ActionContent2Commits,
  92. "ToUtf8": ToUtf8,
  93. "EscapePound": func(str string) string {
  94. return strings.Replace(strings.Replace(str, "%", "%25", -1), "#", "%23", -1)
  95. },
  96. "RenderCommitMessage": RenderCommitMessage,
  97. "ThemeColorMetaTag": func() string {
  98. return setting.ThemeColorMetaTag
  99. },
  100. }}
  101. }
  102. func Safe(raw string) template.HTML {
  103. return template.HTML(raw)
  104. }
  105. func Str2html(raw string) template.HTML {
  106. return template.HTML(markdown.Sanitizer.Sanitize(raw))
  107. }
  108. func Range(l int) []int {
  109. return make([]int, l)
  110. }
  111. func List(l *list.List) chan interface{} {
  112. e := l.Front()
  113. c := make(chan interface{})
  114. go func() {
  115. for e != nil {
  116. c <- e.Value
  117. e = e.Next()
  118. }
  119. close(c)
  120. }()
  121. return c
  122. }
  123. func Sha1(str string) string {
  124. return base.EncodeSha1(str)
  125. }
  126. func ToUtf8WithErr(content []byte) (error, string) {
  127. charsetLabel, err := base.DetectEncoding(content)
  128. if err != nil {
  129. return err, ""
  130. } else if charsetLabel == "UTF-8" {
  131. return nil, string(content)
  132. }
  133. encoding, _ := charset.Lookup(charsetLabel)
  134. if encoding == nil {
  135. return fmt.Errorf("Unknown encoding: %s", charsetLabel), string(content)
  136. }
  137. // If there is an error, we concatenate the nicely decoded part and the
  138. // original left over. This way we won't loose data.
  139. result, n, err := transform.String(encoding.NewDecoder(), string(content))
  140. if err != nil {
  141. result = result + string(content[n:])
  142. }
  143. return err, result
  144. }
  145. func ToUtf8(content string) string {
  146. _, res := ToUtf8WithErr([]byte(content))
  147. return res
  148. }
  149. // Replaces all prefixes 'old' in 's' with 'new'.
  150. func ReplaceLeft(s, old, new string) string {
  151. old_len, new_len, i, n := len(old), len(new), 0, 0
  152. for ; i < len(s) && strings.HasPrefix(s[i:], old); n += 1 {
  153. i += old_len
  154. }
  155. // simple optimization
  156. if n == 0 {
  157. return s
  158. }
  159. // allocating space for the new string
  160. newLen := n*new_len + len(s[i:])
  161. replacement := make([]byte, newLen, newLen)
  162. j := 0
  163. for ; j < n*new_len; j += new_len {
  164. copy(replacement[j:j+new_len], new)
  165. }
  166. copy(replacement[j:], s[i:])
  167. return string(replacement)
  168. }
  169. // RenderCommitMessage renders commit message with XSS-safe and special links.
  170. func RenderCommitMessage(full bool, msg, urlPrefix string, metas map[string]string) template.HTML {
  171. cleanMsg := template.HTMLEscapeString(msg)
  172. fullMessage := string(markdown.RenderIssueIndexPattern([]byte(cleanMsg), urlPrefix, metas))
  173. msgLines := strings.Split(strings.TrimSpace(fullMessage), "\n")
  174. numLines := len(msgLines)
  175. if numLines == 0 {
  176. return template.HTML("")
  177. } else if !full {
  178. return template.HTML(msgLines[0])
  179. } else if numLines == 1 || (numLines >= 2 && len(msgLines[1]) == 0) {
  180. // First line is a header, standalone or followed by empty line
  181. header := fmt.Sprintf("<h3>%s</h3>", msgLines[0])
  182. if numLines >= 2 {
  183. fullMessage = header + fmt.Sprintf("\n<pre>%s</pre>", strings.Join(msgLines[2:], "\n"))
  184. } else {
  185. fullMessage = header
  186. }
  187. } else {
  188. // Non-standard git message, there is no header line
  189. fullMessage = fmt.Sprintf("<h4>%s</h4>", strings.Join(msgLines, "<br>"))
  190. }
  191. return template.HTML(fullMessage)
  192. }
  193. type Actioner interface {
  194. GetOpType() int
  195. GetActUserName() string
  196. GetActEmail() string
  197. GetRepoUserName() string
  198. GetRepoName() string
  199. GetRepoPath() string
  200. GetRepoLink() string
  201. GetBranch() string
  202. GetContent() string
  203. GetCreate() time.Time
  204. GetIssueInfos() []string
  205. }
  206. // ActionIcon accepts a int that represents action operation type
  207. // and returns a icon class name.
  208. func ActionIcon(opType int) string {
  209. switch opType {
  210. case 1, 8: // Create and transfer repository
  211. return "repo"
  212. case 5, 9: // Commit repository
  213. return "git-commit"
  214. case 6: // Create issue
  215. return "issue-opened"
  216. case 7: // New pull request
  217. return "git-pull-request"
  218. case 10: // Comment issue
  219. return "comment"
  220. case 11: // Merge pull request
  221. return "git-merge"
  222. case 12, 14: // Close issue or pull request
  223. return "issue-closed"
  224. case 13, 15: // Reopen issue or pull request
  225. return "issue-reopened"
  226. default:
  227. return "invalid type"
  228. }
  229. }
  230. func ActionContent2Commits(act Actioner) *models.PushCommits {
  231. push := models.NewPushCommits()
  232. if err := json.Unmarshal([]byte(act.GetContent()), push); err != nil {
  233. return nil
  234. }
  235. return push
  236. }
  237. func DiffTypeToStr(diffType int) string {
  238. diffTypes := map[int]string{
  239. 1: "add", 2: "modify", 3: "del", 4: "rename",
  240. }
  241. return diffTypes[diffType]
  242. }
  243. func DiffLineTypeToStr(diffType int) string {
  244. switch diffType {
  245. case 2:
  246. return "add"
  247. case 3:
  248. return "del"
  249. case 4:
  250. return "tag"
  251. }
  252. return "same"
  253. }