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.

313 lines
6.5 KiB

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