tool.go 9.3 KB

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