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 4 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
81 changes: 72 additions & 9 deletions api/auth/user/UserRestHandler.go
Original file line number Diff line number Diff line change
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 = "admin@github.com/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 == "admin@github.com/devtron-labs" {
userInfo.EmailId = "admin"
}

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

if err != nil {
Expand Down Expand Up @@ -362,7 +355,42 @@ 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()
// check query param
params := r.URL.Query()
searchKey := params.Get("searchKey")
sortOrder := params.Get("sortOrder")
sortBy := params.Get("sortBy")
offsetString := params.Get("offset")
var offset int
if len(offsetString) > 0 {
offset, err = strconv.Atoi(offsetString)
if err != nil {
handler.logger.Errorw("request err, GetAll", "err", err, "offset", offset)
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
return
}
}
sizeString := params.Get("size")
var size int
if len(sizeString) > 0 {
size, err = strconv.Atoi(sizeString)
if err != nil {
handler.logger.Errorw("request err, GetAll", "err", err, "size", size)
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
return
}
}
showAllString := params.Get("showAll")
showAll := false
if len(showAllString) > 0 {
showAll, err = strconv.ParseBool(showAllString)
if err != nil {
handler.logger.Errorw("request err, GetAll", "err", err, "showAll", showAll)
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
return
}
}
kartik-579 marked this conversation as resolved.
Show resolved Hide resolved
res, err := handler.userService.GetAllWithFilters(sortOrder, sortBy, offset, size, showAll, searchKey)
kartik-579 marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
handler.logger.Errorw("service err, GetAll", "err", err)
common.WriteJsonResp(w, err, "Failed to Get", http.StatusInternalServerError)
Expand Down Expand Up @@ -692,7 +720,42 @@ func (handler UserRestHandlerImpl) FetchRoleGroups(w http.ResponseWriter, r *htt
common.WriteJsonResp(w, errors.New("unauthorized"), nil, http.StatusForbidden)
return
}
res, err := handler.roleGroupService.FetchRoleGroups()
// check query param
params := r.URL.Query()
sortOrder := params.Get("sortOrder")
searchKey := params.Get("searchKey")
sortBy := params.Get("sortBy")
offsetString := params.Get("offset")
var offset int
if len(offsetString) > 0 {
offset, err = strconv.Atoi(offsetString)
if err != nil {
handler.logger.Errorw("request err, FetchRoleGroups", "err", err, "offset", offset)
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
return
}
}
sizeString := params.Get("size")
var size int
if len(sizeString) > 0 {
size, err = strconv.Atoi(sizeString)
if err != nil {
handler.logger.Errorw("request err, FetchRoleGroups", "err", err, "size", size)
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
return
}
}
showAllString := params.Get("showAll")
showAll := false
if len(showAllString) > 0 {
showAll, err = strconv.ParseBool(showAllString)
if err != nil {
handler.logger.Errorw("request err, FetchRoleGroups", "err", err, "showAll", showAll)
common.WriteJsonResp(w, err, nil, http.StatusBadRequest)
return
}
kartik-579 marked this conversation as resolved.
Show resolved Hide resolved
}
res, err := handler.roleGroupService.FetchRoleGroupsWithFilters(sortOrder, sortBy, offset, size, showAll, searchKey)
kartik-579 marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
handler.logger.Errorw("service err, FetchRoleGroups", "err", err)
common.WriteJsonResp(w, err, "", http.StatusInternalServerError)
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
47 changes: 34 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"`
UserType string `json:"-"`
LastUsedAt time.Time `json:"-"`
LastUsedByIp string `json:"-"`
Exist bool `json:"-"`
UserId int32 `json:"-"` // created or modified user id
kartik-579 marked this conversation as resolved.
Show resolved Hide resolved
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"`
}

type RoleGroup struct {
Expand Down Expand Up @@ -117,3 +119,22 @@ 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"`
}
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.

24 changes: 24 additions & 0 deletions internal/util/ValidateUtil.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,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 == "admin" || value == "system" {
kartik-579 marked this conversation as resolved.
Show resolved Hide resolved
return false
}
return true
}

func validateForSystemOrAdminUserById(fl validator.FieldLevel) bool {
value := fl.Field().Int()
if value == 1 || value == 2 {
kartik-579 marked this conversation as resolved.
Show resolved Hide resolved
return false
}
return true
}

