Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: active inactive user phase 1 #4589

Merged
merged 35 commits into from
Feb 8, 2024
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
ebedf11
listing user and group changes
Shivam-nagar23 Jan 25, 2024
a628719
default value chnage
Shivam-nagar23 Jan 25, 2024
d54de55
group listing optimisation
Shivam-nagar23 Jan 25, 2024
a4baf56
wire_gen
Shivam-nagar23 Jan 25, 2024
08465d3
order by in group
Shivam-nagar23 Jan 25, 2024
2854bf0
Merge branch 'main' into feat-active-inactive-user-phase-1
Shivam-nagar23 Jan 27, 2024
37ffe40
default values
Shivam-nagar23 Jan 29, 2024
a68c624
discard
Shivam-nagar23 Jan 29, 2024
e3c482d
updated on
Shivam-nagar23 Jan 29, 2024
defe28f
case insensitive
Shivam-nagar23 Jan 29, 2024
000a883
Merge branch 'main' into feat-active-inactive-user-phase-1
Shivam-nagar23 Jan 29, 2024
eac977e
script number change
Shivam-nagar23 Jan 29, 2024
8801233
specs
Shivam-nagar23 Jan 29, 2024
b50f89c
review chnages
Shivam-nagar23 Jan 30, 2024
1cce3af
sql update
Shivam-nagar23 Jan 30, 2024
1febba6
id for user
Shivam-nagar23 Jan 30, 2024
6603a0a
Merge branch 'main' into feat-active-inactive-user-phase-1
Shivam-nagar23 Jan 31, 2024
046f47a
script number chnage
Shivam-nagar23 Jan 31, 2024
a93a59d
review comments-1
Shivam-nagar23 Jan 31, 2024
00cd1d5
review comments
Shivam-nagar23 Jan 31, 2024
befeca7
review comments
Shivam-nagar23 Jan 31, 2024
5ef0552
rest handler remove methods
Shivam-nagar23 Jan 31, 2024
5920a87
validation for delete
Shivam-nagar23 Jan 31, 2024
79ea449
delete user handling
Shivam-nagar23 Jan 31, 2024
47e0656
review comments
Shivam-nagar23 Feb 1, 2024
d1ad254
review comments
Shivam-nagar23 Feb 1, 2024
c2c5fb5
Merge branch 'main' into feat-active-inactive-user-phase-1
Shivam-nagar23 Feb 5, 2024
4448c9e
export csv filters support
Shivam-nagar23 Feb 5, 2024
cde92a2
Revert "export csv filters support"
Shivam-nagar23 Feb 5, 2024
3b3496f
Merge branch 'main' into feat-active-inactive-user-phase-1
Shivam-nagar23 Feb 5, 2024
feee76e
Merge branch 'main' into feat-active-inactive-user-phase-1
Shivam-nagar23 Feb 5, 2024
a61f732
Merge branch 'main' into feat-active-inactive-user-phase-1
Shivam-nagar23 Feb 6, 2024
2c6f3b7
main-merge
Shivam-nagar23 Feb 6, 2024
9dd58b6
Merge branch 'main' into feat-active-inactive-user-phase-1
Shivam-nagar23 Feb 7, 2024
9efa163
main-merge
Shivam-nagar23 Feb 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 25 additions & 58 deletions api/auth/user/UserRestHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/devtron-labs/devtron/pkg/auth/user/helper"
"github.com/gorilla/schema"
"net/http"
"strconv"
"strings"
Expand All @@ -44,12 +46,10 @@ type UserRestHandler interface {
GetById(w http.ResponseWriter, r *http.Request)
GetAll(w http.ResponseWriter, r *http.Request)
DeleteUser(w http.ResponseWriter, r *http.Request)
GetAllDetailedUsers(w http.ResponseWriter, r *http.Request)
FetchRoleGroupById(w http.ResponseWriter, r *http.Request)
CreateRoleGroup(w http.ResponseWriter, r *http.Request)
UpdateRoleGroup(w http.ResponseWriter, r *http.Request)
FetchRoleGroups(w http.ResponseWriter, r *http.Request)
FetchDetailedRoleGroups(w http.ResponseWriter, r *http.Request)
FetchRoleGroupsByName(w http.ResponseWriter, r *http.Request)
DeleteRoleGroup(w http.ResponseWriter, r *http.Request)
CheckUserRoles(w http.ResponseWriter, r *http.Request)
Expand Down Expand Up @@ -210,20 +210,13 @@ func (handler UserRestHandlerImpl) UpdateUser(w http.ResponseWriter, r *http.Req
// RBAC enforcer applying
token := r.Header.Get("token")

if userInfo.EmailId == "admin" {
userInfo.EmailId = "[email protected]/devtron-labs"
}
err = handler.validator.Struct(userInfo)
if err != nil {
handler.logger.Errorw("validation err, UpdateUser", "err", err, "payload", userInfo)
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
return
}

if userInfo.EmailId == "[email protected]/devtron-labs" {
userInfo.EmailId = "admin"
}

res, rolesChanged, groupsModified, restrictedGroups, err := handler.userService.UpdateUser(&userInfo, token, handler.CheckManagerAuth)

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

func (handler UserRestHandlerImpl) GetAll(w http.ResponseWriter, r *http.Request) {
var decoder = schema.NewDecoder()
userId, err := handler.userService.GetLoggedInUser(r)
if userId == 0 || err != nil {
common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized)
Expand Down Expand Up @@ -362,35 +356,16 @@ func (handler UserRestHandlerImpl) GetAll(w http.ResponseWriter, r *http.Request
common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden)
return
}
res, err := handler.userService.GetAll()
req := &bean.FetchListingRequest{}
err = decoder.Decode(req, r.URL.Query())
if err != nil {
handler.logger.Errorw("service err, GetAll", "err", err)
common.WriteJsonResp(w, err, "Failed to Get", http.StatusInternalServerError)
return
}

common.WriteJsonResp(w, err, res, http.StatusOK)
}

func (handler UserRestHandlerImpl) GetAllDetailedUsers(w http.ResponseWriter, r *http.Request) {
userId, err := handler.userService.GetLoggedInUser(r)
if userId == 0 || err != nil {
common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized)
return
}

token := r.Header.Get("token")
isActionUserSuperAdmin := false
if ok := handler.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionGet, "*"); ok {
isActionUserSuperAdmin = true
}
if !isActionUserSuperAdmin {
common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden)
handler.logger.Errorw("request err, GetAll", "err", err, "payload", req)
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
return
}
res, err := handler.userService.GetAllDetailedUsers()
res, err := handler.userService.GetAllWithFilters(req)
if err != nil {
handler.logger.Errorw("service err, GetAllDetailedUsers", "err", err)
handler.logger.Errorw("service err, GetAll", "err", err)
kartik-579 marked this conversation as resolved.
Show resolved Hide resolved
common.WriteJsonResp(w, err, "Failed to Get", http.StatusInternalServerError)
return
}
Expand Down Expand Up @@ -451,7 +426,15 @@ func (handler UserRestHandlerImpl) DeleteUser(w http.ResponseWriter, r *http.Req
}
}
//RBAC enforcer Ends

