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

tool.go 11 kB

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