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.

171 lines
4.0 KiB

  1. // This package parse a http request from datatables (jQuery plugin) to a friendly structure
  2. // More details in https://github.com/saulortega/datatables
  3. // import "github.com/saulortega/datatables"
  4. package datatables
  5. import (
  6. "errors"
  7. "net/http"
  8. "regexp"
  9. "strconv"
  10. "strings"
  11. )
  12. type Column struct {
  13. Data string
  14. Name string
  15. Index int
  16. Orderable bool
  17. Searchable bool
  18. SearchValue string
  19. SearchRegex bool
  20. }
  21. type Order struct {
  22. Column Column
  23. Dir string
  24. }
  25. type Filter struct {
  26. Draw int
  27. Start int
  28. Length int
  29. Order []Order
  30. Columns []Column
  31. SearchValue string
  32. SearchRegex bool
  33. }
  34. func Parse(r *http.Request) (Filter, error) {
  35. return parse(r)
  36. }
  37. func MustParse(r *http.Request) Filter {
  38. f, err := parse(r)
  39. if err != nil {
  40. panic(err)
  41. }
  42. return f
  43. }
  44. func parse(r *http.Request) (Filter, error) {
  45. var E error
  46. var F = Filter{
  47. Order: []Order{},
  48. Columns: []Column{},
  49. }
  50. var errores = []string{}
  51. var mapColsTmp = make(map[int]map[string]string)
  52. var mapOrdsTmp = make(map[int]map[string]string)
  53. for ll, v := range r.Form {
  54. if regexp.MustCompile(`^columns\[`).MatchString(ll) {
  55. a := regexp.MustCompile(`^columns\[([0-9]+)\]\[`).ReplaceAllString(ll, "$1-")
  56. a = regexp.MustCompile(`search\]\[(value|regex)`).ReplaceAllString(a, "search$1")
  57. a = regexp.MustCompile(`\]$`).ReplaceAllString(a, "")
  58. p := strings.Split(a, "-")
  59. i, er := strconv.Atoi(p[0])
  60. if er != nil {
  61. errores = append(errores, er.Error())
  62. continue
  63. }
  64. if _, ok := mapColsTmp[i]; !ok {
  65. mapColsTmp[i] = make(map[string]string)
  66. }
  67. mapColsTmp[i][p[1]] = v[0]
  68. } else if regexp.MustCompile(`^order\[`).MatchString(ll) {
  69. a := regexp.MustCompile(`^order\[([0-9]+)\]\[`).ReplaceAllString(ll, "$1-")
  70. a = regexp.MustCompile(`\]$`).ReplaceAllString(a, "")
  71. p := strings.Split(a, "-")
  72. i, er := strconv.Atoi(p[0])
  73. if er != nil {
  74. errores = append(errores, er.Error())
  75. continue
  76. }
  77. if _, ok := mapOrdsTmp[i]; !ok {
  78. mapOrdsTmp[i] = make(map[string]string)
  79. }
  80. mapOrdsTmp[i][p[1]] = v[0]
  81. } else if ll == "search[value]" {
  82. F.SearchValue = strings.TrimSpace(v[0])
  83. } else if ll == "search[regex]" {
  84. F.SearchRegex, E = strconv.ParseBool(v[0])
  85. if E != nil {
  86. errores = append(errores, E.Error())
  87. }
  88. } else if ll == "start" {
  89. F.Start, E = strconv.Atoi(v[0])
  90. if E != nil {
  91. errores = append(errores, E.Error())
  92. }
  93. } else if ll == "length" {
  94. F.Length, E = strconv.Atoi(v[0])
  95. if E != nil {
  96. errores = append(errores, E.Error())
  97. }
  98. } else if ll == "draw" {
  99. F.Draw, E = strconv.Atoi(v[0])
  100. if E != nil {
  101. errores = append(errores, E.Error())
  102. }
  103. }
  104. }
  105. for i := 0; i < len(mapColsTmp); i++ {
  106. c := Column{Index: i}
  107. c.Data = strings.TrimSpace(mapColsTmp[i]["data"])
  108. c.Name = strings.TrimSpace(mapColsTmp[i]["name"])
  109. c.Orderable, E = strconv.ParseBool(mapColsTmp[i]["orderable"])
  110. if E != nil {
  111. errores = append(errores, E.Error())
  112. }
  113. c.Searchable, E = strconv.ParseBool(mapColsTmp[i]["searchable"])
  114. if E != nil {
  115. errores = append(errores, E.Error())
  116. }
  117. c.SearchValue = strings.TrimSpace(mapColsTmp[i]["searchvalue"])
  118. c.SearchRegex, E = strconv.ParseBool(mapColsTmp[i]["searchregex"])
  119. if E != nil {
  120. errores = append(errores, E.Error())
  121. }
  122. F.Columns = append(F.Columns, c)
  123. }
  124. for i := 0; i < len(mapOrdsTmp); i++ {
  125. dir := strings.ToUpper(mapOrdsTmp[i]["dir"])
  126. ic, er := strconv.Atoi(mapOrdsTmp[i]["column"])
  127. if er != nil || (dir != "ASC" && dir != "DESC") {
  128. if er != nil {
  129. errores = append(errores, er.Error())
  130. } else {
  131. errores = append(errores, "dir invalid: «"+dir+"»")
  132. }
  133. continue
  134. }
  135. o := Order{Dir: dir}
  136. for _, c := range F.Columns {
  137. if c.Index == ic {
  138. o.Column = c
  139. break
  140. }
  141. }
  142. if o.Column == (Column{}) {
  143. errores = append(errores, "column with index "+strconv.Itoa(ic)+" not found")
  144. continue
  145. }
  146. F.Order = append(F.Order, o)
  147. }
  148. if len(errores) > 0 {
  149. E = errors.New(strings.Join(errores, "; "))
  150. }
  151. return F, E
  152. }