Mercurial > gemma
view pkg/controllers/user.go @ 3488:aa264021e2bf zpg-ldc
merged default into zpg-ldc branch.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Mon, 27 May 2019 16:38:07 +0200 |
parents | 92812bf2f008 |
children | 07d853f9bf47 |
line wrap: on
line source
// This is Free Software under GNU Affero General Public License v >= 3.0 // without warranty, see README.md and license for details. // // SPDX-License-Identifier: AGPL-3.0-or-later // License-Filename: LICENSES/AGPL-3.0.txt // // Copyright (C) 2018 by via donau // – Österreichische Wasserstraßen-Gesellschaft mbH // Software engineering by Intevation GmbH // // Author(s): // * Sascha L. Teichmann <sascha.teichmann@intevation.de> // * Tom Gottfried <tom.gottfried@intevation.de> // * Sascha Wilde <sascha.wilde@intevation.de> package controllers import ( "bytes" "database/sql" "fmt" "log" "net/http" "text/template" "time" "github.com/gorilla/mux" "gemma.intevation.de/gemma/pkg/auth" "gemma.intevation.de/gemma/pkg/misc" "gemma.intevation.de/gemma/pkg/models" "gemma.intevation.de/gemma/pkg/scheduler" ) const ( createUserSQL = `INSERT INTO users.list_users VALUES ($1, $2, $3, $4, NULL, $5)` createUserExtentSQL = `INSERT INTO users.list_users VALUES ($1, $2, $3, $4, ST_MakeBox2D(ST_Point($5, $6), ST_Point($7, $8)), $9)` updateUserUnprivSQL = `UPDATE users.list_users SET (pw, map_extent, email_address) = ($2, ST_MakeBox2D(ST_Point($3, $4), ST_Point($5, $6)), $7) WHERE username = $1` updateUserSQL = `UPDATE users.list_users SET (rolname, username, pw, country, map_extent, email_address) = ($2, $3, $4, $5, NULL, $6) WHERE username = $1` updateUserExtentSQL = `UPDATE users.list_users SET (rolname, username, pw, country, map_extent, email_address) = ($2, $3, $4, $5, ST_MakeBox2D(ST_Point($6, $7), ST_Point($8, $9)), $10) WHERE username = $1` deleteUserSQL = `DELETE FROM users.list_users WHERE username = $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 ( testSysadminNotifyMailTmpl = template.Must( template.New("sysadmin").Parse(`Dear {{ .User }}, this is a test email for the Gemma System Errors notification service. You recieved this mail, because a System Administrator triggered the test mail sending function at {{ .Timestamp }}. When a critical system error is detected an automated mail will be send to the address: {{ .Email }} with details on the error condition.`)) testWWAdminNotifyMailTmpl = template.Must( template.New("waterwayadmin").Parse(`Dear {{ .User }}, this is a test email for the Gemma System Imports notification service. You recieved this mail, because a System Administrator triggered the test mail sending function at {{ .Timestamp }}. When the status of an data import managed by you changes an automated mail will be send to the address: {{ .Email }} with details on the new import status (inkluding import errors) and details on the concerned import.`)) ) func deleteUser( _ interface{}, req *http.Request, db *sql.Conn, ) (jr JSONResult, err error) { user := mux.Vars(req)["user"] if !models.UserName(user).IsValid() { err = JSONError{http.StatusBadRequest, "error: user invalid"} return } session, _ := auth.GetSession(req) if session.User == user { err = JSONError{http.StatusBadRequest, "error: cannot delete yourself"} return } ctx := req.Context() // Remove scheduled tasks. ids, err2 := scheduler.ScheduledUserIDs(ctx, db, user) if err2 == nil { if len(ids) > 0 { go func() { scheduler.UnbindByIDs(ids) }() } } else { log.Printf("error: %v\n", err2) } var res sql.Result if res, err = db.ExecContext(ctx, deleteUserSQL, user); err != nil { return } if n, err2 := res.RowsAffected(); err2 == nil && n == 0 { err = JSONError{ Code: http.StatusNotFound, Message: fmt.Sprintf("Cannot find user %s.", user), } return } // Running in a go routine should not be necessary. go func() { auth.Sessions.Logout(user) }() jr = JSONResult{Code: http.StatusNoContent} return } func updateUser( input interface{}, req *http.Request, db *sql.Conn, ) (jr JSONResult, err error) { user := models.UserName(mux.Vars(req)["user"]) if !user.IsValid() { err = JSONError{http.StatusBadRequest, "error: user invalid"} return } newUser := input.(*models.User) var res sql.Result if s, _ := auth.GetSession(req); s.Roles.Has("sys_admin") { if newUser.Extent == nil { res, err = db.ExecContext( req.Context(), updateUserSQL, user, newUser.Role, newUser.User, newUser.Password, newUser.Country, newUser.Email, ) } else { res, err = db.ExecContext( req.Context(), updateUserExtentSQL, user, newUser.Role, newUser.User, newUser.Password, newUser.Country, newUser.Extent.X1, newUser.Extent.Y1, newUser.Extent.X2, newUser.Extent.Y2, newUser.Email, ) } } else { if newUser.Extent == nil { err = JSONError{http.StatusBadRequest, "extent is mandatory"} return } res, err = db.ExecContext( req.Context(), updateUserUnprivSQL, user, newUser.Password, newUser.Extent.X1, newUser.Extent.Y1, newUser.Extent.X2, newUser.Extent.Y2, newUser.Email, ) } if err != nil { return } if n, err2 := res.RowsAffected(); err2 == nil && n == 0 { err = JSONError{ Code: http.StatusNotFound, Message: fmt.Sprintf("Cannot find user %s.", user), } return } if user != newUser.User { // Running in a go routine should not be necessary. go func() { auth.Sessions.Logout(string(user)) }() } jr = JSONResult{ Code: http.StatusCreated, Result: struct { Result string `json:"result"` }{"success"}, } return } func createUser( input interface{}, req *http.Request, db *sql.Conn, ) (jr JSONResult, err error) { user := input.(*models.User) if user.Extent == nil { _, err = db.ExecContext( req.Context(), createUserSQL, user.Role, user.User, user.Password, user.Country, user.Email, ) } else { _, err = db.ExecContext( req.Context(), 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"` }{"success"}, } return } func listUsers( _ interface{}, req *http.Request, db *sql.Conn, ) (jr JSONResult, err error) { var rows *sql.Rows rows, err = db.QueryContext(req.Context(), listUsersSQL) if err != nil { return } defer rows.Close() var users []*models.User for rows.Next() { user := &models.User{Extent: &models.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 []*models.User `json:"users"` }{users}, } return } func listUser( _ interface{}, req *http.Request, db *sql.Conn, ) (jr JSONResult, err error) { user := models.UserName(mux.Vars(req)["user"]) if !user.IsValid() { err = JSONError{http.StatusBadRequest, "error: user invalid"} return } result := &models.User{ User: user, Extent: &models.BoundingBox{}, } err = db.QueryRowContext(req.Context(), 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 } func sendTestMail( _ interface{}, req *http.Request, db *sql.Conn, ) (jr JSONResult, err error) { user := models.UserName(mux.Vars(req)["user"]) if !user.IsValid() { err = JSONError{http.StatusBadRequest, "error: user invalid"} return } userData := &models.User{ User: user, Extent: &models.BoundingBox{}, } err = db.QueryRowContext(req.Context(), listUserSQL, user).Scan( &userData.Role, &userData.Country, &userData.Email, &userData.Extent.X1, &userData.Extent.Y1, &userData.Extent.X2, &userData.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 } var subject string var tmplVars = struct { User string Timestamp string Email string }{ User: string(user), Timestamp: time.Now().Format("2006-01-02 15:04:05"), Email: string(userData.Email), } var bodyTmpl *template.Template if userData.Role == "sys_admin" { subject = "Gemma: Sysadmin Notification TEST" bodyTmpl = testSysadminNotifyMailTmpl } else if userData.Role == "waterway_admin" { subject = "Gemma: Waterway Admin Notification TEST" bodyTmpl = testWWAdminNotifyMailTmpl } else { err = JSONError{ Code: http.StatusBadRequest, Message: "Test mails can only be generated for admin roles.", } return } var buf bytes.Buffer if err := bodyTmpl.Execute(&buf, &tmplVars); err != nil { log.Printf("error: %v\n", err) } err = misc.SendMail(string(userData.Email), subject, buf.String()) if err != nil { return } jr.Result = &struct { Message string `json:"message"` }{"Sending test mail."} return }