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