@@ -9,19 +9,11 @@ import (
99 "github.com/gin-gonic/gin"
1010 "github.com/gotify/server/v3/auth"
1111 "github.com/gotify/server/v3/auth/password"
12+ "github.com/gotify/server/v3/database"
1213 "github.com/gotify/server/v3/model"
1314)
1415
15- // The UserDatabase interface for encapsulating database access.
16- type UserDatabase interface {
17- GetUsers () ([]* model.User , error )
18- GetUserByID (id uint ) (* model.User , error )
19- GetUserByName (name string ) (* model.User , error )
20- DeleteUserByID (id uint ) error
21- UpdateUser (user * model.User ) error
22- CreateUser (user * model.User ) error
23- CountUser (condition ... any ) (int64 , error )
24- }
16+ var errCannotDeleteLastAdmin = errors .New ("cannot delete last admin" )
2517
2618// UserChangeNotifier notifies listeners for user changes.
2719type UserChangeNotifier struct {
@@ -59,7 +51,7 @@ func (c *UserChangeNotifier) fireUserAdded(uid uint) error {
5951
6052// The UserAPI provides handlers for managing users.
6153type UserAPI struct {
62- DB UserDatabase
54+ DB * database. GormDatabase
6355 PasswordStrength int
6456 UserChangeNotifier * UserChangeNotifier
6557 Registration bool
@@ -343,19 +335,26 @@ func (a *UserAPI) DeleteUserByID(ctx *gin.Context) {
343335 return
344336 }
345337 if user != nil {
346- adminCount , err := a .DB .CountUser (& model.User {Admin : true })
347- if success := successOrAbort (ctx , 500 , err ); ! success {
348- return
349- }
350- if user .Admin && adminCount == 1 {
351- ctx .AbortWithError (400 , errors .New ("cannot delete last admin" ))
352- return
353- }
354- if err := a .UserChangeNotifier .fireUserDeleted (id ); err != nil {
355- ctx .AbortWithError (500 , err )
356- return
338+ for range 3 {
339+ err = a .DB .Txn (func (txdb * database.GormDatabase ) error {
340+ if err := txdb .DeleteUserByID (id ); err != nil {
341+ return err
342+ }
343+ anotherAdmin , err := txdb .GetUsers (& model.User {Admin : true })
344+ if err != nil {
345+ return err
346+ }
347+ if user .Admin && len (anotherAdmin ) == 0 {
348+ ctx .AbortWithError (400 , errCannotDeleteLastAdmin )
349+ return errCannotDeleteLastAdmin
350+ }
351+ return a .UserChangeNotifier .fireUserDeleted (id )
352+ })
353+ if err == nil || ctx .IsAborted () {
354+ return
355+ }
357356 }
358- successOrAbort (ctx , 500 , a . DB . DeleteUserByID ( id ) )
357+ successOrAbort (ctx , 500 , err )
359358 } else {
360359 ctx .AbortWithError (404 , errors .New ("user does not exist" ))
361360 }
@@ -470,15 +469,7 @@ func (a *UserAPI) UpdateUserByID(ctx *gin.Context) {
470469 return
471470 }
472471 if dbUser != nil {
473- adminCount , err := a .DB .CountUser (& model.User {Admin : true })
474- if success := successOrAbort (ctx , 500 , err ); ! success {
475- return
476- }
477- if ! updatedUser .Admin && dbUser .Admin && adminCount == 1 {
478- ctx .AbortWithError (400 , errors .New ("cannot delete last admin" ))
479- return
480- }
481-
472+ dbUserWasAdmin := dbUser .Admin
482473 dbUser .Name = updatedUser .Name
483474 dbUser .Admin = updatedUser .Admin
484475
@@ -494,10 +485,35 @@ func (a *UserAPI) UpdateUserByID(ctx *gin.Context) {
494485 }
495486 dbUser .Pass = pw
496487 }
497- if success := successOrAbort (ctx , 500 , a .DB .UpdateUser (dbUser )); ! success {
498- return
488+
489+ for range 3 {
490+ err = a .DB .Txn (func (txdb * database.GormDatabase ) error {
491+ if err := txdb .UpdateUser (dbUser ); err != nil {
492+ return err
493+ }
494+
495+ anotherAdmin , err := txdb .GetUsers (& model.User {Admin : true })
496+ if err != nil {
497+ return err
498+ }
499+ if ! updatedUser .Admin && dbUserWasAdmin && len (anotherAdmin ) == 0 {
500+ ctx .AbortWithError (400 , errCannotDeleteLastAdmin )
501+ return errCannotDeleteLastAdmin
502+ }
503+
504+ return nil
505+ })
506+
507+ if ctx .IsAborted () {
508+ return
509+ }
510+
511+ if err == nil {
512+ ctx .JSON (200 , toExternalUser (dbUser ))
513+ return
514+ }
499515 }
500- ctx .JSON ( 200 , toExternalUser ( dbUser ) )
516+ ctx .AbortWithError ( 500 , err )
501517 } else {
502518 ctx .AbortWithError (404 , errors .New ("user does not exist" ))
503519 }
0 commit comments