diff --git a/chaoscenter/authentication/api/handlers/grpc/grpc_handler.go b/chaoscenter/authentication/api/handlers/grpc/grpc_handler.go index 984677537e7..9851b7a7a91 100644 --- a/chaoscenter/authentication/api/handlers/grpc/grpc_handler.go +++ b/chaoscenter/authentication/api/handlers/grpc/grpc_handler.go @@ -59,7 +59,7 @@ func (s *ServerGrpc) GetProjectById(ctx context.Context, for _, member := range project.Members { var projectMember protos.ProjectMembers projectMember.Email = memberMap[member.UserID].Email - projectMember.UserName = memberMap[member.UserID].UserName + projectMember.Username = memberMap[member.UserID].Username projectMember.Invitation = string(member.Invitation) projectMember.Uid = member.UserID projectMember.JoinedAt = member.JoinedAt @@ -94,7 +94,7 @@ func (s *ServerGrpc) GetUserById(ctx context.Context, return &protos.GetUserByIdResponse{ Id: user.ID, Name: user.Name, - Username: user.UserName, + Username: user.Username, CreatedAt: strconv.FormatInt(user.CreatedAt, 10), UpdatedAt: strconv.FormatInt(user.UpdatedAt, 10), DeactivatedAt: deactivatedAt, diff --git a/chaoscenter/authentication/api/handlers/rest/dex_auth_handler.go b/chaoscenter/authentication/api/handlers/rest/dex_auth_handler.go index 81ac32ad488..7ab3432d81c 100644 --- a/chaoscenter/authentication/api/handlers/rest/dex_auth_handler.go +++ b/chaoscenter/authentication/api/handlers/rest/dex_auth_handler.go @@ -102,7 +102,7 @@ func DexCallback(userService services.ApplicationService) gin.HandlerFunc { var userData = entities.User{ Name: claims.Name, Email: claims.Email, - UserName: claims.Email, + Username: claims.Email, Role: entities.RoleUser, Audit: entities.Audit{ CreatedAt: createdAt, diff --git a/chaoscenter/authentication/api/handlers/rest/project_handler.go b/chaoscenter/authentication/api/handlers/rest/project_handler.go index 2157535baaa..920c5acd32f 100644 --- a/chaoscenter/authentication/api/handlers/rest/project_handler.go +++ b/chaoscenter/authentication/api/handlers/rest/project_handler.go @@ -6,7 +6,6 @@ import ( "time" "github.com/litmuschaos/litmus/chaoscenter/authentication/api/presenter" - "github.com/litmuschaos/litmus/chaoscenter/authentication/api/types" "github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/entities" "github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/services" "github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/utils" @@ -75,53 +74,7 @@ func GetProject(service services.ApplicationService) gin.HandlerFunc { return } - // Fetching user ids of all the members in the project - var uids []string - for _, member := range project.Members { - uids = append(uids, member.UserID) - } - - authUsers, err := service.FindUsersByUID(uids) - if err != nil { - log.Error(err) - c.JSON(utils.ErrorStatusCodes[utils.ErrServerError], presenter.CreateErrorResponse(utils.ErrServerError)) - return - } - - memberMap := make(map[string]entities.User) - for _, authUser := range *authUsers { - memberMap[authUser.ID] = authUser - } - - var members []*types.Member - - // Adding additional details of project members - for _, member := range project.Members { - members = append(members, &types.Member{ - UserID: memberMap[member.UserID].ID, - UserName: memberMap[member.UserID].UserName, - Name: memberMap[member.UserID].Name, - Role: member.Role, - Email: memberMap[member.UserID].Email, - Invitation: member.Invitation, - JoinedAt: member.JoinedAt, - DeactivatedAt: memberMap[member.UserID].DeactivatedAt, - }) - } - - c.JSON(200, gin.H{"data": types.Project{ - ID: project.ID, - Name: project.Name, - State: project.State, - Audit: entities.Audit{ - IsRemoved: project.IsRemoved, - CreatedAt: project.CreatedAt, - CreatedBy: project.UpdatedBy, - UpdatedAt: project.UpdatedAt, - UpdatedBy: project.UpdatedBy, - }, - Members: members, - }}) + c.JSON(200, gin.H{"data": project}) } } @@ -141,59 +94,7 @@ func GetProjectsByUserID(service services.ApplicationService) gin.HandlerFunc { return } - var uids []string - - // Fetching user ids of all members from all user's projects - for _, project := range projects { - for _, member := range project.Members { - uids = append(uids, member.UserID) - } - } - authUsers, err := service.FindUsersByUID(uids) - if err != nil || authUsers == nil { - log.Error(err) - c.JSON(utils.ErrorStatusCodes[utils.ErrServerError], presenter.CreateErrorResponse(utils.ErrServerError)) - return - } - memberMap := make(map[string]entities.User) - - for _, authUser := range *authUsers { - memberMap[authUser.ID] = authUser - } - - var outputProjects []*types.Project - - // Adding additional details of project members - for _, project := range projects { - var members []*types.Member - for _, member := range project.Members { - members = append(members, &types.Member{ - UserID: memberMap[member.UserID].ID, - UserName: memberMap[member.UserID].UserName, - Name: memberMap[member.UserID].Name, - Role: member.Role, - Email: memberMap[member.UserID].Email, - Invitation: member.Invitation, - JoinedAt: member.JoinedAt, - DeactivatedAt: memberMap[member.UserID].DeactivatedAt, - }) - } - outputProjects = append(outputProjects, &types.Project{ - ID: project.ID, - Name: project.Name, - Members: members, - State: project.State, - Audit: entities.Audit{ - IsRemoved: project.IsRemoved, - CreatedAt: project.CreatedAt, - CreatedBy: project.UpdatedBy, - UpdatedAt: project.UpdatedAt, - UpdatedBy: project.UpdatedBy, - }, - }) - } - - c.JSON(200, gin.H{"data": outputProjects}) + c.JSON(200, gin.H{"data": projects}) } } @@ -221,6 +122,19 @@ func GetProjectStats(service services.ApplicationService) gin.HandlerFunc { } } +func GetActiveProjectMembers(service services.ApplicationService) gin.HandlerFunc { + return func(c *gin.Context) { + projectID := c.Param("project_id") + state := c.Param("state") + members, err := service.GetProjectMembers(projectID, state) + if err != nil { + c.JSON(utils.ErrorStatusCodes[utils.ErrServerError], presenter.CreateErrorResponse(utils.ErrServerError)) + return + } + c.JSON(200, gin.H{"data": members}) + } +} + // getInvitation returns the Invitation status func getInvitation(service services.ApplicationService, member entities.MemberInput) (entities.Invitation, error) { project, err := service.GetProjectByProjectID(member.ProjectID) @@ -291,9 +205,17 @@ func CreateProject(service services.ApplicationService) gin.HandlerFunc { Audit: entities.Audit{ IsRemoved: false, CreatedAt: time.Now().Unix(), - CreatedBy: user.ID, + CreatedBy: entities.UserDetailResponse{ + Username: user.Username, + UserID: user.ID, + Email: user.Email, + }, UpdatedAt: time.Now().Unix(), - UpdatedBy: user.ID, + UpdatedBy: entities.UserDetailResponse{ + Username: user.Username, + UserID: user.ID, + Email: user.Email, + }, }, } @@ -385,15 +307,14 @@ func SendInvitation(service services.ApplicationService) gin.HandlerFunc { return } - c.JSON(200, gin.H{"data": types.Member{ - UserID: user.ID, - UserName: user.UserName, - Name: user.Name, - Role: entities.MemberRole(newMember.Role), - Email: user.Email, - Invitation: entities.Invitation(newMember.Invitation), - JoinedAt: newMember.JoinedAt, - DeactivatedAt: user.DeactivatedAt, + c.JSON(200, gin.H{"data": entities.Member{ + UserID: user.ID, + Username: user.Username, + Name: user.Name, + Role: newMember.Role, + Email: user.Email, + Invitation: newMember.Invitation, + JoinedAt: newMember.JoinedAt, }}) } } @@ -610,7 +531,7 @@ func UpdateProjectName(service services.ApplicationService) gin.HandlerFunc { } } -// GetOwnerProject returns an array of project IDs in which user is an owner +// GetOwnerProjectIDs returns an array of project IDs in which user is an owner func GetOwnerProjectIDs(service services.ApplicationService) gin.HandlerFunc { return func(c *gin.Context) { uid := c.MustGet("uid").(string) diff --git a/chaoscenter/authentication/api/handlers/rest/user_handlers.go b/chaoscenter/authentication/api/handlers/rest/user_handlers.go index 75fb3b39dd0..023a2add707 100644 --- a/chaoscenter/authentication/api/handlers/rest/user_handlers.go +++ b/chaoscenter/authentication/api/handlers/rest/user_handlers.go @@ -37,8 +37,8 @@ func CreateUser(service services.ApplicationService) gin.HandlerFunc { return } - userRequest.UserName = utils.SanitizeString(userRequest.UserName) - if userRequest.Role == "" || userRequest.UserName == "" || userRequest.Password == "" { + userRequest.Username = utils.SanitizeString(userRequest.Username) + if userRequest.Role == "" || userRequest.Username == "" || userRequest.Password == "" { c.JSON(utils.ErrorStatusCodes[utils.ErrInvalidRequest], presenter.CreateErrorResponse(utils.ErrInvalidRequest)) return } @@ -138,6 +138,29 @@ func FetchUsers(service services.ApplicationService) gin.HandlerFunc { } } +func InviteUsers(service services.ApplicationService) gin.HandlerFunc { + return func(c *gin.Context) { + projectID := c.Param("project_id") + if projectID == "" { + c.JSON(utils.ErrorStatusCodes[utils.ErrInvalidRequest], presenter.CreateErrorResponse(utils.ErrInvalidRequest)) + return + } + projectMembers, err := service.GetProjectMembers(projectID, "all") + + var uids []string + for _, k := range projectMembers { + uids = append(uids, k.UserID) + } + users, err := service.InviteUsers(uids) + if err != nil { + log.Error(err) + c.JSON(utils.ErrorStatusCodes[utils.ErrServerError], presenter.CreateErrorResponse(utils.ErrServerError)) + return + } + c.JSON(200, users) + } +} + func LoginUser(service services.ApplicationService) gin.HandlerFunc { return func(c *gin.Context) { var userRequest entities.User @@ -147,14 +170,14 @@ func LoginUser(service services.ApplicationService) gin.HandlerFunc { c.JSON(utils.ErrorStatusCodes[utils.ErrInvalidRequest], presenter.CreateErrorResponse(utils.ErrInvalidRequest)) return } - userRequest.UserName = utils.SanitizeString(userRequest.UserName) - if userRequest.UserName == "" || userRequest.Password == "" { + userRequest.Username = utils.SanitizeString(userRequest.Username) + if userRequest.Username == "" || userRequest.Password == "" { c.JSON(utils.ErrorStatusCodes[utils.ErrInvalidRequest], presenter.CreateErrorResponse(utils.ErrInvalidRequest)) return } // Checking if user exists - user, err := service.FindUserByUsername(userRequest.UserName) + user, err := service.FindUserByUsername(userRequest.Username) if err != nil { log.Error(err) c.JSON(utils.ErrorStatusCodes[utils.ErrUserNotFound], presenter.CreateErrorResponse(utils.ErrUserNotFound)) @@ -201,15 +224,23 @@ func LoginUser(service services.ApplicationService) gin.HandlerFunc { state := "active" newProject := &entities.Project{ ID: uuid.Must(uuid.NewRandom()).String(), - Name: user.UserName + "'s project", + Name: user.Username + "'s project", Members: members, State: &state, Audit: entities.Audit{ IsRemoved: false, CreatedAt: time.Now().Unix(), - CreatedBy: user.ID, + CreatedBy: entities.UserDetailResponse{ + Username: user.Username, + UserID: user.ID, + Email: user.Email, + }, UpdatedAt: time.Now().Unix(), - UpdatedBy: user.ID, + UpdatedBy: entities.UserDetailResponse{ + Username: user.Username, + UserID: user.ID, + Email: user.Email, + }, }, } err := service.CreateProject(newProject) @@ -274,7 +305,7 @@ func ResetPassword(service services.ApplicationService) gin.HandlerFunc { } uid := c.MustGet("uid").(string) var adminUser entities.User - adminUser.UserName = c.MustGet("username").(string) + adminUser.Username = c.MustGet("username").(string) adminUser.ID = uid if utils.StrictPasswordPolicy { err := utils.ValidateStrictPassword(userPasswordRequest.NewPassword) @@ -321,7 +352,7 @@ func UpdateUserState(service services.ApplicationService) gin.HandlerFunc { } var adminUser entities.User - adminUser.UserName = c.MustGet("username").(string) + adminUser.Username = c.MustGet("username").(string) adminUser.ID = c.MustGet("uid").(string) // Checking if loggedIn user is admin diff --git a/chaoscenter/authentication/api/main.go b/chaoscenter/authentication/api/main.go index 879b6cbc723..9dc1e8524b8 100644 --- a/chaoscenter/authentication/api/main.go +++ b/chaoscenter/authentication/api/main.go @@ -108,7 +108,7 @@ func validatedAdminSetup(service services.ApplicationService) { adminUser := entities.User{ ID: uID, - UserName: utils.AdminName, + Username: utils.AdminName, Password: password, Role: entities.RoleAdmin, Audit: entities.Audit{ diff --git a/chaoscenter/authentication/api/presenter/protos/authentication.pb.go b/chaoscenter/authentication/api/presenter/protos/authentication.pb.go index 10392c9e53f..78c9d469e98 100644 --- a/chaoscenter/authentication/api/presenter/protos/authentication.pb.go +++ b/chaoscenter/authentication/api/presenter/protos/authentication.pb.go @@ -204,7 +204,7 @@ type ProjectMembers struct { unknownFields protoimpl.UnknownFields Uid string `protobuf:"bytes,1,opt,name=uid,proto3" json:"uid,omitempty"` - UserName string `protobuf:"bytes,2,opt,name=userName,proto3" json:"userName,omitempty"` + Username string `protobuf:"bytes,2,opt,name=userName,proto3" json:"userName,omitempty"` Role string `protobuf:"bytes,3,opt,name=role,proto3" json:"role,omitempty"` Email string `protobuf:"bytes,4,opt,name=email,proto3" json:"email,omitempty"` Invitation string `protobuf:"bytes,5,opt,name=invitation,proto3" json:"invitation,omitempty"` @@ -250,9 +250,9 @@ func (x *ProjectMembers) GetUid() string { return "" } -func (x *ProjectMembers) GetUserName() string { +func (x *ProjectMembers) GetUsername() string { if x != nil { - return x.UserName + return x.Username } return "" } diff --git a/chaoscenter/authentication/api/routes/project_router.go b/chaoscenter/authentication/api/routes/project_router.go index 87d676ff016..5457b855a3f 100644 --- a/chaoscenter/authentication/api/routes/project_router.go +++ b/chaoscenter/authentication/api/routes/project_router.go @@ -12,6 +12,7 @@ import ( func ProjectRouter(router *gin.Engine, service services.ApplicationService) { router.Use(middleware.JwtMiddleware()) router.GET("/get_project/:project_id", rest.GetProject(service)) + router.GET("/get_project_members/:project_id/:state", rest.GetActiveProjectMembers(service)) router.GET("/get_user_with_project/:username", rest.GetUserWithProject(service)) router.GET("/get_owner_projects", rest.GetOwnerProjectIDs(service)) router.GET("/get_project_role/:project_id", rest.GetProjectRole(service)) @@ -23,5 +24,5 @@ func ProjectRouter(router *gin.Engine, service services.ApplicationService) { router.POST("/decline_invitation", rest.DeclineInvitation(service)) router.POST("/remove_invitation", rest.RemoveInvitation(service)) router.POST("/leave_project", rest.LeaveProject(service)) - router.POST("/update_projectname", rest.UpdateProjectName(service)) + router.POST("/update_project_name", rest.UpdateProjectName(service)) } diff --git a/chaoscenter/authentication/api/routes/user_router.go b/chaoscenter/authentication/api/routes/user_router.go index 9fa16bfaf25..e65d46f54b9 100644 --- a/chaoscenter/authentication/api/routes/user_router.go +++ b/chaoscenter/authentication/api/routes/user_router.go @@ -18,5 +18,6 @@ func UserRouter(router *gin.Engine, service services.ApplicationService) { router.POST("/update/details", rest.UpdateUser(service)) router.GET("/getUser/:uid", rest.GetUser(service)) router.GET("/users", rest.FetchUsers(service)) + router.GET("/invite_users/:project_id", rest.InviteUsers(service)) router.POST("/update/state", rest.UpdateUserState(service)) } diff --git a/chaoscenter/authentication/api/types/project_types.go b/chaoscenter/authentication/api/types/project_types.go deleted file mode 100644 index 26d6b571847..00000000000 --- a/chaoscenter/authentication/api/types/project_types.go +++ /dev/null @@ -1,25 +0,0 @@ -package types - -import "github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/entities" - -// Project contains the required fields to be returned by GET APIs -type Project struct { - entities.Audit `bson:",inline"` - ID string `bson:"_id"` - UID string `bson:"uid"` - Name string `bson:"name"` - Members []*Member `bson:"members"` - State *string `bson:"state"` -} - -// Member contains the required fields to be returned by GET APIs -type Member struct { - UserID string `bson:"user_id"` - UserName string `bson:"username"` - Name string `bson:"name"` - Role entities.MemberRole `bson:"role"` - Email string `bson:"email"` - Invitation entities.Invitation `bson:"invitation"` - JoinedAt string `bson:"joined_at"` - DeactivatedAt *int64 `bson:"deactivated_at"` -} diff --git a/chaoscenter/authentication/pkg/entities/common_schema.go b/chaoscenter/authentication/pkg/entities/common_schema.go index 09d2dfd9422..63df34e05ea 100644 --- a/chaoscenter/authentication/pkg/entities/common_schema.go +++ b/chaoscenter/authentication/pkg/entities/common_schema.go @@ -1,15 +1,21 @@ package entities type ResourceDetails struct { - Name string `bson:"name"` - Description string `bson:"description"` - Tags []string `bson:"tags"` + Name string `bson:"name" json:"name"` + Description string `bson:"description" json:"description"` + Tags []string `bson:"tags" json:"tags"` } type Audit struct { - UpdatedAt int64 `bson:"updated_at"` - CreatedAt int64 `bson:"created_at"` - CreatedBy string `bson:"created_by"` - UpdatedBy string `bson:"updated_by"` - IsRemoved bool `bson:"is_removed"` + UpdatedAt int64 `bson:"updated_at" json:"updatedAt"` + CreatedAt int64 `bson:"created_at" json:"createdAt"` + CreatedBy UserDetailResponse `bson:"created_by" json:"createdBy"` + UpdatedBy UserDetailResponse `bson:"updated_by" json:"updatedBy"` + IsRemoved bool `bson:"is_removed" json:"isRemoved"` +} + +type UserDetailResponse struct { + UserID string `bson:"user_id" json:"userID"` + Username string `bson:"username" json:"username"` + Email string `bson:"email" json:"email"` } diff --git a/chaoscenter/authentication/pkg/entities/project.go b/chaoscenter/authentication/pkg/entities/project.go index 6964f00003d..9a9b898d1a8 100644 --- a/chaoscenter/authentication/pkg/entities/project.go +++ b/chaoscenter/authentication/pkg/entities/project.go @@ -3,48 +3,55 @@ package entities // Project contains the required fields to be stored in the database for a project type Project struct { Audit `bson:",inline"` - ID string `bson:"_id"` - Name string `bson:"name"` - Members []*Member `bson:"members"` - State *string `bson:"state"` + ID string `bson:"_id" json:"projectID"` + Name string `bson:"name" json:"name"` + Members []*Member `bson:"members" json:"members"` + State *string `bson:"state" json:"state"` } type Owner struct { - UserID string `bson:"user_id"` - Username string `bson:"username"` + UserID string `bson:"user_id" json:"userID"` + Username string `bson:"username" json:"username"` } type MemberStat struct { - Owner *[]Owner `bson:"owner"` - Total int `bson:"total"` + Owner *[]Owner `bson:"owner" json:"owner"` + Total int `bson:"total" json:"total"` } type ProjectStats struct { - Name string `bson:"name"` - ProjectID string `bson:"_id"` - Members *MemberStat `bson:"memberStat"` + Name string `bson:"name" json:"name"` + ProjectID string `bson:"_id" json:"projectID"` + Members *MemberStat `bson:"memberStat" json:"members"` } // Member contains the required fields to be stored in the database for a member type Member struct { - UserID string `bson:"user_id"` - Role MemberRole `bson:"role"` - Invitation Invitation `bson:"invitation"` - JoinedAt string `bson:"joined_at"` + UserID string `bson:"user_id" json:"userID"` + Username string `bson:"username" json:"username"` + Email string `bson:"email" json:"email"` + Name string `bson:"name" json:"name"` + Role MemberRole `bson:"role" json:"role"` + Invitation Invitation `bson:"invitation" json:"invitation"` + JoinedAt string `bson:"joined_at" json:"joinedAt"` +} + +type Members struct { + Members []*Member `bson:"members" json:"members"` } type ProjectInput struct { - ProjectID string `bson:"project_id" json:"project_id"` - ProjectName string `bson:"project_name" json:"project_name"` + ProjectID string `bson:"project_id" json:"projectID"` + ProjectName string `bson:"project_name" json:"projectName"` } type CreateProjectInput struct { - ProjectName string `bson:"project_name" json:"project_name"` - UserID string `bson:"user_id" json:"user_id"` + ProjectName string `bson:"project_name" json:"projectName"` + UserID string `bson:"user_id" json:"userID"` } type MemberInput struct { - ProjectID string `json:"project_id"` - UserID string `json:"user_id"` + ProjectID string `json:"projectID"` + UserID string `json:"userID"` Role *MemberRole `json:"role"` } @@ -114,3 +121,11 @@ const ( // ExitedProject is the state when the user has exited the project ExitedProject Invitation = "Exited" ) + +type State string + +const ( + Accepted State = "accepted" + NotAccepted State = "not_accepted" + All State = "all" +) diff --git a/chaoscenter/authentication/pkg/entities/user.go b/chaoscenter/authentication/pkg/entities/user.go index 5b95ba81fc5..d5726a8633c 100644 --- a/chaoscenter/authentication/pkg/entities/user.go +++ b/chaoscenter/authentication/pkg/entities/user.go @@ -24,13 +24,13 @@ const ( // User contains the user information type User struct { Audit `bson:",inline"` - ID string `bson:"_id,omitempty" json:"_id"` - UserName string `bson:"username,omitempty" json:"username"` + ID string `bson:"_id,omitempty" json:"userID"` + Username string `bson:"username,omitempty" json:"username"` Password string `bson:"password,omitempty" json:"password,omitempty"` Email string `bson:"email,omitempty" json:"email,omitempty"` Name string `bson:"name,omitempty" json:"name,omitempty"` Role Role `bson:"role,omitempty" json:"role"` - DeactivatedAt *int64 `bson:"deactivated_at,omitempty" json:"deactivated_at,omitempty"` + DeactivatedAt *int64 `bson:"deactivated_at,omitempty" json:"deactivatedAt,omitempty"` } // UserDetails is used to update user's personal details @@ -44,14 +44,14 @@ type UserDetails struct { // UserPassword defines structure for password related requests type UserPassword struct { Username string `json:"username,omitempty"` - OldPassword string `json:"old_password,omitempty"` - NewPassword string `json:"new_password,omitempty"` + OldPassword string `json:"oldPassword,omitempty"` + NewPassword string `json:"newPassword,omitempty"` } // UpdateUserState defines structure to deactivate or reactivate user type UpdateUserState struct { Username string `json:"username"` - IsDeactivate *bool `json:"is_deactivate"` + IsDeactivate *bool `json:"isDeactivate"` } // APIStatus defines structure for APIroute status @@ -72,7 +72,7 @@ func (user User) GetUserWithProject() *UserWithProject { return &UserWithProject{ ID: user.ID, - Username: user.UserName, + Username: user.Username, Name: user.Name, Audit: Audit{ IsRemoved: user.IsRemoved, @@ -104,7 +104,7 @@ func (user *User) GetSignedJWT() (string, error) { claims := token.Claims.(jwt.MapClaims) claims["uid"] = user.ID claims["role"] = user.Role - claims["username"] = user.UserName + claims["username"] = user.Username claims["exp"] = time.Now().Add(time.Minute * time.Duration(utils.JWTExpiryDuration)).Unix() tokenString, err := token.SignedString([]byte(utils.JwtSecret)) diff --git a/chaoscenter/authentication/pkg/project/repository.go b/chaoscenter/authentication/pkg/project/repository.go index 298f6a97943..9d2a9db0433 100644 --- a/chaoscenter/authentication/pkg/project/repository.go +++ b/chaoscenter/authentication/pkg/project/repository.go @@ -30,6 +30,7 @@ type Repository interface { UpdateProjectState(userID string, deactivateTime string) error GetOwnerProjectIDs(ctx context.Context, userID string) ([]string, error) GetProjectRole(projectID string, userID string) (*entities.MemberRole, error) + GetProjectMembers(projectID string, state string) ([]*entities.Member, error) } type repository struct { @@ -395,6 +396,71 @@ func (r repository) GetProjectRole(projectID string, userID string) (*entities.M return &(res.Members[0].Role), nil } +func (r repository) GetProjectMembers(projectID string, state string) ([]*entities.Member, error) { + var pipeline mongo.Pipeline + filter := bson.D{ + {"$match", bson.D{ + {"_id", projectID}, + }}, + } + pipeline = append(pipeline, filter) + var projection bson.D + switch state { + case string(entities.Accepted): + projection = bson.D{ + {"$project", bson.D{ + {"_id", 0}, + {"members", bson.D{ + {"$filter", bson.D{ + {"input", "$members"}, + {"as", "member"}, + {"cond", bson.D{{ + "$eq", bson.A{"$$member.invitation", entities.AcceptedInvitation}, + }}}, + }}, + }}, + }}, + } + pipeline = append(pipeline, projection) + case string(entities.NotAccepted): + projection = bson.D{ + {"$project", bson.D{ + {"_id", 0}, + {"members", bson.D{ + {"$filter", bson.D{ + {"input", "$members"}, + {"as", "member"}, + {"cond", bson.D{{ + "$ne", bson.A{"$$member.invitation", entities.AcceptedInvitation}, + }}}, + }}, + }}, + }}, + } + pipeline = append(pipeline, projection) + case string(entities.All): + projection = bson.D{ + {"$project", bson.D{ + {"_id", 0}, + {"members", 1}, + }}, + } + pipeline = append(pipeline, projection) + } + + var res []entities.Members + cursor, err := r.GetAggregateProjects(pipeline, nil) + if err != nil { + return nil, err + } + + if err = cursor.All(context.TODO(), &res); err != nil { + return nil, err + } + + return res[0].Members, nil +} + // NewRepo creates a new instance of this repository func NewRepo(collection *mongo.Collection) Repository { return &repository{ diff --git a/chaoscenter/authentication/pkg/services/project_service.go b/chaoscenter/authentication/pkg/services/project_service.go index 97d8be4d506..030424571f4 100644 --- a/chaoscenter/authentication/pkg/services/project_service.go +++ b/chaoscenter/authentication/pkg/services/project_service.go @@ -24,6 +24,7 @@ type projectService interface { UpdateProjectState(userID string, deactivateTime string) error GetOwnerProjectIDs(ctx context.Context, userID string) ([]string, error) GetProjectRole(projectID string, userID string) (*entities.MemberRole, error) + GetProjectMembers(projectID string, state string) ([]*entities.Member, error) } func (a applicationService) GetProjectByProjectID(projectID string) (*entities.Project, error) { @@ -75,3 +76,7 @@ func (a applicationService) GetOwnerProjectIDs(ctx context.Context, userID strin func (a applicationService) GetProjectRole(projectID string, userID string) (*entities.MemberRole, error) { return a.projectRepository.GetProjectRole(projectID, userID) } + +func (a applicationService) GetProjectMembers(projectID string, state string) ([]*entities.Member, error) { + return a.projectRepository.GetProjectMembers(projectID, state) +} diff --git a/chaoscenter/authentication/pkg/services/user_service.go b/chaoscenter/authentication/pkg/services/user_service.go index f05b6ae5e38..c696350ee6a 100644 --- a/chaoscenter/authentication/pkg/services/user_service.go +++ b/chaoscenter/authentication/pkg/services/user_service.go @@ -17,6 +17,7 @@ type userService interface { UpdateUser(user *entities.UserDetails) error IsAdministrator(user *entities.User) error UpdateUserState(username string, isDeactivate bool, deactivateTime string) error + InviteUsers(invitedUsers []string) (*[]entities.User, error) } // LoginUser is the implementation of the repository function `LoginUser` @@ -73,3 +74,7 @@ func (a applicationService) IsAdministrator(user *entities.User) error { func (a applicationService) UpdateUserState(username string, isDeactivate bool, deactivateTime string) error { return a.userRepository.UpdateUserState(username, isDeactivate, deactivateTime) } + +func (a applicationService) InviteUsers(invitedUsers []string) (*[]entities.User, error) { + return a.userRepository.InviteUsers(invitedUsers) +} diff --git a/chaoscenter/authentication/pkg/user/repository.go b/chaoscenter/authentication/pkg/user/repository.go index fa5072474b8..24175ddc54a 100644 --- a/chaoscenter/authentication/pkg/user/repository.go +++ b/chaoscenter/authentication/pkg/user/repository.go @@ -26,6 +26,7 @@ type Repository interface { UpdateUser(user *entities.UserDetails) error IsAdministrator(user *entities.User) error UpdateUserState(username string, isDeactivate bool, deactivateTime string) error + InviteUsers(invitedUsers []string) (*[]entities.User, error) } type repository struct { @@ -47,7 +48,7 @@ func (r repository) LoginUser(user *entities.User) (*entities.User, error) { if mongo.IsDuplicateKeyError(err) { var result = entities.User{} findOneErr := r.Collection.FindOne(context.TODO(), bson.M{ - "username": user.UserName, + "username": user.Username, }).Decode(&result) if findOneErr != nil { return nil, findOneErr @@ -87,6 +88,34 @@ func (r repository) GetUsers() (*[]entities.User, error) { return &Users, nil } +func (r repository) InviteUsers(invitedUsers []string) (*[]entities.User, error) { + cursor, err := r.Collection.Find(context.Background(), + bson.D{ + {"_id", bson.D{ + {"$nin", invitedUsers}, + }}, + {"deactivated_at", bson.D{ + {"$exists", false}, + }}, + }) + + if err != nil { + return nil, err + } + + var Users = []entities.User{} + for cursor.Next(context.TODO()) { + var user entities.User + err := cursor.Decode(&user) + if err != nil { + return nil, err + } + Users = append(Users, *user.SanitizedUser()) + } + + return &Users, nil +} + // FindUsersByUID fetches the user from database that matches the passed uids func (r repository) FindUsersByUID(uid []string) (*[]entities.User, error) { cursor, err := r.Collection.Find(context.Background(), @@ -110,7 +139,7 @@ func (r repository) FindUsersByUID(uid []string) (*[]entities.User, error) { return &Users, nil } -// FindUser finds and returns a user if it exists +// FindUserByUsername finds and returns a user if it exists func (r repository) FindUserByUsername(username string) (*entities.User, error) { var result = entities.User{} findOneErr := r.Collection.FindOne(context.TODO(), bson.M{ @@ -137,9 +166,9 @@ func (r repository) CheckPasswordHash(hash, password string) error { // UpdatePassword helps to update the password of the user, it acts as a resetPassword when isAdminBeingReset is set to true func (r repository) UpdatePassword(userPassword *entities.UserPassword, isAdminBeingReset bool) error { var result = entities.User{} - result.UserName = userPassword.Username + result.Username = userPassword.Username findOneErr := r.Collection.FindOne(context.TODO(), bson.M{ - "username": result.UserName, + "username": result.Username, }).Decode(&result) if findOneErr != nil { return findOneErr @@ -190,7 +219,7 @@ func (r repository) IsAdministrator(user *entities.User) error { var result = entities.User{} findOneErr := r.Collection.FindOne(context.TODO(), bson.M{ "_id": user.ID, - "username": user.UserName, + "username": user.Username, }).Decode(&result) if findOneErr != nil { return findOneErr diff --git a/chaoscenter/authentication/pkg/validations/rbac_validator.go b/chaoscenter/authentication/pkg/validations/rbac_validator.go index a37b9acca4a..7cfcf9f5218 100644 --- a/chaoscenter/authentication/pkg/validations/rbac_validator.go +++ b/chaoscenter/authentication/pkg/validations/rbac_validator.go @@ -44,7 +44,6 @@ func RbacValidator(uid string, projectID string, return err } if project == nil { - log.Error("authgRPC Error: Unauthorised") return errors.New("auth gRPC - Unauthorized") }