-
Notifications
You must be signed in to change notification settings - Fork 0
/
handler.go
155 lines (126 loc) · 3.48 KB
/
handler.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package main
import (
"encoding/json"
"log"
"net/http"
"net/url"
"strings"
"time"
"github.com/jboverfelt/infest/models"
"github.com/markbates/pop"
)
// Error represents a handler error. It provides methods for a HTTP status
// code and embeds the built-in error interface.
type Error interface {
error
Status() int
}
// StatusError represents an error with an associated HTTP status code.
type StatusError struct {
Code int
Err error
}
// Allows StatusError to satisfy the error interface.
func (se StatusError) Error() string {
return se.Err.Error()
}
// Status returns our HTTP status code.
func (se StatusError) Status() int {
return se.Code
}
// Env represents handler dependencies
type Env struct {
DB *pop.Connection
}
// Handler represents an HTTP handler that can return errors
// and access dependencies in a type-safe way
type Handler struct {
*Env
h func(e *Env, w http.ResponseWriter, r *http.Request) error
}
// NewHandler allocates a new handler
func NewHandler(e *Env, handlerFunc func(e *Env, w http.ResponseWriter, r *http.Request) error) Handler {
return Handler{e, handlerFunc}
}
func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
err := h.h(h.Env, w, r)
if err != nil {
log.Printf("ERROR: %v", err)
switch e := err.(type) {
case Error:
// We can retrieve the status here and write out a specific
// HTTP status code.
log.Printf("HTTP %d - %s", e.Status(), e)
http.Error(w, e.Error(), e.Status())
default:
// Any error types we don't specifically look out for default
// to serving a HTTP 500
http.Error(w, http.StatusText(http.StatusInternalServerError),
http.StatusInternalServerError)
}
}
}
func all(e *Env, w http.ResponseWriter, r *http.Request) error {
var closures []models.Closure
params := r.URL.Query()
baseQuery := e.DB.PaginateFromParams(params)
addQueryParams(baseQuery, params)
err := baseQuery.All(&closures)
if err != nil {
return err
}
w.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(w).Encode(closures)
if err != nil {
return err
}
return nil
}
func addQueryParams(query *pop.Query, params url.Values) {
supportedParams := map[string]string{
"sort": params.Get("sort"),
"name": params.Get("name"),
"reason": params.Get("reason"),
"startDate": params.Get("startDate"),
"endDate": params.Get("endDate"),
}
if supportedParams["sort"] != "" {
addSort(query, supportedParams["sort"])
}
if supportedParams["name"] != "" {
query.Where("name = ?", supportedParams["name"])
}
if supportedParams["reason"] != "" {
query.Where("reason LIKE '%' || ? || '%'", supportedParams["reason"])
}
if supportedParams["startDate"] != "" {
tmpTime, err := time.Parse(closureTimeFmt, supportedParams["startDate"])
if err == nil {
query.Where("closuredate >= ?", tmpTime)
}
}
if supportedParams["endDate"] != "" {
tmpTime, err := time.Parse(closureTimeFmt, supportedParams["endDate"])
if err == nil {
query.Where("closuredate <= ?", tmpTime)
}
}
}
func addSort(query *pop.Query, sortVal string) {
supportedSortFields := map[string]bool{
"name": true,
"address": true,
"reason": true,
"closuredate": true,
"reopendate": true,
"reopencomments": true,
}
parts := strings.Split(sortVal, ".")
if len(parts) == 2 {
if strings.ToLower(parts[1]) == "asc" || strings.ToLower(parts[1]) == "desc" {
if _, ok := supportedSortFields[parts[0]]; ok {
query.Order(strings.Join(parts, " "))
}
}
}
}