Mercurial > gemma
changeset 442:fc37e7072022
Moved some models used in controllers to to model package because they may be needed elsewhere (e.g. GeoServer config).
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Tue, 21 Aug 2018 16:57:55 +0200 |
parents | 76a76691a298 |
children | 5e8ac1c67fe6 |
files | pkg/controllers/extservices.go pkg/controllers/pubservices.go pkg/controllers/pwreset.go pkg/controllers/routes.go pkg/controllers/token.go pkg/controllers/types.go pkg/controllers/user.go pkg/models/extservices.go pkg/models/pubservices.go pkg/models/types.go |
diffstat | 10 files changed, 344 insertions(+), 334 deletions(-) [+] |
line wrap: on
line diff
--- a/pkg/controllers/extservices.go Tue Aug 21 14:59:36 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -package controllers - -import ( - "database/sql" - "log" - "sync" - - "gemma.intevation.de/gemma/pkg/auth" -) - -type extEntry struct { - url string - isWFS bool -} - -type extServices struct { - mu sync.Mutex - entries map[string]extEntry -} - -var externalServices = &extServices{} - -const selectExternalServices = `SELECT local_name, remote_url, is_wfs -FROM sys_admin.external_services` - -func (es *extServices) find(name string) (string, bool) { - es.mu.Lock() - defer es.mu.Unlock() - - if es.entries == nil { - es.entries = make(map[string]extEntry) - if err := es.load(); err != nil { - log.Printf("error: %v\n", err) - return "", false - } - } - e, found := es.entries[name] - return e.url, found -} - -func (es *extServices) load() error { - return auth.RunAs("sys_admin", func(db *sql.DB) error { - rows, err := db.Query(selectExternalServices) - if err != nil { - return err - } - defer rows.Close() - for rows.Next() { - var entry extEntry - var key string - if err := rows.Scan(&key, &entry.url, &entry.isWFS); err != nil { - return err - } - es.entries[key] = entry - } - return rows.Err() - }) -} - -func (es *extServices) invalidate() { - es.mu.Lock() - es.entries = nil - es.mu.Unlock() -}
--- a/pkg/controllers/pubservices.go Tue Aug 21 14:59:36 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -package controllers - -import ( - "database/sql" - "log" - "sync" - - "gemma.intevation.de/gemma/pkg/auth" -) - -type pubEntry struct { - style sql.NullString - asWMS bool - asWFS bool -} - -type pubServices struct { - entries map[string]pubEntry - mu sync.Mutex -} - -const selectPublishedServices = `SELECT name, style, as_wms, as_wfs -FROM sys_admin.published_services` - -var publishedServices = &pubServices{} - -func (ps *pubServices) find(name string) (string, bool) { - ps.mu.Lock() - defer ps.mu.Unlock() - - if ps.entries == nil { - ps.entries = make(map[string]pubEntry) - if err := ps.load(); err != nil { - log.Printf("error: %v\n", err) - return "", false - } - } - _, found := ps.entries[name] - if !found { - name = "" - } - return name, found -} - -func (ps *pubServices) load() error { - return auth.RunAs("sys_admin", func(db *sql.DB) error { - rows, err := db.Query(selectPublishedServices) - if err != nil { - return err - } - defer rows.Close() - for rows.Next() { - var entry pubEntry - var key string - if err := rows.Scan( - &key, &entry.style, - &entry.asWFS, &entry.asWFS, - ); err != nil { - return err - } - ps.entries[key] = entry - } - return rows.Err() - }) - return nil -}
--- a/pkg/controllers/pwreset.go Tue Aug 21 14:59:36 2018 +0200 +++ b/pkg/controllers/pwreset.go Tue Aug 21 16:57:55 2018 +0200 @@ -16,6 +16,7 @@ "gemma.intevation.de/gemma/pkg/auth" "gemma.intevation.de/gemma/pkg/common" "gemma.intevation.de/gemma/pkg/misc" + "gemma.intevation.de/gemma/pkg/models" ) const ( @@ -167,7 +168,7 @@ _ *sql.DB, ) (jr JSONResult, err error) { - user := input.(*PWResetUser) + user := input.(*models.PWResetUser) if user.User == "" { err = JSONError{http.StatusBadRequest, "Invalid user name"}
--- a/pkg/controllers/routes.go Tue Aug 21 14:59:36 2018 +0200 +++ b/pkg/controllers/routes.go Tue Aug 21 16:57:55 2018 +0200 @@ -8,6 +8,7 @@ "gemma.intevation.de/gemma/pkg/auth" "gemma.intevation.de/gemma/pkg/middleware" + "gemma.intevation.de/gemma/pkg/models" ) func BindRoutes(m *mux.Router) { @@ -25,7 +26,7 @@ })).Methods(http.MethodGet) api.Handle("/users", sysAdmin(&JSONHandler{ - Input: func() interface{} { return new(User) }, + Input: func() interface{} { return new(models.User) }, Handle: createUser, })).Methods(http.MethodPost) @@ -34,7 +35,7 @@ })).Methods(http.MethodGet) api.Handle("/users/{user}", all(&JSONHandler{ - Input: func() interface{} { return new(User) }, + Input: func() interface{} { return new(models.User) }, Handle: updateUser, })).Methods(http.MethodPut) @@ -44,7 +45,7 @@ // Password resets. api.Handle("/users/passwordreset", &JSONHandler{ - Input: func() interface{} { return new(PWResetUser) }, + Input: func() interface{} { return new(models.PWResetUser) }, Handle: passwordResetRequest, }).Methods(http.MethodPost) @@ -54,7 +55,7 @@ // External proxies. proxy := &httputil.ReverseProxy{ - Director: proxyDirector(externalServices.find), + Director: proxyDirector(models.ExternalServices.Find), ModifyResponse: proxyModifyResponse("/api/external/"), } @@ -70,7 +71,7 @@ // Internal proxies. internal := &httputil.ReverseProxy{ - Director: proxyDirector(publishedServices.find), + Director: proxyDirector(models.PublishedServices.Find), ModifyResponse: proxyModifyResponse("/api/internal/"), }
--- a/pkg/controllers/token.go Tue Aug 21 14:59:36 2018 +0200 +++ b/pkg/controllers/token.go Tue Aug 21 16:57:55 2018 +0200 @@ -7,6 +7,7 @@ "net/http" "gemma.intevation.de/gemma/pkg/auth" + "gemma.intevation.de/gemma/pkg/models" ) func sendJSON(rw http.ResponseWriter, data interface{}) { @@ -63,7 +64,7 @@ password = req.FormValue("password") ) - if !UserName(user).isValid() || password == "" { + if !models.UserName(user).IsValid() || password == "" { http.Error(rw, "Invalid credentials", http.StatusBadRequest) return }
--- a/pkg/controllers/types.go Tue Aug 21 14:59:36 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,185 +0,0 @@ -package controllers - -import ( - "database/sql/driver" - "encoding/json" - "errors" - "regexp" - "strings" - - "gemma.intevation.de/gemma/pkg/auth" -) - -type ( - Email string - Country string - Role string - UserName string - - BoundingBox struct { - X1 float64 `json:"x1"` - Y1 float64 `json:"y1"` - X2 float64 `json:"x2"` - Y2 float64 `json:"y2"` - } - - User struct { - User UserName `json:"user"` - Role Role `json:"role"` - Password string `json:"password,omitempty"` - Email Email `json:"email"` - Country Country `json:"country"` - Extent *BoundingBox `json:"extent"` - } - - PWResetUser struct { - User string `json:"user"` - } -) - -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") - errNoString = errors.New("Not a string") -) - -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 errNoValidUser = errors.New("Not a valid user") - -func (u UserName) isValid() bool { - return u != "" && - !strings.ContainsAny(string(u), auth.InvalidRoleCharacters) -} - -func (u *UserName) UnmarshalJSON(data []byte) error { - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - if !emailRe.MatchString(s) { - return errNoEmailAddress - } - user := UserName(s) - if !user.isValid() { - return errNoValidUser - } - *u = user - return nil -} - -func (u *UserName) Scan(src interface{}) (err error) { - if s, ok := src.(string); ok { - *u = UserName(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 -}
--- a/pkg/controllers/user.go Tue Aug 21 14:59:36 2018 +0200 +++ b/pkg/controllers/user.go Tue Aug 21 16:57:55 2018 +0200 @@ -8,6 +8,7 @@ "github.com/gorilla/mux" "gemma.intevation.de/gemma/pkg/auth" + "gemma.intevation.de/gemma/pkg/models" ) const ( @@ -57,7 +58,7 @@ ) (jr JSONResult, err error) { user := mux.Vars(req)["user"] - if !UserName(user).isValid() { + if !models.UserName(user).IsValid() { err = JSONError{http.StatusBadRequest, "error: user invalid"} return } @@ -94,13 +95,13 @@ db *sql.DB, ) (jr JSONResult, err error) { - user := UserName(mux.Vars(req)["user"]) - if !user.isValid() { + user := models.UserName(mux.Vars(req)["user"]) + if !user.IsValid() { err = JSONError{http.StatusBadRequest, "error: user invalid"} return } - newUser := input.(*User) + newUser := input.(*models.User) var res sql.Result if s, _ := auth.GetSession(req); s.Roles.Has("sys_admin") { @@ -173,7 +174,7 @@ db *sql.DB, ) (jr JSONResult, err error) { - user := input.(*User) + user := input.(*models.User) if user.Extent == nil { _, err = db.Exec( @@ -223,10 +224,10 @@ } defer rows.Close() - var users []*User + var users []*models.User for rows.Next() { - user := &User{Extent: &BoundingBox{}} + user := &models.User{Extent: &models.BoundingBox{}} if err = rows.Scan( &user.Role, &user.User, @@ -242,7 +243,7 @@ jr = JSONResult{ Result: struct { - Users []*User `json:"users"` + Users []*models.User `json:"users"` }{users}, } return @@ -253,15 +254,15 @@ db *sql.DB, ) (jr JSONResult, err error) { - user := UserName(mux.Vars(req)["user"]) - if !user.isValid() { + user := models.UserName(mux.Vars(req)["user"]) + if !user.IsValid() { err = JSONError{http.StatusBadRequest, "error: user invalid"} return } - result := &User{ + result := &models.User{ User: user, - Extent: &BoundingBox{}, + Extent: &models.BoundingBox{}, } err = db.QueryRow(listUserSQL, user).Scan(
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/models/extservices.go Tue Aug 21 16:57:55 2018 +0200 @@ -0,0 +1,64 @@ +package models + +import ( + "database/sql" + "log" + "sync" + + "gemma.intevation.de/gemma/pkg/auth" +) + +type ExtEntry struct { + url string + isWFS bool +} + +type ExtServices struct { + mu sync.Mutex + entries map[string]ExtEntry +} + +var ExternalServices = &ExtServices{} + +const selectExternalServices = `SELECT local_name, remote_url, is_wfs +FROM sys_admin.external_services` + +func (es *ExtServices) Find(name string) (string, bool) { + es.mu.Lock() + defer es.mu.Unlock() + + if es.entries == nil { + es.entries = make(map[string]ExtEntry) + if err := es.load(); err != nil { + log.Printf("error: %v\n", err) + return "", false + } + } + e, found := es.entries[name] + return e.url, found +} + +func (es *ExtServices) load() error { + return auth.RunAs("sys_admin", func(db *sql.DB) error { + rows, err := db.Query(selectExternalServices) + if err != nil { + return err + } + defer rows.Close() + for rows.Next() { + var entry ExtEntry + var key string + if err := rows.Scan(&key, &entry.url, &entry.isWFS); err != nil { + return err + } + es.entries[key] = entry + } + return rows.Err() + }) +} + +func (es *ExtServices) Invalidate() { + es.mu.Lock() + es.entries = nil + es.mu.Unlock() +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/models/pubservices.go Tue Aug 21 16:57:55 2018 +0200 @@ -0,0 +1,72 @@ +package models + +import ( + "database/sql" + "log" + "sync" + + "gemma.intevation.de/gemma/pkg/auth" +) + +type PubEntry struct { + style sql.NullString + asWMS bool + asWFS bool +} + +type PubServices struct { + entries map[string]PubEntry + mu sync.Mutex +} + +const selectPublishedServices = `SELECT name, style, as_wms, as_wfs +FROM sys_admin.published_services` + +var PublishedServices = &PubServices{} + +func (ps *PubServices) Find(name string) (string, bool) { + ps.mu.Lock() + defer ps.mu.Unlock() + + if ps.entries == nil { + ps.entries = make(map[string]PubEntry) + if err := ps.load(); err != nil { + log.Printf("error: %v\n", err) + return "", false + } + } + _, found := ps.entries[name] + if !found { + name = "" + } + return name, found +} + +func (ps *PubServices) load() error { + return auth.RunAs("sys_admin", func(db *sql.DB) error { + rows, err := db.Query(selectPublishedServices) + if err != nil { + return err + } + defer rows.Close() + for rows.Next() { + var entry PubEntry + var key string + if err := rows.Scan( + &key, &entry.style, + &entry.asWFS, &entry.asWFS, + ); err != nil { + return err + } + ps.entries[key] = entry + } + return rows.Err() + }) + return nil +} + +func (ps *PubServices) Invalidate() { + ps.mu.Lock() + ps.entries = nil + ps.mu.Unlock() +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/models/types.go Tue Aug 21 16:57:55 2018 +0200 @@ -0,0 +1,185 @@ +package models + +import ( + "database/sql/driver" + "encoding/json" + "errors" + "regexp" + "strings" + + "gemma.intevation.de/gemma/pkg/auth" +) + +type ( + Email string + Country string + Role string + UserName string + + BoundingBox struct { + X1 float64 `json:"x1"` + Y1 float64 `json:"y1"` + X2 float64 `json:"x2"` + Y2 float64 `json:"y2"` + } + + User struct { + User UserName `json:"user"` + Role Role `json:"role"` + Password string `json:"password,omitempty"` + Email Email `json:"email"` + Country Country `json:"country"` + Extent *BoundingBox `json:"extent"` + } + + PWResetUser struct { + User string `json:"user"` + } +) + +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") + errNoString = errors.New("Not a string") +) + +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 errNoValidUser = errors.New("Not a valid user") + +func (u UserName) IsValid() bool { + return u != "" && + !strings.ContainsAny(string(u), auth.InvalidRoleCharacters) +} + +func (u *UserName) UnmarshalJSON(data []byte) error { + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + if !emailRe.MatchString(s) { + return errNoEmailAddress + } + user := UserName(s) + if !user.IsValid() { + return errNoValidUser + } + *u = user + return nil +} + +func (u *UserName) Scan(src interface{}) (err error) { + if s, ok := src.(string); ok { + *u = UserName(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 +}