template.go 5.6 KB

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