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

270 lines
6.4 KiB

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