Mercurial > gemma
view controllers/user.go @ 283:0b4c824517c4 usermanagement
merge with default
author | Thomas Junk <thomas.junk@intevation.de> |
---|---|
date | Mon, 30 Jul 2018 17:27:41 +0200 |
parents | d89a19c297e0 |
children | be6e60fca3dd |
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 users.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 users.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 } if user != newUser.User { // Running in a go routine should not be necessary. go func() { auth.ConnPool.Logout(user) }() } 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 }