func validateDockerImage(fl validator.FieldLevel) bool {
value := fl.Field().String()
if strings.Contains(value, ":") {
Expand Down
92 changes: 76 additions & 16 deletions pkg/auth/user/RoleGroupService.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package user
import (
"errors"
"fmt"
"github.com/devtron-labs/devtron/pkg/auth/user/repository/helper"
"strings"
"time"

Expand All @@ -40,29 +41,33 @@ type RoleGroupService interface {
UpdateRoleGroup(request *bean.RoleGroup, token string, managerAuth func(resource, token string, object string) bool) (*bean.RoleGroup, error)
FetchDetailedRoleGroups() ([]*bean.RoleGroup, error)
FetchRoleGroupsById(id int32) (*bean.RoleGroup, error)
FetchRoleGroups() ([]*bean.RoleGroup, error)
FetchRoleGroups() (*bean.RoleGroupListingResponse, error)
FetchRoleGroupsWithFilters(sortOrder string, sortBy string, offset int, totalSize int, showAll bool, searchKey string) (*bean.RoleGroupListingResponse, error)
FetchRoleGroupsByName(name string) ([]*bean.RoleGroup, error)
DeleteRoleGroup(model *bean.RoleGroup) (bool, error)
FetchRolesForGroups(groupNames []string) ([]*bean.RoleFilter, error)
}

type RoleGroupServiceImpl struct {
userAuthRepository repository.UserAuthRepository
logger *zap.SugaredLogger
userRepository repository.UserRepository
roleGroupRepository repository.RoleGroupRepository
userCommonService UserCommonService
userAuthRepository repository.UserAuthRepository
logger *zap.SugaredLogger
userRepository repository.UserRepository
roleGroupRepository repository.RoleGroupRepository
userCommonService UserCommonService
userRepositoryQueryBuilder helper.UserRepositoryQueryBuilder
}

func NewRoleGroupServiceImpl(userAuthRepository repository.UserAuthRepository,
logger *zap.SugaredLogger, userRepository repository.UserRepository,
roleGroupRepository repository.RoleGroupRepository, userCommonService UserCommonService) *RoleGroupServiceImpl {
roleGroupRepository repository.RoleGroupRepository, userCommonService UserCommonService,
userRepositoryQueryBuilder helper.UserRepositoryQueryBuilder) *RoleGroupServiceImpl {
serviceImpl := &RoleGroupServiceImpl{
userAuthRepository: userAuthRepository,
logger: logger,
userRepository: userRepository,
roleGroupRepository: roleGroupRepository,
userCommonService: userCommonService,
userAuthRepository: userAuthRepository,
logger: logger,
userRepository: userRepository,
roleGroupRepository: roleGroupRepository,
userCommonService: userCommonService,
userRepositoryQueryBuilder: userRepositoryQueryBuilder,
}
cStore = sessions.NewCookieStore(randKey())
return serviceImpl
Expand Down Expand Up @@ -619,12 +624,67 @@ func (impl RoleGroupServiceImpl) FetchDetailedRoleGroups() ([]*bean.RoleGroup, e
return list, nil
}

func (impl RoleGroupServiceImpl) FetchRoleGroups() ([]*bean.RoleGroup, error) {
roleGroup, err := impl.roleGroupRepository.GetAllRoleGroup()
func (impl RoleGroupServiceImpl) FetchRoleGroups() (*bean.RoleGroupListingResponse, error) {
list, err := impl.FetchDetailedRoleGroups()
if err != nil {
impl.logger.Errorw("error while fetching user from db", "error", err)
impl.logger.Errorw("error in FetchDetailedRoleGroups", "err", err)
return nil, err
}
response := &bean.RoleGroupListingResponse{
RoleGroups: list,
TotalCount: len(list),
}
return response, nil
}

// FetchRoleGroupsWithFilters takes filters args as input and outputs RoleGroupListingResponse based on the request filters.
func (impl RoleGroupServiceImpl) FetchRoleGroupsWithFilters(sortOrder string, sortBy string, offset int, totalSize int, showAll bool, searchKey string) (*bean.RoleGroupListingResponse, error) {
// getting request from filter args
Shivam-nagar23 marked this conversation as resolved.
Show resolved Hide resolved
request := impl.getRequestWithFiltersArgs(sortOrder, sortBy, offset, totalSize, showAll, searchKey)
if request.ShowAll {
return impl.FetchRoleGroups()
}
// Setting size as zero to calculate the total number of results based on request
size := request.Size
request.Size = 0

query := impl.userRepositoryQueryBuilder.GetQueryForGroupListingWithFilters(request)
totalCount, err := impl.userRepository.GetCountExecutingQuery(query)
if err != nil {
impl.logger.Errorw("error in FetchRoleGroupsWithFilters", "err", err, "query", query)
return nil, err
}

request.Size = size
query = impl.userRepositoryQueryBuilder.GetQueryForGroupListingWithFilters(request)
roleGroup, err := impl.roleGroupRepository.GetAllExecutingQuery(query)
if err != nil {
impl.logger.Errorw("error while FetchRoleGroupsWithFilters", "error", err, "query", query)
return nil, err
}

list := impl.fetchRoleGroupResponseFromModel(roleGroup)
response := &bean.RoleGroupListingResponse{
RoleGroups: list,
TotalCount: totalCount,
}
kartik-579 marked this conversation as resolved.
Show resolved Hide resolved
return response, nil
}

func (impl RoleGroupServiceImpl) getRequestWithFiltersArgs(sortOrder string, sortBy string, offset int, totalSize int, showAll bool, searchKey string) *bean.FetchListingRequest {
sortByRes, size := impl.userCommonService.GetDefaultValuesIfNotPresent(sortBy, totalSize, true)
kartik-579 marked this conversation as resolved.
Show resolved Hide resolved
request := &bean.FetchListingRequest{
SortOrder: bean2.SortOrder(sortOrder),
SortBy: sortByRes,
Offset: offset,
Size: size,
ShowAll: showAll,
SearchKey: searchKey,
}
return request
}

func (impl RoleGroupServiceImpl) fetchRoleGroupResponseFromModel(roleGroup []*repository.RoleGroup) []*bean.RoleGroup {
var list []*bean.RoleGroup
for _, item := range roleGroup {
bean := &bean.RoleGroup{
Expand All @@ -639,7 +699,7 @@ func (impl RoleGroupServiceImpl) FetchRoleGroups() ([]*bean.RoleGroup, error) {
if len(list) == 0 {
list = make([]*bean.RoleGroup, 0)
}
return list, nil
return list
}

func (impl RoleGroupServiceImpl) FetchRoleGroupsByName(name string) ([]*bean.RoleGroup, error) {
Expand Down
1 change: 1 addition & 0 deletions pkg/auth/user/UserAuditService.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ func (impl UserAuditServiceImpl) Save(userAudit *UserAudit) error {
UserId: userId,
ClientIp: userAudit.ClientIp,
CreatedOn: userAudit.CreatedOn,
UpdatedOn: userAudit.UpdatedOn,
}
err := impl.userAuditRepository.Save(userAuditDb)
if err != nil {
Expand Down
Loading
Loading