//validation
validated := helper.CheckIfUserDevtronManaged(int32(id))
if !validated {
err = &util.ApiError{Code: "400", HttpStatusCode: 400, UserMessage: "cannot delete system or admin user"}
handler.logger.Errorw("request err, DeleteUser, validation failed", "id", id, "err", err)
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
return
}
//service call
res, err := handler.userService.DeleteUser(user)
if err != nil {
handler.logger.Errorw("service err, DeleteUser", "err", err, "id", id)
Expand Down Expand Up @@ -639,6 +622,7 @@ func (handler UserRestHandlerImpl) UpdateRoleGroup(w http.ResponseWriter, r *htt
}

func (handler UserRestHandlerImpl) FetchRoleGroups(w http.ResponseWriter, r *http.Request) {
var decoder = schema.NewDecoder()
userId, err := handler.userService.GetLoggedInUser(r)
if userId == 0 || err != nil {
common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized)
Expand Down Expand Up @@ -692,32 +676,15 @@ func (handler UserRestHandlerImpl) FetchRoleGroups(w http.ResponseWriter, r *htt
common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden)
return
}
res, err := handler.roleGroupService.FetchRoleGroups()
if err != nil {
handler.logger.Errorw("service err, FetchRoleGroups", "err", err)
common.WriteJsonResp(w, err, "", http.StatusInternalServerError)
return
}
common.WriteJsonResp(w, err, res, http.StatusOK)
}

