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.

285 lines
7.4 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
  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. "bytes"
  7. "crypto/md5"
  8. "encoding/hex"
  9. "encoding/json"
  10. "fmt"
  11. "math"
  12. "strings"
  13. "time"
  14. )
  15. // Encode string to md5 hex value
  16. func EncodeMd5(str string) string {
  17. m := md5.New()
  18. m.Write([]byte(str))
  19. return hex.EncodeToString(m.Sum(nil))
  20. }
  21. // Seconds-based time units
  22. const (
  23. Minute = 60
  24. Hour = 60 * Minute
  25. Day = 24 * Hour
  26. Week = 7 * Day
  27. Month = 30 * Day
  28. Year = 12 * Month
  29. )
  30. // TimeSince calculates the time interval and generate user-friendly string.
  31. func TimeSince(then time.Time) string {
  32. now := time.Now()
  33. lbl := "ago"
  34. diff := now.Unix() - then.Unix()
  35. if then.After(now) {
  36. lbl = "from now"
  37. diff = then.Unix() - now.Unix()
  38. }
  39. switch {
  40. case diff <= 0:
  41. return "now"
  42. case diff <= 2:
  43. return fmt.Sprintf("1 second %s", lbl)
  44. case diff < 1*Minute:
  45. return fmt.Sprintf("%d seconds %s", diff, lbl)
  46. case diff < 2*Minute:
  47. return fmt.Sprintf("1 minute %s", lbl)
  48. case diff < 1*Hour:
  49. return fmt.Sprintf("%d minutes %s", diff/Minute, lbl)
  50. case diff < 2*Hour:
  51. return fmt.Sprintf("1 hour %s", lbl)
  52. case diff < 1*Day:
  53. return fmt.Sprintf("%d hours %s", diff/Hour, lbl)
  54. case diff < 2*Day:
  55. return fmt.Sprintf("1 day %s", lbl)
  56. case diff < 1*Week:
  57. return fmt.Sprintf("%d days %s", diff/Day, lbl)
  58. case diff < 2*Week:
  59. return fmt.Sprintf("1 week %s", lbl)
  60. case diff < 1*Month:
  61. return fmt.Sprintf("%d weeks %s", diff/Week, lbl)
  62. case diff < 2*Month:
  63. return fmt.Sprintf("1 month %s", lbl)
  64. case diff < 1*Year:
  65. return fmt.Sprintf("%d months %s", diff/Month, lbl)
  66. case diff < 18*Month:
  67. return fmt.Sprintf("1 year %s", lbl)
  68. }
  69. return then.String()
  70. }
  71. const (
  72. Byte = 1
  73. KByte = Byte * 1024
  74. MByte = KByte * 1024
  75. GByte = MByte * 1024
  76. TByte = GByte * 1024
  77. PByte = TByte * 1024
  78. EByte = PByte * 1024
  79. )
  80. var bytesSizeTable = map[string]uint64{
  81. "b": Byte,
  82. "kb": KByte,
  83. "mb": MByte,
  84. "gb": GByte,
  85. "tb": TByte,
  86. "pb": PByte,
  87. "eb": EByte,
  88. }
  89. func logn(n, b float64) float64 {
  90. return math.Log(n) / math.Log(b)
  91. }
  92. func humanateBytes(s uint64, base float64, sizes []string) string {
  93. if s < 10 {
  94. return fmt.Sprintf("%dB", s)
  95. }
  96. e := math.Floor(logn(float64(s), base))
  97. suffix := sizes[int(e)]
  98. val := float64(s) / math.Pow(base, math.Floor(e))
  99. f := "%.0f"
  100. if val < 10 {
  101. f = "%.1f"
  102. }
  103. return fmt.Sprintf(f+"%s", val, suffix)
  104. }
  105. // FileSize calculates the file size and generate user-friendly string.
  106. func FileSize(s int64) string {
  107. sizes := []string{"B", "KB", "MB", "GB", "TB", "PB", "EB"}
  108. return humanateBytes(uint64(s), 1024, sizes)
  109. }
  110. // Subtract deals with subtraction of all types of number.
  111. func Subtract(left interface{}, right interface{}) interface{} {
  112. var rleft, rright int64
  113. var fleft, fright float64
  114. var isInt bool = true
  115. switch left.(type) {
  116. case int:
  117. rleft = int64(left.(int))
  118. case int8:
  119. rleft = int64(left.(int8))
  120. case int16:
  121. rleft = int64(left.(int16))
  122. case int32:
  123. rleft = int64(left.(int32))
  124. case int64:
  125. rleft = left.(int64)
  126. case float32:
  127. fleft = float64(left.(float32))
  128. isInt = false
  129. case float64:
  130. fleft = left.(float64)
  131. isInt = false
  132. }
  133. switch right.(type) {
  134. case int:
  135. rright = int64(right.(int))
  136. case int8:
  137. rright = int64(right.(int8))
  138. case int16:
  139. rright = int64(right.(int16))
  140. case int32:
  141. rright = int64(right.(int32))
  142. case int64:
  143. rright = right.(int64)
  144. case float32:
  145. fright = float64(left.(float32))
  146. isInt = false
  147. case float64:
  148. fleft = left.(float64)
  149. isInt = false
  150. }
  151. if isInt {
  152. return rleft - rright
  153. } else {
  154. return fleft + float64(rleft) - (fright + float64(rright))
  155. }
  156. }
  157. // DateFormat pattern rules.
  158. var datePatterns = []string{
  159. // year
  160. "Y", "2006", // A full numeric representation of a year, 4 digits Examples: 1999 or 2003
  161. "y", "06", //A two digit representation of a year Examples: 99 or 03
  162. // month
  163. "m", "01", // Numeric representation of a month, with leading zeros 01 through 12
  164. "n", "1", // Numeric representation of a month, without leading zeros 1 through 12
  165. "M", "Jan", // A short textual representation of a month, three letters Jan through Dec
  166. "F", "January", // A full textual representation of a month, such as January or March January through December
  167. // day
  168. "d", "02", // Day of the month, 2 digits with leading zeros 01 to 31
  169. "j", "2", // Day of the month without leading zeros 1 to 31
  170. // week
  171. "D", "Mon", // A textual representation of a day, three letters Mon through Sun
  172. "l", "Monday", // A full textual representation of the day of the week Sunday through Saturday
  173. // time
  174. "g", "3", // 12-hour format of an hour without leading zeros 1 through 12
  175. "G", "15", // 24-hour format of an hour without leading zeros 0 through 23
  176. "h", "03", // 12-hour format of an hour with leading zeros 01 through 12
  177. "H", "15", // 24-hour format of an hour with leading zeros 00 through 23
  178. "a", "pm", // Lowercase Ante meridiem and Post meridiem am or pm
  179. "A", "PM", // Uppercase Ante meridiem and Post meridiem AM or PM
  180. "i", "04", // Minutes with leading zeros 00 to 59
  181. "s", "05", // Seconds, with leading zeros 00 through 59
  182. // time zone
  183. "T", "MST",
  184. "P", "-07:00",
  185. "O", "-0700",
  186. // RFC 2822
  187. "r", time.RFC1123Z,
  188. }
  189. // Parse Date use PHP time format.
  190. func DateParse(dateString, format string) (time.Time, error) {
  191. replacer := strings.NewReplacer(datePatterns...)
  192. format = replacer.Replace(format)
  193. return time.ParseInLocation(format, dateString, time.Local)
  194. }
  195. // Date takes a PHP like date func to Go's time format.
  196. func DateFormat(t time.Time, format string) string {
  197. replacer := strings.NewReplacer(datePatterns...)
  198. format = replacer.Replace(format)
  199. return t.Format(format)
  200. }
  201. type Actioner interface {
  202. GetOpType() int
  203. GetActUserName() string
  204. GetRepoName() string
  205. GetContent() string
  206. }
  207. // ActionIcon accepts a int that represents action operation type
  208. // and returns a icon class name.
  209. func ActionIcon(opType int) string {
  210. switch opType {
  211. case 1: // Create repository.
  212. return "plus-circle"
  213. case 5: // Commit repository.
  214. return "arrow-circle-o-right"
  215. default:
  216. return "invalid type"
  217. }
  218. }
  219. const (
  220. TPL_CREATE_REPO = `<a href="/user/%s">%s</a> created repository <a href="/%s/%s">%s</a>`
  221. TPL_COMMIT_REPO = `<a href="/user/%s">%s</a> pushed to <a href="/%s/%s/tree/%s">%s</a> at <a href="/%s/%s">%s/%s</a>%s`
  222. TPL_COMMIT_REPO_LI = `<div><img id="gogs-user-avatar-commit" src="%s?s=16" alt="user-avatar" title="username"/> <a href="/%s/%s/commit/%s">%s</a> %s</div>`
  223. )
  224. // ActionDesc accepts int that represents action operation type
  225. // and returns the description.
  226. func ActionDesc(act Actioner, avatarLink string) string {
  227. actUserName := act.GetActUserName()
  228. repoName := act.GetRepoName()
  229. content := act.GetContent()
  230. switch act.GetOpType() {
  231. case 1: // Create repository.
  232. return fmt.Sprintf(TPL_CREATE_REPO, actUserName, actUserName, actUserName, repoName, repoName)
  233. case 5: // Commit repository.
  234. var commits [][]string
  235. if err := json.Unmarshal([]byte(content), &commits); err != nil {
  236. return err.Error()
  237. }
  238. buf := bytes.NewBuffer([]byte("\n"))
  239. for _, commit := range commits {
  240. buf.WriteString(fmt.Sprintf(TPL_COMMIT_REPO_LI, avatarLink, actUserName, repoName, commit[0], commit[0][:7], commit[1]) + "\n")
  241. }
  242. return fmt.Sprintf(TPL_COMMIT_REPO, actUserName, actUserName, actUserName, repoName, "master", "master", actUserName, repoName, actUserName, repoName,
  243. buf.String())
  244. default:
  245. return "invalid type"
  246. }
  247. }