changeset 5498:59cbd1b48c3a deactivate-users

Implemented delete a user if its a none admin user or a admin w/o imports. Admins with imports are deactivated.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Tue, 21 Sep 2021 19:02:53 +0200
parents 1e6053a4ed98
children a30b6c6541e0
files pkg/controllers/user.go pkg/models/user.go
diffstat 2 files changed, 65 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/pkg/controllers/user.go	Tue Sep 21 15:39:51 2021 +0200
+++ b/pkg/controllers/user.go	Tue Sep 21 19:02:53 2021 +0200
@@ -28,6 +28,7 @@
 	"github.com/gorilla/mux"
 
 	"gemma.intevation.de/gemma/pkg/auth"
+	"gemma.intevation.de/gemma/pkg/common"
 	"gemma.intevation.de/gemma/pkg/log"
 	"gemma.intevation.de/gemma/pkg/misc"
 	"gemma.intevation.de/gemma/pkg/models"
@@ -57,8 +58,19 @@
   = ($2, $3, $4, $5, ST_MakeBox2D(ST_Point($6, $7), ST_Point($8, $9)), $10, $11)
   WHERE username = $1`
 
+	usersExistsSQL = `SELECT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = $1)`
+
+	userIsAdminSQL = `SELECT EXISTS (SELECT 1 FROM pg_roles
+  WHERE pg_has_role($1, oid, 'member') AND rolname in ('waterway_admin', 'sys_admin'))`
+
+	adminHasImportsSQL = `SELECT EXISTS (SELECT 1 FROM import.imports
+  WHERE username = $1)`
+
 	deleteUserSQL = `DELETE FROM users.list_users WHERE username = $1`
 
+	deactivateUserSQL = `UPDATE users.list_users
+  SET (pw, email_address, report_reciever, active) = ($1, 'nomail@example.com', false, false)`
+
 	listUsersSQL = `SELECT
   rolname,
   username,
@@ -66,7 +78,8 @@
   email_address,
   ST_XMin(map_extent), ST_YMin(map_extent),
   ST_XMax(map_extent), ST_YMax(map_extent),
-  report_reciever
+  report_reciever,
+  active
 FROM users.list_users`
 
 	listUserSQL = `SELECT
@@ -134,6 +147,24 @@
 
 	db := mw.JSONConn(req)
 
+	// TODO: Move this into the transaction.
+
+	// First check if user exists
+
+	var userExists bool
+	if err = db.QueryRowContext(ctx, usersExistsSQL).Scan(&userExists); err != nil {
+		log.Errorf("%v\n", err)
+		return
+	}
+
+	if !userExists {
+		err = mw.JSONError{
+			Code:    http.StatusNotFound,
+			Message: fmt.Sprintf("Cannot find user %s.", user),
+		}
+		return
+	}
+
 	// Remove scheduled tasks.
 	ids, err2 := scheduler.ScheduledUserIDs(ctx, db, user)
 	if err2 == nil {
@@ -144,17 +175,42 @@
 		log.Errorf("%v\n", err2)
 	}
 
-	var res sql.Result
+	var tx *sql.Tx
+	if tx, err = db.BeginTx(ctx, nil); err != nil {
+		return
+	}
+	defer tx.Rollback()
 
-	if res, err = db.ExecContext(ctx, deleteUserSQL, user); err != nil {
+	var isAdmin bool
+	if err = tx.QueryRowContext(ctx, userIsAdminSQL).Scan(&isAdmin); err != nil {
+		log.Errorf("%v\n", err)
 		return
 	}
 
-	if n, err2 := res.RowsAffected(); err2 == nil && n == 0 {
-		err = mw.JSONError{
-			Code:    http.StatusNotFound,
-			Message: fmt.Sprintf("Cannot find user %s.", user),
+	if !isAdmin { // All none admins can be deleted directly.
+		if _, err = tx.ExecContext(ctx, deleteUserSQL, user); err != nil {
+			log.Errorf("%v\n", err)
+			return
+		}
+	} else {
+		var hasImports bool
+		if err = tx.QueryRowContext(ctx, adminHasImportsSQL).Scan(&hasImports); err != nil {
+			log.Errorf("%v\n", err)
+			return
 		}
+		if !hasImports { // An admin w/o can also be simply deleted.
+			if _, err = tx.ExecContext(ctx, deleteUserSQL, user); err != nil {
+				log.Errorf("%v\n", err)
+				return
+			}
+		} else { // Admin user with imports needs to be deactivated.
+			pw := common.RandomString(30)
+			if _, err = tx.ExecContext(ctx, deactivateUserSQL, pw); err != nil {
+				return
+			}
+		}
+	}
+	if err = tx.Commit(); err != nil {
 		return
 	}
 
@@ -454,6 +510,7 @@
 			&user.Extent.X1, &user.Extent.Y1,
 			&user.Extent.X2, &user.Extent.Y2,
 			&user.Reports,
+			&user.Active,
 		); err != nil {
 			return
 		}
--- a/pkg/models/user.go	Tue Sep 21 15:39:51 2021 +0200
+++ b/pkg/models/user.go	Tue Sep 21 19:02:53 2021 +0200
@@ -47,6 +47,7 @@
 		Email    Email        `json:"email"`
 		Country  Country      `json:"country"`
 		Reports  bool         `json:"reports"`
+		Active   bool         `json:"active"`
 		Extent   *BoundingBox `json:"extent"`
 	}