Skip to content

Commit cb60db0

Browse files
feat: active inactive user phase 1 (#4589)
* listing user and group changes * default value chnage * group listing optimisation * wire_gen * order by in group * default values * discard * updated on * case insensitive * script number change * specs * review chnages * sql update * id for user * script number chnage * review comments-1 * review comments * review comments * rest handler remove methods * validation for delete * delete user handling * review comments * review comments * export csv filters support * Revert "export csv filters support" This reverts commit 4448c9e.
1 parent 322cf1d commit cb60db0

22 files changed

+668
-168
lines changed

api/auth/user/UserRestHandler.go

Lines changed: 25 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import (
2121
"encoding/json"
2222
"errors"
2323
"fmt"
24+
"github.com/devtron-labs/devtron/pkg/auth/user/helper"
25+
"github.com/gorilla/schema"
2426
"net/http"
2527
"strconv"
2628
"strings"
@@ -44,12 +46,10 @@ type UserRestHandler interface {
4446
GetById(w http.ResponseWriter, r *http.Request)
4547
GetAll(w http.ResponseWriter, r *http.Request)
4648
DeleteUser(w http.ResponseWriter, r *http.Request)
47-
GetAllDetailedUsers(w http.ResponseWriter, r *http.Request)
4849
FetchRoleGroupById(w http.ResponseWriter, r *http.Request)
4950
CreateRoleGroup(w http.ResponseWriter, r *http.Request)
5051
UpdateRoleGroup(w http.ResponseWriter, r *http.Request)
5152
FetchRoleGroups(w http.ResponseWriter, r *http.Request)
52-
FetchDetailedRoleGroups(w http.ResponseWriter, r *http.Request)
5353
FetchRoleGroupsByName(w http.ResponseWriter, r *http.Request)
5454
DeleteRoleGroup(w http.ResponseWriter, r *http.Request)
5555
CheckUserRoles(w http.ResponseWriter, r *http.Request)
@@ -210,20 +210,13 @@ func (handler UserRestHandlerImpl) UpdateUser(w http.ResponseWriter, r *http.Req
210210
// RBAC enforcer applying
211211
token := r.Header.Get("token")
212212

213-
if userInfo.EmailId == "admin" {
214-
userInfo.EmailId = "admin@github.com/devtron-labs"
215-
}
216213
err = handler.validator.Struct(userInfo)
217214
if err != nil {
218215
handler.logger.Errorw("validation err, UpdateUser", "err", err, "payload", userInfo)
219216
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
220217
return
221218
}
222219

223-
if userInfo.EmailId == "admin@github.com/devtron-labs" {
224-
userInfo.EmailId = "admin"
225-
}
226-
227220
res, rolesChanged, groupsModified, restrictedGroups, err := handler.userService.UpdateUser(&userInfo, token, handler.CheckManagerAuth)
228221

229222
if err != nil {
@@ -309,6 +302,7 @@ func (handler UserRestHandlerImpl) GetById(w http.ResponseWriter, r *http.Reques
309302
}
310303

311304
func (handler UserRestHandlerImpl) GetAll(w http.ResponseWriter, r *http.Request) {
305+
var decoder = schema.NewDecoder()
312306
userId, err := handler.userService.GetLoggedInUser(r)
313307
if userId == 0 || err != nil {
314308
common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized)
@@ -362,35 +356,16 @@ func (handler UserRestHandlerImpl) GetAll(w http.ResponseWriter, r *http.Request
362356
common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden)
363357
return
364358
}
365-
res, err := handler.userService.GetAll()
359+
req := &bean.FetchListingRequest{}
360+
err = decoder.Decode(req, r.URL.Query())
366361
if err != nil {
367-
handler.logger.Errorw("service err, GetAll", "err", err)
368-
common.WriteJsonResp(w, err, "Failed to Get", http.StatusInternalServerError)
369-
return
370-
}
371-
372-
common.WriteJsonResp(w, err, res, http.StatusOK)
373-
}
374-
375-
func (handler UserRestHandlerImpl) GetAllDetailedUsers(w http.ResponseWriter, r *http.Request) {
376-
userId, err := handler.userService.GetLoggedInUser(r)
377-
if userId == 0 || err != nil {
378-
common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized)
379-
return
380-
}
381-
382-
token := r.Header.Get("token")
383-
isActionUserSuperAdmin := false
384-
if ok := handler.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionGet, "*"); ok {
385-
isActionUserSuperAdmin = true
386-
}
387-
if !isActionUserSuperAdmin {
388-
common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden)
362+
handler.logger.Errorw("request err, GetAll", "err", err, "payload", req)
363+
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
389364
return
390365
}
391-
res, err := handler.userService.GetAllDetailedUsers()
366+
res, err := handler.userService.GetAllWithFilters(req)
392367
if err != nil {
393-
handler.logger.Errorw("service err, GetAllDetailedUsers", "err", err)
368+
handler.logger.Errorw("service err, GetAll", "err", err)
394369
common.WriteJsonResp(w, err, "Failed to Get", http.StatusInternalServerError)
395370
return
396371
}
@@ -451,7 +426,15 @@ func (handler UserRestHandlerImpl) DeleteUser(w http.ResponseWriter, r *http.Req
451426
}
452427
}
453428
//RBAC enforcer Ends
454-
429+
//validation
430+
validated := helper.CheckIfUserDevtronManaged(int32(id))
431+
if !validated {
432+
err = &util.ApiError{Code: "400", HttpStatusCode: 400, UserMessage: "cannot delete system or admin user"}
433+
handler.logger.Errorw("request err, DeleteUser, validation failed", "id", id, "err", err)
434+
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
435+
return
436+
}
437+
//service call
455438
res, err := handler.userService.DeleteUser(user)
456439
if err != nil {
457440
handler.logger.Errorw("service err, DeleteUser", "err", err, "id", id)
@@ -639,6 +622,7 @@ func (handler UserRestHandlerImpl) UpdateRoleGroup(w http.ResponseWriter, r *htt
639622
}
640623

641624
func (handler UserRestHandlerImpl) FetchRoleGroups(w http.ResponseWriter, r *http.Request) {
625+
var decoder = schema.NewDecoder()
642626
userId, err := handler.userService.GetLoggedInUser(r)
643627
if userId == 0 || err != nil {
644628
common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized)
@@ -692,32 +676,15 @@ func (handler UserRestHandlerImpl) FetchRoleGroups(w http.ResponseWriter, r *htt
692676
common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden)
693677
return
694678
}
695-
res, err := handler.roleGroupService.FetchRoleGroups()
696-
if err != nil {
697-
handler.logger.Errorw("service err, FetchRoleGroups", "err", err)
698-
common.WriteJsonResp(w, err, "", http.StatusInternalServerError)
699-
return
700-
}
701-
common.WriteJsonResp(w, err, res, http.StatusOK)
702-
}
703679

704-
func (handler UserRestHandlerImpl) FetchDetailedRoleGroups(w http.ResponseWriter, r *http.Request) {
705-
userId, err := handler.userService.GetLoggedInUser(r)
706-
if userId == 0 || err != nil {
707-
common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized)
708-
return
709-
}
710-
token := r.Header.Get("token")
711-
isActionUserSuperAdmin := false
712-
if ok := handler.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionGet, "*"); ok {
713-
isActionUserSuperAdmin = true
714-
}
715-
if !isActionUserSuperAdmin {
716-
common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden)
680+
req := &bean.FetchListingRequest{}
681+
err = decoder.Decode(req, r.URL.Query())
682+
if err != nil {
683+
handler.logger.Errorw("request err, FetchRoleGroups", "err", err, "payload", req)
684+
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
717685
return
718686
}
719-
720-
res, err := handler.roleGroupService.FetchDetailedRoleGroups()
687+
res, err := handler.roleGroupService.FetchRoleGroupsWithFilters(req)
721688
if err != nil {
722689
handler.logger.Errorw("service err, FetchRoleGroups", "err", err)
723690
common.WriteJsonResp(w, err, "", http.StatusInternalServerError)

api/auth/user/UserRouter.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,6 @@ func (router UserRouterImpl) InitUserRouter(userAuthRouter *mux.Router) {
4949
userAuthRouter.Path("/{id}").
5050
HandlerFunc(router.userRestHandler.DeleteUser).Methods("DELETE")
5151

52-
userAuthRouter.Path("/detail/get").
53-
HandlerFunc(router.userRestHandler.GetAllDetailedUsers).Methods("GET")
54-
5552
userAuthRouter.Path("/role/group/{id}").
5653
HandlerFunc(router.userRestHandler.FetchRoleGroupById).Methods("GET")
5754
userAuthRouter.Path("/role/group").
@@ -60,8 +57,6 @@ func (router UserRouterImpl) InitUserRouter(userAuthRouter *mux.Router) {
6057
HandlerFunc(router.userRestHandler.UpdateRoleGroup).Methods("PUT")
6158
userAuthRouter.Path("/role/group").
6259
HandlerFunc(router.userRestHandler.FetchRoleGroups).Methods("GET")
63-
userAuthRouter.Path("/role/group/detailed/get").
64-
HandlerFunc(router.userRestHandler.FetchDetailedRoleGroups).Methods("GET")
6560
userAuthRouter.Path("/role/group/search").
6661
Queries("name", "{name}").
6762
HandlerFunc(router.userRestHandler.FetchRoleGroupsByName).Methods("GET")

api/auth/user/wire_user.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ import (
55
"github.com/devtron-labs/devtron/pkg/auth/authorisation/casbin"
66
user2 "github.com/devtron-labs/devtron/pkg/auth/user"
77
repository2 "github.com/devtron-labs/devtron/pkg/auth/user/repository"
8+
"github.com/devtron-labs/devtron/pkg/auth/user/repository/helper"
89
"github.com/google/wire"
910
)
1011

1112
//depends on sql,validate,logger
1213

1314
var UserWireSet = wire.NewSet(
1415
UserAuditWireSet,
15-
16+
helper.NewUserRepositoryQueryBuilder,
1617
NewUserAuthRouterImpl,
1718
wire.Bind(new(UserAuthRouter), new(*UserAuthRouterImpl)),
1819
NewUserAuthHandlerImpl,

api/bean/UserRequest.go

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package bean
1919

2020
import (
2121
"encoding/json"
22+
"github.com/devtron-labs/devtron/pkg/auth/user/bean"
2223
"time"
2324
)
2425

@@ -29,19 +30,20 @@ type UserRole struct {
2930
}
3031

3132
type UserInfo struct {
32-
Id int32 `json:"id" validate:"number"`
33-
EmailId string `json:"email_id" validate:"required"`
34-
Roles []string `json:"roles,omitempty"`
35-
AccessToken string `json:"access_token,omitempty"`
36-
UserType string `json:"-"`
37-
LastUsedAt time.Time `json:"-"`
38-
LastUsedByIp string `json:"-"`
39-
Exist bool `json:"-"`
40-
UserId int32 `json:"-"` // created or modified user id
41-
RoleFilters []RoleFilter `json:"roleFilters"`
42-
Status string `json:"status,omitempty"`
43-
Groups []string `json:"groups"`
44-
SuperAdmin bool `json:"superAdmin,notnull"`
33+
Id int32 `json:"id" validate:"number,not-system-admin-userid"`
34+
EmailId string `json:"emailId" validate:"required,not-system-admin-user"`
35+
Roles []string `json:"roles,omitempty"`
36+
AccessToken string `json:"access_token,omitempty"`
37+
RoleFilters []RoleFilter `json:"roleFilters"`
38+
Status string `json:"status,omitempty"`
39+
Groups []string `json:"groups"` // this will be deprecated in future do not use
40+
SuperAdmin bool `json:"superAdmin,notnull"`
41+
LastLoginTime time.Time `json:"lastLoginTime"`
42+
UserType string `json:"-"`
43+
LastUsedAt time.Time `json:"-"`
44+
LastUsedByIp string `json:"-"`
45+
Exist bool `json:"-"`
46+
UserId int32 `json:"-"` // created or modified user id
4547
}
4648

4749
type RoleGroup struct {
@@ -117,3 +119,23 @@ const (
117119
CHART_GROUP_ENTITY = "chart-group"
118120
CLUSTER_ENTITIY = "cluster"
119121
)
122+
123+
type UserListingResponse struct {
124+
Users []UserInfo `json:"users"`
125+
TotalCount int `json:"totalCount"`
126+
}
127+
128+
type RoleGroupListingResponse struct {
129+
RoleGroups []*RoleGroup `json:"roleGroups"`
130+
TotalCount int `json:"totalCount"`
131+
}
132+
133+
type FetchListingRequest struct {
134+
SearchKey string `json:"searchKey"`
135+
SortOrder bean.SortOrder `json:"sortOrder"`
136+
SortBy bean.SortBy `json:"sortBy"`
137+
Offset int `json:"offset"`
138+
Size int `json:"size"`
139+
ShowAll bool `json:"showAll"`
140+
CountCheck bool `json:"-"`
141+
}

cmd/external-app/wire_gen.go

Lines changed: 4 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/util/ValidateUtil.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package util
1919

2020
import (
21+
"github.com/devtron-labs/devtron/pkg/auth/user/bean"
2122
"regexp"
2223
"strings"
2324

@@ -94,9 +95,33 @@ func IntValidator() (*validator.Validate, error) {
9495
if err != nil {
9596
return v, err
9697
}
98+
err = v.RegisterValidation("not-system-admin-user", validateForSystemOrAdminUser)
99+
if err != nil {
100+
return v, err
101+
}
102+
err = v.RegisterValidation("not-system-admin-userid", validateForSystemOrAdminUserById)
103+
if err != nil {
104+
return v, err
105+
}
97106
return v, err
98107
}
99108

109+
func validateForSystemOrAdminUser(fl validator.FieldLevel) bool {
110+
value := fl.Field().String()
111+
if value == bean.AdminUser || value == bean.SystemUser {
112+
return false
113+
}
114+
return true
115+
}
116+
117+
func validateForSystemOrAdminUserById(fl validator.FieldLevel) bool {
118+
value := fl.Field().Int()
119+
if value == bean.AdminUserId || value == bean.SystemUserId {
120+
return false
121+
}
122+
return true
123+
}
124+
100125
func validateDockerImage(fl validator.FieldLevel) bool {
101126
value := fl.Field().String()
102127
if strings.Contains(value, ":") {

0 commit comments

Comments
 (0)