Mercurial > gemma
view controllers/user.go @ 257:dfc2b035e055
Slimming down the signature of the JSONHandler type to
not take the http.ResponseWriter.
Idea of this handler is to simply transform JSON to JSON.
The input is already parsed. The output is generated from
JSONResult. So there is no need to pass the ResponseWriter
to the handler function.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Fri, 27 Jul 2018 13:03:56 +0200 |
parents | de6fdb316b8f |
children | ab9859981ee3 |
line wrap: on
line source
package controllers import ( "database/sql" "database/sql/driver" "encoding/json" "errors" "fmt" "net/http" "regexp" "strings" "github.com/gorilla/mux" "gemma.intevation.de/gemma/auth" ) type ( Email string Country string Role string BoundingBox struct { X1 float64 `json:"x1"` Y1 float64 `json:"y1"` X2 float64 `json:"x2"` Y2 float64 `json:"y2"` } User struct { User string `json:"user"` Role Role `json:"role"` Password string `json:"password,omitempty"` Email Email `json:"email"` Country Country `json:"country"` Extent *BoundingBox `json:"extent"` } ) const ( createUserSQL = `SELECT sys_admin.create_user($1, $2, $3, $4, NULL, $5)` createUserExtentSQL = `SELECT sys_admin.create_user($1, $2, $3, $4, ST_MakeBox2D(ST_Point($5, $6), ST_Point($7, $8)), $9)` updateUserSQL = `SELECT sys_admin.update_user($1, $2, $3, $4, $5, NULL, $6)` updateUserExtentSQL = `SELECT sys_admin.update_user($1, $2, $3, $4, $5, ST_MakeBox2D(ST_Point($6, $7), ST_Point($8, $9)), $10)` deleteUserSQL = `SELECT sys_admin.delete_user($1)` listUsersSQL = `SELECT rolname, username, country, email_address, ST_XMin(map_extent), ST_YMin(map_extent), ST_XMax(map_extent), ST_YMax(map_extent) FROM sys_admin.list_users` listUserSQL = `SELECT rolname, country, email_address, ST_XMin(map_extent), ST_YMin(map_extent), ST_XMax(map_extent), ST_YMax(map_extent) FROM sys_admin.list_users WHERE username = $1` ) var errNoString = errors.New("Not a string") var ( // https://stackoverflow.com/questions/201323/how-to-validate-an-email-address-using-a-regular-expression emailRe = regexp.MustCompile( `(?:[a-z0-9!#$%&'*+/=?^_` + "`" + `{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_` + "`" + `{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]` + `|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")` + `@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?` + `|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}` + `(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]` + `:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]` + `|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])`) errNoEmailAddress = errors.New("Not a valid email address") ) func (e *Email) UnmarshalJSON(data []byte) error { var s string if err := json.Unmarshal(data, &s); err != nil { return err } if !emailRe.MatchString(s) { return errNoEmailAddress } *e = Email(s) return nil } func (e Email) Value() (driver.Value, error) { return string(e), nil } func (e *Email) Scan(src interface{}) (err error) { if s, ok := src.(string); ok { *e = Email(s) } else { err = errNoString } return } var ( validCountries = []string{ "AT", "BG", "DE", "HU", "HR", "MD", "RO", "RS", "SK", "UA", } errNoValidCountry = errors.New("Not a valid country") ) func (c *Country) UnmarshalJSON(data []byte) error { var s string if err := json.Unmarshal(data, &s); err != nil { return err } s = strings.ToUpper(s) for _, v := range validCountries { if v == s { *c = Country(v) return nil } } return errNoValidCountry } func (c Country) Value() (driver.Value, error) { return string(c), nil } func (c *Country) Scan(src interface{}) (err error) { if s, ok := src.(string); ok { *c = Country(s) } else { err = errNoString } return } var ( validRoles = []string{ "waterway_user", "waterway_admin", "sys_admin", } errNoValidRole = errors.New("Not a valid role") ) func (r Role) Value() (driver.Value, error) { return string(r), nil } func (r *Role) Scan(src interface{}) (err error) { if s, ok := src.(string); ok { *r = Role(s) } else { err = errNoString } return } func (r *Role) UnmarshalJSON(data []byte) error { var s string if err := json.Unmarshal(data, &s); err != nil { return err } s = strings.ToLower(s) for _, v := range validRoles { if v == s { *r = Role(v) return nil } } return errNoValidRole } func deleteUser( input interface{}, req *http.Request, db *sql.DB, ) (jr JSONResult, err error) { user := mux.Vars(req)["user"] if user == "" { err = JSONError{http.StatusBadRequest, "error: user empty"} return } session, _ := auth.GetSession(req) if session.User == user { err = JSONError{http.StatusBadRequest, "error: cannot delete yourself"} return } if _, err = db.Exec(deleteUserSQL, user); err != nil { return } // Running in a go routine should not be necessary. go func() { auth.ConnPool.Logout(user) }() jr = JSONResult{Code: http.StatusNoContent} return } func updateUser( input interface{}, req *http.Request, db *sql.DB, ) (jr JSONResult, err error) { user := mux.Vars(req)["user"] if user == "" { err = JSONError{http.StatusBadRequest, "error: user empty"} return } newUser := input.(*User) if newUser.Extent == nil { _, err = db.Exec( updateUserSQL, user, newUser.Role, newUser.User, newUser.Password, newUser.Country, newUser.Email, ) } else { _, err = db.Exec( updateUserExtentSQL, user, newUser.Role, newUser.User, newUser.Password, newUser.Country, newUser.Extent.X1, newUser.Extent.Y1, newUser.Extent.X2, newUser.Extent.Y2, newUser.Email, ) } if err != nil { return } jr = JSONResult{ Code: http.StatusCreated, Result: struct { Result string `json:"result"` }{ Result: "success", }, } return } func createUser( input interface{}, req *http.Request, db *sql.DB, ) (jr JSONResult, err error) { user := input.(*User) if user.Extent == nil { _, err = db.Exec( createUserSQL, user.Role, user.User, user.Password, user.Country, user.Email, ) } else { _, err = db.Exec( createUserExtentSQL, user.Role, user.User, user.Password, user.Country, user.Extent.X1, user.Extent.Y1, user.Extent.X2, user.Extent.Y2, user.Email, ) } if err != nil { return } jr = JSONResult{ Code: http.StatusCreated, Result: struct { Result string `json:"result"` }{ Result: "success", }, } return } func listUsers( input interface{}, req *http.Request, db *sql.DB, ) (jr JSONResult, err error) { var rows *sql.Rows rows, err = db.Query(listUsersSQL) if err != nil { return } defer rows.Close() var users []*User for rows.Next() { user := &User{Extent: &BoundingBox{}} if err = rows.Scan( &user.Role, &user.User, &user.Country, &user.Email, &user.Extent.X1, &user.Extent.Y1, &user.Extent.X2, &user.Extent.Y2, ); err != nil { return } users = append(users, user) } jr = JSONResult{ Result: struct { Users []*User `json:"users"` }{ Users: users, }, } return } func listUser( input interface{}, req *http.Request, db *sql.DB, ) (jr JSONResult, err error) { user := mux.Vars(req)["user"] if user == "" { err = JSONError{http.StatusBadRequest, "error: user empty"} return } result := &User{ User: user, Extent: &BoundingBox{}, } err = db.QueryRow(listUserSQL, user).Scan( &result.Role, &result.Country, &result.Email, &result.Extent.X1, &result.Extent.Y1, &result.Extent.X2, &result.Extent.Y2, ) switch { case err == sql.ErrNoRows: err = JSONError{ Code: http.StatusNotFound, Message: fmt.Sprintf("Cannot find user %s.", user), } return case err != nil: return } jr.Result = result return }