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