func (handler UserRestHandlerImpl) FetchDetailedRoleGroups(w http.ResponseWriter, r *http.Request) {
userId, err := handler.userService.GetLoggedInUser(r)
if userId == 0 || err != nil {
common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized)
return
}
token := r.Header.Get("token")
isActionUserSuperAdmin := false
if ok := handler.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionGet, "*"); ok {
isActionUserSuperAdmin = true
}
if !isActionUserSuperAdmin {
common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden)
req := &bean.FetchListingRequest{}
err = decoder.Decode(req, r.URL.Query())
if err != nil {
handler.logger.Errorw("request err, FetchRoleGroups", "err", err, "payload", req)
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
return
}

res, err := handler.roleGroupService.FetchDetailedRoleGroups()
res, err := handler.roleGroupService.FetchRoleGroupsWithFilters(req)
if err != nil {
handler.logger.Errorw("service err, FetchRoleGroups", "err", err)
common.WriteJsonResp(w, err, "", http.StatusInternalServerError)
Expand Down
5 changes: 0 additions & 5 deletions api/auth/user/UserRouter.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,6 @@ func (router UserRouterImpl) InitUserRouter(userAuthRouter *mux.Router) {
userAuthRouter.Path("/{id}").
HandlerFunc(router.userRestHandler.DeleteUser).Methods("DELETE")

userAuthRouter.Path("/detail/get").
HandlerFunc(router.userRestHandler.GetAllDetailedUsers).Methods("GET")

userAuthRouter.Path("/role/group/{id}").
HandlerFunc(router.userRestHandler.FetchRoleGroupById).Methods("GET")
userAuthRouter.Path("/role/group").
Expand All @@ -60,8 +57,6 @@ func (router UserRouterImpl) InitUserRouter(userAuthRouter *mux.Router) {
HandlerFunc(router.userRestHandler.UpdateRoleGroup).Methods("PUT")
userAuthRouter.Path("/role/group").
HandlerFunc(router.userRestHandler.FetchRoleGroups).Methods("GET")
userAuthRouter.Path("/role/group/detailed/get").
HandlerFunc(router.userRestHandler.FetchDetailedRoleGroups).Methods("GET")
userAuthRouter.Path("/role/group/search").
Queries("name", "{name}").
HandlerFunc(router.userRestHandler.FetchRoleGroupsByName).Methods("GET")
Expand Down
3 changes: 2 additions & 1 deletion api/auth/user/wire_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import (
"github.com/devtron-labs/devtron/pkg/auth/authorisation/casbin"
user2 "github.com/devtron-labs/devtron/pkg/auth/user"
repository2 "github.com/devtron-labs/devtron/pkg/auth/user/repository"
"github.com/devtron-labs/devtron/pkg/auth/user/repository/helper"
"github.com/google/wire"
)

//depends on sql,validate,logger

var UserWireSet = wire.NewSet(
UserAuditWireSet,

helper.NewUserRepositoryQueryBuilder,
NewUserAuthRouterImpl,
wire.Bind(new(UserAuthRouter), new(*UserAuthRouterImpl)),
NewUserAuthHandlerImpl,
Expand Down
48 changes: 35 additions & 13 deletions api/bean/UserRequest.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package bean

import (
"encoding/json"
"github.com/devtron-labs/devtron/pkg/auth/user/bean"
"time"
)

Expand All @@ -29,19 +30,20 @@ type UserRole struct {
}

type UserInfo struct {
Id int32 `json:"id" validate:"number"`
EmailId string `json:"email_id" validate:"required"`
Roles []string `json:"roles,omitempty"`
AccessToken string `json:"access_token,omitempty"`
UserType string `json:"-"`
LastUsedAt time.Time `json:"-"`
LastUsedByIp string `json:"-"`
Exist bool `json:"-"`
UserId int32 `json:"-"` // created or modified user id
RoleFilters []RoleFilter `json:"roleFilters"`
Status string `json:"status,omitempty"`
Groups []string `json:"groups"`
SuperAdmin bool `json:"superAdmin,notnull"`
Id int32 `json:"id" validate:"number,not-system-admin-userid"`
EmailId string `json:"emailId" validate:"required,not-system-admin-user"`
Roles []string `json:"roles,omitempty"`
AccessToken string `json:"access_token,omitempty"`
RoleFilters []RoleFilter `json:"roleFilters"`
Status string `json:"status,omitempty"`
Groups []string `json:"groups"` // this will be deprecated in future do not use
SuperAdmin bool `json:"superAdmin,notnull"`
LastLoginTime time.Time `json:"lastLoginTime"`
UserType string `json:"-"`
LastUsedAt time.Time `json:"-"`
LastUsedByIp string `json:"-"`
Exist bool `json:"-"`
UserId int32 `json:"-"` // created or modified user id
}

type RoleGroup struct {
Expand Down Expand Up @@ -117,3 +119,23 @@ const (
CHART_GROUP_ENTITY = "chart-group"
CLUSTER_ENTITIY = "cluster"
)

type UserListingResponse struct {
Users []UserInfo `json:"users"`
TotalCount int `json:"totalCount"`
}

type RoleGroupListingResponse struct {
RoleGroups []*RoleGroup `json:"roleGroups"`
TotalCount int `json:"totalCount"`
}

type FetchListingRequest struct {
SearchKey string `json:"searchKey"`
SortOrder bean.SortOrder `json:"sortOrder"`
SortBy bean.SortBy `json:"sortBy"`
Offset int `json:"offset"`
Size int `json:"size"`
ShowAll bool `json:"showAll"`
CountCheck bool `json:"-"`
}
6 changes: 4 additions & 2 deletions cmd/external-app/wire_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions internal/util/ValidateUtil.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package util

import (
"github.com/devtron-labs/devtron/pkg/auth/user/bean"
"regexp"
"strings"

Expand Down Expand Up @@ -94,9 +95,33 @@ func IntValidator() (*validator.Validate, error) {
if err != nil {
return v, err
}
err = v.RegisterValidation("not-system-admin-user", validateForSystemOrAdminUser)
if err != nil {
return v, err
}
err = v.RegisterValidation("not-system-admin-userid", validateForSystemOrAdminUserById)
if err != nil {
return v, err
}
return v, err
}

func validateForSystemOrAdminUser(fl validator.FieldLevel) bool {
value := fl.Field().String()
if value == bean.AdminUser || value == bean.SystemUser {
return false
}
return true
}

func validateForSystemOrAdminUserById(fl validator.FieldLevel) bool {
value := fl.Field().Int()
if value == bean.AdminUserId || value == bean.SystemUserId {
return false
}
return true
}

func validateDockerImage(fl validator.FieldLevel) bool {
value := fl.Field().String()
if strings.Contains(value, ":") {
Expand Down
Loading
Loading