mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-13 03:24:26 +00:00
feat: project commands more requests (#47)
* feat: eventstore repository * fix: remove gorm * version * feat: pkg * feat: add some files for project * feat: eventstore without eventstore-lib * rename files * gnueg * fix: key json * fix: add object * fix: change imports * fix: internal models * fix: some imports * fix: global model * fix: add some functions on repo * feat(eventstore): sdk * fix(eventstore): search query * fix(eventstore): rename app to eventstore * delete empty test * remove unused func * merge master * fix(eventstore): tests * fix(models): delete unused struct * fix: some funcitons * feat(eventstore): implemented push events * fix: move project eventstore to project package * fix: change project eventstore funcs * feat(eventstore): overwrite context data * fix: change project eventstore * fix: add project repo to mgmt server * feat(types): SQL-config * fix: commented code * feat(eventstore): options to overwrite editor * feat: auth interceptor and cockroach migrations * fix: migrations * fix: fix filter * fix: not found on getbyid * fix: add sequence * fix: add some tests * fix(eventstore): nullable sequence * fix: add some tests * merge * fix: add some tests * fix(migrations): correct statements for sequence * fix: add some tests * fix: add some tests * fix: changes from mr * Update internal/eventstore/models/field.go Co-Authored-By: livio-a <livio.a@gmail.com> * fix(eventstore): code quality * fix: add types to aggregate/Event-types * fix(eventstore): rename modifier* to editor* * fix(eventstore): delete editor_org * fix(migrations): remove editor_org field, rename modifier_* to editor_* * fix: generate files * fix(eventstore): tests * fix(eventstore): rename modifier to editor * fix(migrations): add cluster migration, fix(migrations): fix typo of host in clean clsuter * fix(eventstore): move health * fix(eventstore): AggregateTypeFilter aggregateType as param * code quality * feat: add member funcs * feat: add member model * feat: add member events * feat: add member repo model * fix: project member funcs * fix: add tests * fix: add tests * feat: implement member requests * fix: merge master * fix: read existing in project repo * fix: fix tests * fix: use eventstore sdk * Update internal/project/model/project_member.go Co-Authored-By: Silvan <silvan.reusser@gmail.com> * fix: use get project func * fix: return err not nil * fix: change error to caos err Co-authored-by: adlerhurst <silvan.reusser@gmail.com> Co-authored-by: livio-a <livio.a@gmail.com>
This commit is contained in:
parent
d0e72713fc
commit
bd33b54ac5
@ -31,28 +31,31 @@ func (repo *ProjectRepo) CreateProject(ctx context.Context, name string) (*proj_
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (repo *ProjectRepo) UpdateProject(ctx context.Context, project *proj_model.Project) (*proj_model.Project, error) {
|
func (repo *ProjectRepo) UpdateProject(ctx context.Context, project *proj_model.Project) (*proj_model.Project, error) {
|
||||||
existingProject, err := repo.ProjectByID(ctx, project.ID)
|
return repo.ProjectEvents.UpdateProject(ctx, project)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return repo.ProjectEvents.UpdateProject(ctx, existingProject, project)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *ProjectRepo) DeactivateProject(ctx context.Context, id string) (*proj_model.Project, error) {
|
func (repo *ProjectRepo) DeactivateProject(ctx context.Context, id string) (*proj_model.Project, error) {
|
||||||
project, err := repo.ProjectByID(ctx, id)
|
return repo.ProjectEvents.DeactivateProject(ctx, id)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return repo.ProjectEvents.DeactivateProject(ctx, project)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *ProjectRepo) ReactivateProject(ctx context.Context, id string) (*proj_model.Project, error) {
|
func (repo *ProjectRepo) ReactivateProject(ctx context.Context, id string) (*proj_model.Project, error) {
|
||||||
project, err := repo.ProjectByID(ctx, id)
|
return repo.ProjectEvents.ReactivateProject(ctx, id)
|
||||||
if err != nil {
|
}
|
||||||
return nil, err
|
|
||||||
}
|
func (repo *ProjectRepo) ProjectMemberByID(ctx context.Context, projectID, userID string) (member *proj_model.ProjectMember, err error) {
|
||||||
|
member = proj_model.NewProjectMember(projectID, userID)
|
||||||
return repo.ProjectEvents.ReactivateProject(ctx, project)
|
return repo.ProjectEvents.ProjectMemberByIDs(ctx, member)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *ProjectRepo) AddProjectMember(ctx context.Context, member *proj_model.ProjectMember) (*proj_model.ProjectMember, error) {
|
||||||
|
return repo.ProjectEvents.AddProjectMember(ctx, member)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *ProjectRepo) ChangeProjectMember(ctx context.Context, member *proj_model.ProjectMember) (*proj_model.ProjectMember, error) {
|
||||||
|
return repo.ProjectEvents.ChangeProjectMember(ctx, member)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *ProjectRepo) RemoveProjectMember(ctx context.Context, projectID, userID string) error {
|
||||||
|
member := proj_model.NewProjectMember(projectID, userID)
|
||||||
|
return repo.ProjectEvents.RemoveProjectMember(ctx, member)
|
||||||
}
|
}
|
||||||
|
@ -11,4 +11,9 @@ type ProjectRepository interface {
|
|||||||
UpdateProject(ctx context.Context, project *model.Project) (*model.Project, error)
|
UpdateProject(ctx context.Context, project *model.Project) (*model.Project, error)
|
||||||
DeactivateProject(ctx context.Context, id string) (*model.Project, error)
|
DeactivateProject(ctx context.Context, id string) (*model.Project, error)
|
||||||
ReactivateProject(ctx context.Context, id string) (*model.Project, error)
|
ReactivateProject(ctx context.Context, id string) (*model.Project, error)
|
||||||
|
|
||||||
|
ProjectMemberByID(ctx context.Context, projectID, userID string) (*model.ProjectMember, error)
|
||||||
|
AddProjectMember(ctx context.Context, member *model.ProjectMember) (*model.ProjectMember, error)
|
||||||
|
ChangeProjectMember(ctx context.Context, member *model.ProjectMember) (*model.ProjectMember, error)
|
||||||
|
RemoveProjectMember(ctx context.Context, projectID, userID string) error
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,9 @@ import (
|
|||||||
type Project struct {
|
type Project struct {
|
||||||
es_models.ObjectRoot
|
es_models.ObjectRoot
|
||||||
|
|
||||||
State ProjectState
|
State ProjectState
|
||||||
Name string
|
Name string
|
||||||
|
Members []*ProjectMember
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProjectState in_model.Enum
|
type ProjectState in_model.Enum
|
||||||
@ -33,3 +34,12 @@ func (p *Project) IsValid() bool {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Project) ContainsMember(member *ProjectMember) bool {
|
||||||
|
for _, m := range p.Members {
|
||||||
|
if m.UserID == member.UserID {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
18
internal/project/model/project_member.go
Normal file
18
internal/project/model/project_member.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||||
|
|
||||||
|
type ProjectMember struct {
|
||||||
|
es_models.ObjectRoot
|
||||||
|
|
||||||
|
UserID string
|
||||||
|
Roles []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewProjectMember(projectID, userID string) *ProjectMember {
|
||||||
|
return &ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: projectID}, UserID: userID}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProjectMember) IsValid() bool {
|
||||||
|
return p.ID != "" && p.UserID != "" && len(p.Roles) != 0
|
||||||
|
}
|
@ -2,6 +2,7 @@ package eventsourcing
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore/models"
|
||||||
|
|
||||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||||
es_int "github.com/caos/zitadel/internal/eventstore"
|
es_int "github.com/caos/zitadel/internal/eventstore"
|
||||||
@ -51,15 +52,19 @@ func (es *ProjectEventstore) CreateProject(ctx context.Context, project *proj_mo
|
|||||||
return ProjectToModel(repoProject), nil
|
return ProjectToModel(repoProject), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (es *ProjectEventstore) UpdateProject(ctx context.Context, existingProject *proj_model.Project, project *proj_model.Project) (*proj_model.Project, error) {
|
func (es *ProjectEventstore) UpdateProject(ctx context.Context, project *proj_model.Project) (*proj_model.Project, error) {
|
||||||
if !project.IsValid() {
|
if !project.IsValid() {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "Name is required")
|
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "Name is required")
|
||||||
}
|
}
|
||||||
|
existingProject, err := es.ProjectByID(ctx, &proj_model.Project{ObjectRoot: models.ObjectRoot{ID: project.ID, Sequence: 0}})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
repoExisting := ProjectFromModel(existingProject)
|
repoExisting := ProjectFromModel(existingProject)
|
||||||
repoNew := ProjectFromModel(project)
|
repoNew := ProjectFromModel(project)
|
||||||
|
|
||||||
updateAggregate := ProjectUpdateAggregate(es.AggregateCreator(), repoExisting, repoNew)
|
updateAggregate := ProjectUpdateAggregate(es.AggregateCreator(), repoExisting, repoNew)
|
||||||
err := es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, updateAggregate)
|
err = es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, updateAggregate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -67,7 +72,11 @@ func (es *ProjectEventstore) UpdateProject(ctx context.Context, existingProject
|
|||||||
return ProjectToModel(repoExisting), nil
|
return ProjectToModel(repoExisting), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (es *ProjectEventstore) DeactivateProject(ctx context.Context, existing *proj_model.Project) (*proj_model.Project, error) {
|
func (es *ProjectEventstore) DeactivateProject(ctx context.Context, id string) (*proj_model.Project, error) {
|
||||||
|
existing, err := es.ProjectByID(ctx, &proj_model.Project{ObjectRoot: models.ObjectRoot{ID: id, Sequence: 0}})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if !existing.IsActive() {
|
if !existing.IsActive() {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-die45", "project must be active")
|
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-die45", "project must be active")
|
||||||
}
|
}
|
||||||
@ -78,7 +87,11 @@ func (es *ProjectEventstore) DeactivateProject(ctx context.Context, existing *pr
|
|||||||
return ProjectToModel(repoExisting), nil
|
return ProjectToModel(repoExisting), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (es *ProjectEventstore) ReactivateProject(ctx context.Context, existing *proj_model.Project) (*proj_model.Project, error) {
|
func (es *ProjectEventstore) ReactivateProject(ctx context.Context, id string) (*proj_model.Project, error) {
|
||||||
|
existing, err := es.ProjectByID(ctx, &proj_model.Project{ObjectRoot: models.ObjectRoot{ID: id, Sequence: 0}})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if existing.IsActive() {
|
if existing.IsActive() {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-die45", "project must be inactive")
|
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-die45", "project must be inactive")
|
||||||
}
|
}
|
||||||
@ -88,3 +101,87 @@ func (es *ProjectEventstore) ReactivateProject(ctx context.Context, existing *pr
|
|||||||
es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, aggregate)
|
es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, aggregate)
|
||||||
return ProjectToModel(repoExisting), nil
|
return ProjectToModel(repoExisting), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (es *ProjectEventstore) ProjectMemberByIDs(ctx context.Context, member *proj_model.ProjectMember) (*proj_model.ProjectMember, error) {
|
||||||
|
if member.UserID == "" {
|
||||||
|
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-ld93d", "userID missing")
|
||||||
|
}
|
||||||
|
project, err := es.ProjectByID(ctx, &proj_model.Project{ObjectRoot: models.ObjectRoot{ID: member.ID, Sequence: 0}})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, m := range project.Members {
|
||||||
|
if m.UserID == member.UserID {
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, caos_errs.ThrowInternal(nil, "EVENT-3udjs", "Could not find member in list")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (es *ProjectEventstore) AddProjectMember(ctx context.Context, member *proj_model.ProjectMember) (*proj_model.ProjectMember, error) {
|
||||||
|
if !member.IsValid() {
|
||||||
|
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "UserID and Roles are required")
|
||||||
|
}
|
||||||
|
existing, err := es.ProjectByID(ctx, &proj_model.Project{ObjectRoot: models.ObjectRoot{ID: member.ID, Sequence: 0}})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if existing.ContainsMember(member) {
|
||||||
|
return nil, caos_errs.ThrowAlreadyExists(nil, "EVENT-idke6", "User is already member of this Project")
|
||||||
|
}
|
||||||
|
repoProject := ProjectFromModel(existing)
|
||||||
|
repoMember := ProjectMemberFromModel(member)
|
||||||
|
|
||||||
|
addAggregate := ProjectMemberAddedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoMember)
|
||||||
|
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, addAggregate)
|
||||||
|
for _, m := range repoProject.Members {
|
||||||
|
if m.UserID == member.UserID {
|
||||||
|
return ProjectMemberToModel(m), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, caos_errs.ThrowInternal(nil, "EVENT-3udjs", "Could not find member in list")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (es *ProjectEventstore) ChangeProjectMember(ctx context.Context, member *proj_model.ProjectMember) (*proj_model.ProjectMember, error) {
|
||||||
|
if !member.IsValid() {
|
||||||
|
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "UserID and Roles are required")
|
||||||
|
}
|
||||||
|
existing, err := es.ProjectByID(ctx, &proj_model.Project{ObjectRoot: models.ObjectRoot{ID: member.ID, Sequence: 0}})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !existing.ContainsMember(member) {
|
||||||
|
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-oe39f", "User is not member of this project")
|
||||||
|
}
|
||||||
|
repoProject := ProjectFromModel(existing)
|
||||||
|
repoMember := ProjectMemberFromModel(member)
|
||||||
|
|
||||||
|
projectAggregate := ProjectMemberChangedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoMember)
|
||||||
|
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
|
||||||
|
|
||||||
|
for _, m := range repoProject.Members {
|
||||||
|
if m.UserID == member.UserID {
|
||||||
|
return ProjectMemberToModel(m), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, caos_errs.ThrowInternal(nil, "EVENT-3udjs", "Could not find member in list")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (es *ProjectEventstore) RemoveProjectMember(ctx context.Context, member *proj_model.ProjectMember) error {
|
||||||
|
if member.UserID == "" {
|
||||||
|
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-d43fs", "UserID and Roles are required")
|
||||||
|
}
|
||||||
|
existing, err := es.ProjectByID(ctx, &proj_model.Project{ObjectRoot: models.ObjectRoot{ID: member.ID, Sequence: 0}})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !existing.ContainsMember(member) {
|
||||||
|
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-swf34", "User is not member of this project")
|
||||||
|
}
|
||||||
|
repoProject := ProjectFromModel(existing)
|
||||||
|
repoMember := ProjectMemberFromModel(member)
|
||||||
|
|
||||||
|
projectAggregate := ProjectMemberRemovedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoMember)
|
||||||
|
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
@ -26,8 +26,61 @@ func GetMockProjectByIDNoEvents(ctrl *gomock.Controller) *ProjectEventstore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetMockManipulateProject(ctrl *gomock.Controller) *ProjectEventstore {
|
func GetMockManipulateProject(ctrl *gomock.Controller) *ProjectEventstore {
|
||||||
|
data, _ := json.Marshal(Project{Name: "Name"})
|
||||||
|
events := []*es_models.Event{
|
||||||
|
&es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.ProjectAdded, Data: data},
|
||||||
|
}
|
||||||
mockEs := mock.NewMockEventstore(ctrl)
|
mockEs := mock.NewMockEventstore(ctrl)
|
||||||
|
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||||
mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST"))
|
mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST"))
|
||||||
mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil)
|
mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil)
|
||||||
return &ProjectEventstore{Eventstore: mockEs}
|
return &ProjectEventstore{Eventstore: mockEs}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetMockManipulateInactiveProject(ctrl *gomock.Controller) *ProjectEventstore {
|
||||||
|
data, _ := json.Marshal(Project{Name: "Name"})
|
||||||
|
events := []*es_models.Event{
|
||||||
|
&es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.ProjectAdded, Data: data},
|
||||||
|
&es_models.Event{AggregateID: "ID", Sequence: 2, Type: model.ProjectDeactivated, Data: data},
|
||||||
|
}
|
||||||
|
mockEs := mock.NewMockEventstore(ctrl)
|
||||||
|
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||||
|
mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST"))
|
||||||
|
mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil)
|
||||||
|
return &ProjectEventstore{Eventstore: mockEs}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMockManipulateProjectWithMember(ctrl *gomock.Controller) *ProjectEventstore {
|
||||||
|
data, _ := json.Marshal(Project{Name: "Name"})
|
||||||
|
memberData, _ := json.Marshal(ProjectMember{UserID: "UserID", Roles: []string{"Role"}})
|
||||||
|
events := []*es_models.Event{
|
||||||
|
&es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.ProjectAdded, Data: data},
|
||||||
|
&es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.ProjectMemberAdded, Data: memberData},
|
||||||
|
}
|
||||||
|
mockEs := mock.NewMockEventstore(ctrl)
|
||||||
|
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||||
|
mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST"))
|
||||||
|
mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil)
|
||||||
|
return &ProjectEventstore{Eventstore: mockEs}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMockManipulateProjectNoEvents(ctrl *gomock.Controller) *ProjectEventstore {
|
||||||
|
events := []*es_models.Event{}
|
||||||
|
mockEs := mock.NewMockEventstore(ctrl)
|
||||||
|
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||||
|
mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST"))
|
||||||
|
mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil)
|
||||||
|
return &ProjectEventstore{Eventstore: mockEs}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMockProjectMemberByIDsOK(ctrl *gomock.Controller) *ProjectEventstore {
|
||||||
|
projectData, _ := json.Marshal(Project{Name: "Name"})
|
||||||
|
memberData, _ := json.Marshal(ProjectMember{UserID: "UserID", Roles: []string{"Role"}})
|
||||||
|
events := []*es_models.Event{
|
||||||
|
&es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.ProjectAdded, Data: projectData},
|
||||||
|
&es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.ProjectMemberAdded, Data: memberData},
|
||||||
|
}
|
||||||
|
mockEs := mock.NewMockEventstore(ctrl)
|
||||||
|
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||||
|
return &ProjectEventstore{Eventstore: mockEs}
|
||||||
|
}
|
||||||
|
@ -91,7 +91,7 @@ func TestCreateProject(t *testing.T) {
|
|||||||
res res
|
res res
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "project from events, ok",
|
name: "create project, ok",
|
||||||
args: args{
|
args: args{
|
||||||
es: GetMockManipulateProject(ctrl),
|
es: GetMockManipulateProject(ctrl),
|
||||||
ctx: auth.NewMockContext("orgID", "userID"),
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
@ -134,10 +134,9 @@ func TestCreateProject(t *testing.T) {
|
|||||||
func TestUpdateProject(t *testing.T) {
|
func TestUpdateProject(t *testing.T) {
|
||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
type args struct {
|
type args struct {
|
||||||
es *ProjectEventstore
|
es *ProjectEventstore
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
existing *model.Project
|
new *model.Project
|
||||||
new *model.Project
|
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
project *model.Project
|
project *model.Project
|
||||||
@ -150,34 +149,44 @@ func TestUpdateProject(t *testing.T) {
|
|||||||
res res
|
res res
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "project from events, ok",
|
name: "update project, ok",
|
||||||
args: args{
|
args: args{
|
||||||
es: GetMockManipulateProject(ctrl),
|
es: GetMockManipulateProject(ctrl),
|
||||||
ctx: auth.NewMockContext("orgID", "userID"),
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
existing: &model.Project{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, Name: "Name"},
|
new: &model.Project{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, Name: "NameNew"},
|
||||||
new: &model.Project{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, Name: "NameNew"},
|
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
project: &model.Project{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, Name: "NameNew"},
|
project: &model.Project{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, Name: "NameNew"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "create project no name",
|
name: "update project no name",
|
||||||
args: args{
|
args: args{
|
||||||
es: GetMockManipulateProject(ctrl),
|
es: GetMockManipulateProject(ctrl),
|
||||||
ctx: auth.NewMockContext("orgID", "userID"),
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
existing: &model.Project{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, Name: "Name"},
|
new: &model.Project{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, Name: ""},
|
||||||
new: &model.Project{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, Name: ""},
|
|
||||||
},
|
},
|
||||||
res: res{
|
res: res{
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
errFunc: caos_errs.IsPreconditionFailed,
|
errFunc: caos_errs.IsPreconditionFailed,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "existing project not found",
|
||||||
|
args: args{
|
||||||
|
es: GetMockManipulateProjectNoEvents(ctrl),
|
||||||
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
|
new: &model.Project{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, Name: "NameNew"},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
wantErr: true,
|
||||||
|
errFunc: caos_errs.IsNotFound,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
result, err := tt.args.es.UpdateProject(tt.args.ctx, tt.args.existing, tt.args.new)
|
result, err := tt.args.es.UpdateProject(tt.args.ctx, tt.args.new)
|
||||||
|
|
||||||
if !tt.res.wantErr && result.ID == "" {
|
if !tt.res.wantErr && result.ID == "" {
|
||||||
t.Errorf("result has no id")
|
t.Errorf("result has no id")
|
||||||
@ -224,7 +233,7 @@ func TestDeactivateProject(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "deactivate project with inactive state",
|
name: "deactivate project with inactive state",
|
||||||
args: args{
|
args: args{
|
||||||
es: GetMockManipulateProject(ctrl),
|
es: GetMockManipulateInactiveProject(ctrl),
|
||||||
ctx: auth.NewMockContext("orgID", "userID"),
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
existing: &model.Project{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, Name: "Name", State: model.Inactive},
|
existing: &model.Project{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, Name: "Name", State: model.Inactive},
|
||||||
},
|
},
|
||||||
@ -233,10 +242,22 @@ func TestDeactivateProject(t *testing.T) {
|
|||||||
errFunc: caos_errs.IsPreconditionFailed,
|
errFunc: caos_errs.IsPreconditionFailed,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "existing not found",
|
||||||
|
args: args{
|
||||||
|
es: GetMockManipulateProjectNoEvents(ctrl),
|
||||||
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
|
existing: &model.Project{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, Name: "Name", State: model.Active},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
wantErr: true,
|
||||||
|
errFunc: caos_errs.IsNotFound,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
result, err := tt.args.es.DeactivateProject(tt.args.ctx, tt.args.existing)
|
result, err := tt.args.es.DeactivateProject(tt.args.ctx, tt.args.existing.ID)
|
||||||
|
|
||||||
if !tt.res.wantErr && result.ID == "" {
|
if !tt.res.wantErr && result.ID == "" {
|
||||||
t.Errorf("result has no id")
|
t.Errorf("result has no id")
|
||||||
@ -270,9 +291,9 @@ func TestReactivateProject(t *testing.T) {
|
|||||||
res res
|
res res
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "deactivate project, ok",
|
name: "reactivate project, ok",
|
||||||
args: args{
|
args: args{
|
||||||
es: GetMockManipulateProject(ctrl),
|
es: GetMockManipulateInactiveProject(ctrl),
|
||||||
ctx: auth.NewMockContext("orgID", "userID"),
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
existing: &model.Project{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, Name: "Name", State: model.Inactive},
|
existing: &model.Project{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, Name: "Name", State: model.Inactive},
|
||||||
},
|
},
|
||||||
@ -281,7 +302,7 @@ func TestReactivateProject(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "deactivate project with inactive state",
|
name: "reactivate project with inactive state",
|
||||||
args: args{
|
args: args{
|
||||||
es: GetMockManipulateProject(ctrl),
|
es: GetMockManipulateProject(ctrl),
|
||||||
ctx: auth.NewMockContext("orgID", "userID"),
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
@ -292,10 +313,22 @@ func TestReactivateProject(t *testing.T) {
|
|||||||
errFunc: caos_errs.IsPreconditionFailed,
|
errFunc: caos_errs.IsPreconditionFailed,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "existing not found",
|
||||||
|
args: args{
|
||||||
|
es: GetMockManipulateProjectNoEvents(ctrl),
|
||||||
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
|
existing: &model.Project{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, Name: "Name", State: model.Active},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
wantErr: true,
|
||||||
|
errFunc: caos_errs.IsNotFound,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
result, err := tt.args.es.ReactivateProject(tt.args.ctx, tt.args.existing)
|
result, err := tt.args.es.ReactivateProject(tt.args.ctx, tt.args.existing.ID)
|
||||||
|
|
||||||
if !tt.res.wantErr && result.ID == "" {
|
if !tt.res.wantErr && result.ID == "" {
|
||||||
t.Errorf("result has no id")
|
t.Errorf("result has no id")
|
||||||
@ -309,3 +342,361 @@ func TestReactivateProject(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestProjectMemberByIDs(t *testing.T) {
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
type args struct {
|
||||||
|
es *ProjectEventstore
|
||||||
|
member *model.ProjectMember
|
||||||
|
}
|
||||||
|
type res struct {
|
||||||
|
member *model.ProjectMember
|
||||||
|
wantErr bool
|
||||||
|
errFunc func(err error) bool
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
res res
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "project member from events, ok",
|
||||||
|
args: args{
|
||||||
|
es: GetMockProjectMemberByIDsOK(ctrl),
|
||||||
|
member: &model.ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, UserID: "UserID"},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
member: &model.ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, UserID: "UserID", Roles: []string{"Role"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "project member from events, no events",
|
||||||
|
args: args{
|
||||||
|
es: GetMockProjectByIDNoEvents(ctrl),
|
||||||
|
member: &model.ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, UserID: "UserID"},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
wantErr: true,
|
||||||
|
errFunc: caos_errs.IsNotFound,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "project member from events, no id",
|
||||||
|
args: args{
|
||||||
|
es: GetMockProjectByIDNoEvents(ctrl),
|
||||||
|
member: &model.ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
wantErr: true,
|
||||||
|
errFunc: func(err error) bool {
|
||||||
|
return caos_errs.IsPreconditionFailed(err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
result, err := tt.args.es.ProjectMemberByIDs(nil, tt.args.member)
|
||||||
|
if !tt.res.wantErr && result.ID != tt.res.member.ID {
|
||||||
|
t.Errorf("got wrong result id: expected: %v, actual: %v ", tt.res.member.ID, result.ID)
|
||||||
|
}
|
||||||
|
if !tt.res.wantErr && result.UserID != tt.res.member.UserID {
|
||||||
|
t.Errorf("got wrong result userid: expected: %v, actual: %v ", tt.res.member.UserID, result.UserID)
|
||||||
|
}
|
||||||
|
if !tt.res.wantErr && len(result.Roles) != len(tt.res.member.Roles) {
|
||||||
|
t.Errorf("got wrong result roles: expected: %v, actual: %v ", tt.res.member.Roles, result.Roles)
|
||||||
|
}
|
||||||
|
if tt.res.wantErr && !tt.res.errFunc(err) {
|
||||||
|
t.Errorf("got wrong err: %v ", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddProjectMember(t *testing.T) {
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
type args struct {
|
||||||
|
es *ProjectEventstore
|
||||||
|
ctx context.Context
|
||||||
|
member *model.ProjectMember
|
||||||
|
}
|
||||||
|
type res struct {
|
||||||
|
result *model.ProjectMember
|
||||||
|
wantErr bool
|
||||||
|
errFunc func(err error) bool
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
res res
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "add project member, ok",
|
||||||
|
args: args{
|
||||||
|
es: GetMockManipulateProject(ctrl),
|
||||||
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
|
member: &model.ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, UserID: "UserID", Roles: []string{"Roles"}},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
result: &model.ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, UserID: "UserID", Roles: []string{"Roles"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no userid",
|
||||||
|
args: args{
|
||||||
|
es: GetMockManipulateProject(ctrl),
|
||||||
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
|
member: &model.ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, Roles: []string{"Roles"}},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
wantErr: true,
|
||||||
|
errFunc: caos_errs.IsPreconditionFailed,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no roles",
|
||||||
|
args: args{
|
||||||
|
es: GetMockManipulateProject(ctrl),
|
||||||
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
|
member: &model.ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, UserID: "UserID"},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
wantErr: true,
|
||||||
|
errFunc: caos_errs.IsPreconditionFailed,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "member already existing",
|
||||||
|
args: args{
|
||||||
|
es: GetMockManipulateProjectWithMember(ctrl),
|
||||||
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
|
member: &model.ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, UserID: "UserID", Roles: []string{"Roles"}},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
wantErr: true,
|
||||||
|
errFunc: caos_errs.IsErrorAlreadyExists,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "existing project not found",
|
||||||
|
args: args{
|
||||||
|
es: GetMockManipulateProjectNoEvents(ctrl),
|
||||||
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
|
member: &model.ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, UserID: "UserID", Roles: []string{"Roles"}},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
wantErr: true,
|
||||||
|
errFunc: caos_errs.IsNotFound,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
result, err := tt.args.es.AddProjectMember(tt.args.ctx, tt.args.member)
|
||||||
|
|
||||||
|
if !tt.res.wantErr && result.ID == "" {
|
||||||
|
t.Errorf("result has no id")
|
||||||
|
}
|
||||||
|
if !tt.res.wantErr && result.UserID != tt.res.result.UserID {
|
||||||
|
t.Errorf("got wrong result userid: expected: %v, actual: %v ", tt.res.result.UserID, result.UserID)
|
||||||
|
}
|
||||||
|
if !tt.res.wantErr && len(result.Roles) != len(tt.res.result.Roles) {
|
||||||
|
t.Errorf("got wrong result roles: expected: %v, actual: %v ", tt.res.result.Roles, result.Roles)
|
||||||
|
}
|
||||||
|
if tt.res.wantErr && !tt.res.errFunc(err) {
|
||||||
|
t.Errorf("got wrong err: %v ", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChangeProjectMember(t *testing.T) {
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
type args struct {
|
||||||
|
es *ProjectEventstore
|
||||||
|
ctx context.Context
|
||||||
|
member *model.ProjectMember
|
||||||
|
}
|
||||||
|
type res struct {
|
||||||
|
result *model.ProjectMember
|
||||||
|
wantErr bool
|
||||||
|
errFunc func(err error) bool
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
res res
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "add project member, ok",
|
||||||
|
args: args{
|
||||||
|
es: GetMockManipulateProjectWithMember(ctrl),
|
||||||
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
|
member: &model.ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, UserID: "UserID", Roles: []string{"ChangeRoles"}},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
result: &model.ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, UserID: "UserID", Roles: []string{"Roles"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no userid",
|
||||||
|
args: args{
|
||||||
|
es: GetMockManipulateProject(ctrl),
|
||||||
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
|
member: &model.ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, Roles: []string{"ChangeRoles"}},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
wantErr: true,
|
||||||
|
errFunc: caos_errs.IsPreconditionFailed,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no roles",
|
||||||
|
args: args{
|
||||||
|
es: GetMockManipulateProject(ctrl),
|
||||||
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
|
member: &model.ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, UserID: "UserID"},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
wantErr: true,
|
||||||
|
errFunc: caos_errs.IsPreconditionFailed,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "member not existing",
|
||||||
|
args: args{
|
||||||
|
es: GetMockManipulateProject(ctrl),
|
||||||
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
|
member: &model.ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, UserID: "UserID", Roles: []string{"Roles"}},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
wantErr: true,
|
||||||
|
errFunc: caos_errs.IsPreconditionFailed,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "existing not found",
|
||||||
|
args: args{
|
||||||
|
es: GetMockManipulateProjectNoEvents(ctrl),
|
||||||
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
|
member: &model.ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, UserID: "UserID", Roles: []string{"ChangeRoles"}},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
wantErr: true,
|
||||||
|
errFunc: caos_errs.IsNotFound,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
result, err := tt.args.es.ChangeProjectMember(tt.args.ctx, tt.args.member)
|
||||||
|
|
||||||
|
if !tt.res.wantErr && result.ID == "" {
|
||||||
|
t.Errorf("result has no id")
|
||||||
|
}
|
||||||
|
if !tt.res.wantErr && result.UserID != tt.res.result.UserID {
|
||||||
|
t.Errorf("got wrong result userid: expected: %v, actual: %v ", tt.res.result.UserID, result.UserID)
|
||||||
|
}
|
||||||
|
if !tt.res.wantErr && len(result.Roles) != len(tt.res.result.Roles) {
|
||||||
|
t.Errorf("got wrong result roles: expected: %v, actual: %v ", tt.res.result.Roles, result.Roles)
|
||||||
|
}
|
||||||
|
if tt.res.wantErr && !tt.res.errFunc(err) {
|
||||||
|
t.Errorf("got wrong err: %v ", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemoveProjectMember(t *testing.T) {
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
type args struct {
|
||||||
|
es *ProjectEventstore
|
||||||
|
ctx context.Context
|
||||||
|
existing *model.Project
|
||||||
|
member *model.ProjectMember
|
||||||
|
}
|
||||||
|
type res struct {
|
||||||
|
result *model.ProjectMember
|
||||||
|
wantErr bool
|
||||||
|
errFunc func(err error) bool
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
res res
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "remove project member, ok",
|
||||||
|
args: args{
|
||||||
|
es: GetMockManipulateProjectWithMember(ctrl),
|
||||||
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
|
existing: &model.Project{
|
||||||
|
ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1},
|
||||||
|
Name: "Name",
|
||||||
|
Members: []*model.ProjectMember{&model.ProjectMember{UserID: "UserID", Roles: []string{"Roles"}}},
|
||||||
|
},
|
||||||
|
member: &model.ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, UserID: "UserID"},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
result: &model.ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, UserID: "UserID", Roles: []string{"Roles"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no userid",
|
||||||
|
args: args{
|
||||||
|
es: GetMockManipulateProject(ctrl),
|
||||||
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
|
existing: &model.Project{
|
||||||
|
ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1},
|
||||||
|
Name: "Name",
|
||||||
|
Members: []*model.ProjectMember{&model.ProjectMember{UserID: "UserID", Roles: []string{"Roles"}}},
|
||||||
|
},
|
||||||
|
member: &model.ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, Roles: []string{"ChangeRoles"}},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
wantErr: true,
|
||||||
|
errFunc: caos_errs.IsPreconditionFailed,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "member not existing",
|
||||||
|
args: args{
|
||||||
|
es: GetMockManipulateProject(ctrl),
|
||||||
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
|
existing: &model.Project{
|
||||||
|
ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1},
|
||||||
|
Name: "Name",
|
||||||
|
},
|
||||||
|
member: &model.ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, UserID: "UserID", Roles: []string{"Roles"}},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
wantErr: true,
|
||||||
|
errFunc: caos_errs.IsPreconditionFailed,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "existing not found",
|
||||||
|
args: args{
|
||||||
|
es: GetMockManipulateProjectNoEvents(ctrl),
|
||||||
|
ctx: auth.NewMockContext("orgID", "userID"),
|
||||||
|
member: &model.ProjectMember{ObjectRoot: es_models.ObjectRoot{ID: "ID", Sequence: 1}, UserID: "UserID", Roles: []string{"ChangeRoles"}},
|
||||||
|
},
|
||||||
|
res: res{
|
||||||
|
wantErr: true,
|
||||||
|
errFunc: caos_errs.IsNotFound,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
err := tt.args.es.RemoveProjectMember(tt.args.ctx, tt.args.member)
|
||||||
|
|
||||||
|
if !tt.res.wantErr && err != nil {
|
||||||
|
t.Errorf("should not get err")
|
||||||
|
}
|
||||||
|
if tt.res.wantErr && !tt.res.errFunc(err) {
|
||||||
|
t.Errorf("got wrong err: %v ", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@ package eventsourcing
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"github.com/caos/zitadel/internal/errors"
|
||||||
|
|
||||||
"github.com/caos/logging"
|
"github.com/caos/logging"
|
||||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||||
@ -14,11 +15,27 @@ const (
|
|||||||
|
|
||||||
type Project struct {
|
type Project struct {
|
||||||
es_models.ObjectRoot
|
es_models.ObjectRoot
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
State int32 `json:"-"`
|
State int32 `json:"-"`
|
||||||
|
Members []*ProjectMember `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProjectMember struct {
|
||||||
|
es_models.ObjectRoot
|
||||||
|
UserID string `json:"userId,omitempty"`
|
||||||
|
Roles []string `json:"roles,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Project) Changes(changed *Project) map[string]interface{} {
|
||||||
|
changes := make(map[string]interface{}, 1)
|
||||||
|
if changed.Name != "" && p.Name != changed.Name {
|
||||||
|
changes["name"] = changed.Name
|
||||||
|
}
|
||||||
|
return changes
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProjectFromModel(project *model.Project) *Project {
|
func ProjectFromModel(project *model.Project) *Project {
|
||||||
|
members := ProjectMembersFromModel(project.Members)
|
||||||
return &Project{
|
return &Project{
|
||||||
ObjectRoot: es_models.ObjectRoot{
|
ObjectRoot: es_models.ObjectRoot{
|
||||||
ID: project.ObjectRoot.ID,
|
ID: project.ObjectRoot.ID,
|
||||||
@ -26,12 +43,14 @@ func ProjectFromModel(project *model.Project) *Project {
|
|||||||
ChangeDate: project.ChangeDate,
|
ChangeDate: project.ChangeDate,
|
||||||
CreationDate: project.CreationDate,
|
CreationDate: project.CreationDate,
|
||||||
},
|
},
|
||||||
Name: project.Name,
|
Name: project.Name,
|
||||||
State: model.ProjectStateToInt(project.State),
|
State: model.ProjectStateToInt(project.State),
|
||||||
|
Members: members,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProjectToModel(project *Project) *model.Project {
|
func ProjectToModel(project *Project) *model.Project {
|
||||||
|
members := ProjectMembersToModel(project.Members)
|
||||||
return &model.Project{
|
return &model.Project{
|
||||||
ObjectRoot: es_models.ObjectRoot{
|
ObjectRoot: es_models.ObjectRoot{
|
||||||
ID: project.ID,
|
ID: project.ID,
|
||||||
@ -39,8 +58,51 @@ func ProjectToModel(project *Project) *model.Project {
|
|||||||
CreationDate: project.CreationDate,
|
CreationDate: project.CreationDate,
|
||||||
Sequence: project.Sequence,
|
Sequence: project.Sequence,
|
||||||
},
|
},
|
||||||
Name: project.Name,
|
Name: project.Name,
|
||||||
State: model.ProjectStateFromInt(project.State),
|
State: model.ProjectStateFromInt(project.State),
|
||||||
|
Members: members,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProjectMembersToModel(members []*ProjectMember) []*model.ProjectMember {
|
||||||
|
convertedMembers := make([]*model.ProjectMember, len(members))
|
||||||
|
for i, m := range members {
|
||||||
|
convertedMembers[i] = ProjectMemberToModel(m)
|
||||||
|
}
|
||||||
|
return convertedMembers
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProjectMembersFromModel(members []*model.ProjectMember) []*ProjectMember {
|
||||||
|
convertedMembers := make([]*ProjectMember, len(members))
|
||||||
|
for i, m := range members {
|
||||||
|
convertedMembers[i] = ProjectMemberFromModel(m)
|
||||||
|
}
|
||||||
|
return convertedMembers
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProjectMemberFromModel(member *model.ProjectMember) *ProjectMember {
|
||||||
|
return &ProjectMember{
|
||||||
|
ObjectRoot: es_models.ObjectRoot{
|
||||||
|
ID: member.ObjectRoot.ID,
|
||||||
|
Sequence: member.Sequence,
|
||||||
|
ChangeDate: member.ChangeDate,
|
||||||
|
CreationDate: member.CreationDate,
|
||||||
|
},
|
||||||
|
UserID: member.UserID,
|
||||||
|
Roles: member.Roles,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProjectMemberToModel(member *ProjectMember) *model.ProjectMember {
|
||||||
|
return &model.ProjectMember{
|
||||||
|
ObjectRoot: es_models.ObjectRoot{
|
||||||
|
ID: member.ID,
|
||||||
|
ChangeDate: member.ChangeDate,
|
||||||
|
CreationDate: member.CreationDate,
|
||||||
|
Sequence: member.Sequence,
|
||||||
|
},
|
||||||
|
UserID: member.UserID,
|
||||||
|
Roles: member.Roles,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,14 +114,6 @@ func ProjectFromEvents(project *Project, events ...*es_models.Event) (*Project,
|
|||||||
return project, project.AppendEvents(events...)
|
return project, project.AppendEvents(events...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Project) Changes(changed *Project) map[string]interface{} {
|
|
||||||
changes := make(map[string]interface{}, 1)
|
|
||||||
if changed.Name != "" && p.Name != changed.Name {
|
|
||||||
changes["name"] = changed.Name
|
|
||||||
}
|
|
||||||
return changes
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Project) AppendEvents(events ...*es_models.Event) error {
|
func (p *Project) AppendEvents(events ...*es_models.Event) error {
|
||||||
for _, event := range events {
|
for _, event := range events {
|
||||||
if err := p.AppendEvent(event); err != nil {
|
if err := p.AppendEvent(event); err != nil {
|
||||||
@ -84,8 +138,13 @@ func (p *Project) AppendEvent(event *es_models.Event) error {
|
|||||||
return p.appendDeactivatedEvent()
|
return p.appendDeactivatedEvent()
|
||||||
case model.ProjectReactivated:
|
case model.ProjectReactivated:
|
||||||
return p.appendReactivatedEvent()
|
return p.appendReactivatedEvent()
|
||||||
|
case model.ProjectMemberAdded:
|
||||||
|
return p.appendAddMemberEvent(event)
|
||||||
|
case model.ProjectMemberChanged:
|
||||||
|
return p.appendChangeMemberEvent(event)
|
||||||
|
case model.ProjectMemberRemoved:
|
||||||
|
return p.appendRemoveMemberEvent(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,3 +157,51 @@ func (p *Project) appendReactivatedEvent() error {
|
|||||||
p.State = model.ProjectStateToInt(model.Active)
|
p.State = model.ProjectStateToInt(model.Active)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Project) appendAddMemberEvent(event *es_models.Event) error {
|
||||||
|
member, err := getMemberData(event)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
member.ObjectRoot.CreationDate = event.CreationDate
|
||||||
|
p.Members = append(p.Members, member)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Project) appendChangeMemberEvent(event *es_models.Event) error {
|
||||||
|
member, err := getMemberData(event)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i, m := range p.Members {
|
||||||
|
if m.UserID == member.UserID {
|
||||||
|
p.Members[i] = member
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Project) appendRemoveMemberEvent(event *es_models.Event) error {
|
||||||
|
member, err := getMemberData(event)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i, m := range p.Members {
|
||||||
|
if m.UserID == member.UserID {
|
||||||
|
p.Members[i] = p.Members[len(p.Members)-1]
|
||||||
|
p.Members[len(p.Members)-1] = nil
|
||||||
|
p.Members = p.Members[:len(p.Members)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMemberData(event *es_models.Event) (*ProjectMember, error) {
|
||||||
|
member := &ProjectMember{}
|
||||||
|
member.ObjectRoot.AppendEvent(event)
|
||||||
|
if err := json.Unmarshal(event.Data, member); err != nil {
|
||||||
|
logging.Log("EVEN-e4dkp").WithError(err).Error("could not unmarshal event data")
|
||||||
|
return nil, errors.ThrowInternal(err, "EVENT-83js6", "could not unmarshal event data")
|
||||||
|
}
|
||||||
|
return member, nil
|
||||||
|
}
|
||||||
|
@ -212,3 +212,115 @@ func TestChanges(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func TestAppendAddMemberEvent(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
project *Project
|
||||||
|
member *ProjectMember
|
||||||
|
event *es_models.Event
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
result *Project
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "append add member event",
|
||||||
|
args: args{
|
||||||
|
project: &Project{},
|
||||||
|
member: &ProjectMember{UserID: "UserID", Roles: []string{"Role"}},
|
||||||
|
event: &es_models.Event{},
|
||||||
|
},
|
||||||
|
result: &Project{Members: []*ProjectMember{&ProjectMember{UserID: "UserID", Roles: []string{"Role"}}}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if tt.args.member != nil {
|
||||||
|
data, _ := json.Marshal(tt.args.member)
|
||||||
|
tt.args.event.Data = data
|
||||||
|
}
|
||||||
|
tt.args.project.appendAddMemberEvent(tt.args.event)
|
||||||
|
if len(tt.args.project.Members) != 1 {
|
||||||
|
t.Errorf("got wrong result should have one member actual: %v ", len(tt.args.project.Members))
|
||||||
|
}
|
||||||
|
if tt.args.project.Members[0] == tt.result.Members[0] {
|
||||||
|
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Members[0], tt.args.project.Members[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAppendChangeMemberEvent(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
project *Project
|
||||||
|
member *ProjectMember
|
||||||
|
event *es_models.Event
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
result *Project
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "append change member event",
|
||||||
|
args: args{
|
||||||
|
project: &Project{Members: []*ProjectMember{&ProjectMember{UserID: "UserID", Roles: []string{"Role"}}}},
|
||||||
|
member: &ProjectMember{UserID: "UserID", Roles: []string{"ChangedRole"}},
|
||||||
|
event: &es_models.Event{},
|
||||||
|
},
|
||||||
|
result: &Project{Members: []*ProjectMember{&ProjectMember{UserID: "UserID", Roles: []string{"ChangedRole"}}}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if tt.args.member != nil {
|
||||||
|
data, _ := json.Marshal(tt.args.member)
|
||||||
|
tt.args.event.Data = data
|
||||||
|
}
|
||||||
|
tt.args.project.appendChangeMemberEvent(tt.args.event)
|
||||||
|
if len(tt.args.project.Members) != 1 {
|
||||||
|
t.Errorf("got wrong result should have one member actual: %v ", len(tt.args.project.Members))
|
||||||
|
}
|
||||||
|
if tt.args.project.Members[0] == tt.result.Members[0] {
|
||||||
|
t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result.Members[0], tt.args.project.Members[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAppendRemoveMemberEvent(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
project *Project
|
||||||
|
member *ProjectMember
|
||||||
|
event *es_models.Event
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
result *Project
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "append remove member event",
|
||||||
|
args: args{
|
||||||
|
project: &Project{Members: []*ProjectMember{&ProjectMember{UserID: "UserID", Roles: []string{"Role"}}}},
|
||||||
|
member: &ProjectMember{UserID: "UserID"},
|
||||||
|
event: &es_models.Event{},
|
||||||
|
},
|
||||||
|
result: &Project{Members: []*ProjectMember{}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if tt.args.member != nil {
|
||||||
|
data, _ := json.Marshal(tt.args.member)
|
||||||
|
tt.args.event.Data = data
|
||||||
|
}
|
||||||
|
tt.args.project.appendRemoveMemberEvent(tt.args.event)
|
||||||
|
if len(tt.args.project.Members) != 0 {
|
||||||
|
t.Errorf("got wrong result should have one member actual: %v ", len(tt.args.project.Members))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -89,3 +89,43 @@ func projectStateAggregate(aggCreator *es_models.AggregateCreator, project *Proj
|
|||||||
return agg.AppendEvent(state, nil)
|
return agg.AppendEvent(state, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ProjectMemberAddedAggregate(aggCreator *es_models.AggregateCreator, existing *Project, member *ProjectMember) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||||
|
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||||
|
if existing == nil {
|
||||||
|
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-di38f", "existing project should not be nil")
|
||||||
|
}
|
||||||
|
agg, err := ProjectAggregate(ctx, aggCreator, existing.ID, existing.Sequence)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return agg.AppendEvent(model.ProjectMemberAdded, member)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProjectMemberChangedAggregate(aggCreator *es_models.AggregateCreator, existing *Project, member *ProjectMember) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||||
|
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||||
|
if existing == nil {
|
||||||
|
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-sle3d", "existing project should not be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
agg, err := ProjectAggregate(ctx, aggCreator, existing.ID, existing.Sequence)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return agg.AppendEvent(model.ProjectMemberChanged, member)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProjectMemberRemovedAggregate(aggCreator *es_models.AggregateCreator, existing *Project, member *ProjectMember) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||||
|
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||||
|
if existing == nil {
|
||||||
|
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-slo9e", "existing project should not be nil")
|
||||||
|
}
|
||||||
|
agg, err := ProjectAggregate(ctx, aggCreator, existing.ID, existing.Sequence)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return agg.AppendEvent(model.ProjectMemberRemoved, member)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1220,7 +1220,7 @@
|
|||||||
"200": {
|
"200": {
|
||||||
"description": "A successful response.",
|
"description": "A successful response.",
|
||||||
"schema": {
|
"schema": {
|
||||||
"properties": {}
|
"$ref": "#/definitions/v1ProjectMember"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1280,7 +1280,7 @@
|
|||||||
"200": {
|
"200": {
|
||||||
"description": "A successful response.",
|
"description": "A successful response.",
|
||||||
"schema": {
|
"schema": {
|
||||||
"properties": {}
|
"$ref": "#/definitions/v1ProjectMember"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -3213,7 +3213,7 @@
|
|||||||
"200": {
|
"200": {
|
||||||
"description": "A successful response.",
|
"description": "A successful response.",
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "object"
|
"$ref": "#/definitions/protobufStruct"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -3224,6 +3224,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
|
"protobufListValue": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"values": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/protobufValue"
|
||||||
|
},
|
||||||
|
"description": "Repeated field of dynamically typed values."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "`ListValue` is a wrapper around a repeated field of values.\n\nThe JSON representation for `ListValue` is JSON array."
|
||||||
|
},
|
||||||
"protobufNullValue": {
|
"protobufNullValue": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
@ -3232,6 +3245,51 @@
|
|||||||
"default": "NULL_VALUE",
|
"default": "NULL_VALUE",
|
||||||
"description": "`NullValue` is a singleton enumeration to represent the null value for the\n`Value` type union.\n\n The JSON representation for `NullValue` is JSON `null`.\n\n - NULL_VALUE: Null value."
|
"description": "`NullValue` is a singleton enumeration to represent the null value for the\n`Value` type union.\n\n The JSON representation for `NullValue` is JSON `null`.\n\n - NULL_VALUE: Null value."
|
||||||
},
|
},
|
||||||
|
"protobufStruct": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"fields": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"$ref": "#/definitions/protobufValue"
|
||||||
|
},
|
||||||
|
"description": "Unordered map of dynamically typed values."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "`Struct` represents a structured data value, consisting of fields\nwhich map to dynamically typed values. In some languages, `Struct`\nmight be supported by a native representation. For example, in\nscripting languages like JS a struct is represented as an\nobject. The details of that representation are described together\nwith the proto support for the language.\n\nThe JSON representation for `Struct` is JSON object."
|
||||||
|
},
|
||||||
|
"protobufValue": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"null_value": {
|
||||||
|
"$ref": "#/definitions/protobufNullValue",
|
||||||
|
"description": "Represents a null value."
|
||||||
|
},
|
||||||
|
"number_value": {
|
||||||
|
"type": "number",
|
||||||
|
"format": "double",
|
||||||
|
"description": "Represents a double value."
|
||||||
|
},
|
||||||
|
"string_value": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Represents a string value."
|
||||||
|
},
|
||||||
|
"bool_value": {
|
||||||
|
"type": "boolean",
|
||||||
|
"format": "boolean",
|
||||||
|
"description": "Represents a boolean value."
|
||||||
|
},
|
||||||
|
"struct_value": {
|
||||||
|
"$ref": "#/definitions/protobufStruct",
|
||||||
|
"description": "Represents a structured value."
|
||||||
|
},
|
||||||
|
"list_value": {
|
||||||
|
"$ref": "#/definitions/protobufListValue",
|
||||||
|
"description": "Represents a repeated `Value`."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "`Value` represents a dynamically typed value which can be either\nnull, a number, a string, a boolean, a recursive struct value, or a\nlist of values. A producer of value is expected to set one of that\nvariants, absence of any variant indicates an error.\n\nThe JSON representation for `Value` is JSON value."
|
||||||
|
},
|
||||||
"v1AddOrgMemberRequest": {
|
"v1AddOrgMemberRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -3490,7 +3548,7 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"type": "object"
|
"$ref": "#/definitions/protobufStruct"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -78,14 +78,14 @@ func (mr *MockManagementServiceClientMockRecorder) AddProjectGrantMember(arg0, a
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddProjectMember mocks base method
|
// AddProjectMember mocks base method
|
||||||
func (m *MockManagementServiceClient) AddProjectMember(arg0 context.Context, arg1 *grpc.ProjectMemberAdd, arg2 ...grpc0.CallOption) (*emptypb.Empty, error) {
|
func (m *MockManagementServiceClient) AddProjectMember(arg0 context.Context, arg1 *grpc.ProjectMemberAdd, arg2 ...grpc0.CallOption) (*grpc.ProjectMember, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
varargs := []interface{}{arg0, arg1}
|
varargs := []interface{}{arg0, arg1}
|
||||||
for _, a := range arg2 {
|
for _, a := range arg2 {
|
||||||
varargs = append(varargs, a)
|
varargs = append(varargs, a)
|
||||||
}
|
}
|
||||||
ret := m.ctrl.Call(m, "AddProjectMember", varargs...)
|
ret := m.ctrl.Call(m, "AddProjectMember", varargs...)
|
||||||
ret0, _ := ret[0].(*emptypb.Empty)
|
ret0, _ := ret[0].(*grpc.ProjectMember)
|
||||||
ret1, _ := ret[1].(error)
|
ret1, _ := ret[1].(error)
|
||||||
return ret0, ret1
|
return ret0, ret1
|
||||||
}
|
}
|
||||||
@ -198,14 +198,14 @@ func (mr *MockManagementServiceClientMockRecorder) ChangeProjectGrantMember(arg0
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ChangeProjectMember mocks base method
|
// ChangeProjectMember mocks base method
|
||||||
func (m *MockManagementServiceClient) ChangeProjectMember(arg0 context.Context, arg1 *grpc.ProjectMemberChange, arg2 ...grpc0.CallOption) (*emptypb.Empty, error) {
|
func (m *MockManagementServiceClient) ChangeProjectMember(arg0 context.Context, arg1 *grpc.ProjectMemberChange, arg2 ...grpc0.CallOption) (*grpc.ProjectMember, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
varargs := []interface{}{arg0, arg1}
|
varargs := []interface{}{arg0, arg1}
|
||||||
for _, a := range arg2 {
|
for _, a := range arg2 {
|
||||||
varargs = append(varargs, a)
|
varargs = append(varargs, a)
|
||||||
}
|
}
|
||||||
ret := m.ctrl.Call(m, "ChangeProjectMember", varargs...)
|
ret := m.ctrl.Call(m, "ChangeProjectMember", varargs...)
|
||||||
ret0, _ := ret[0].(*emptypb.Empty)
|
ret0, _ := ret[0].(*grpc.ProjectMember)
|
||||||
ret1, _ := ret[1].(error)
|
ret1, _ := ret[1].(error)
|
||||||
return ret0, ret1
|
return ret0, ret1
|
||||||
}
|
}
|
||||||
|
@ -14,14 +14,23 @@ func (s *Server) SearchProjectMembers(ctx context.Context, request *ProjectMembe
|
|||||||
return nil, errors.ThrowUnimplemented(nil, "GRPC-PLr84", "Not implemented")
|
return nil, errors.ThrowUnimplemented(nil, "GRPC-PLr84", "Not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) AddProjectMember(ctx context.Context, in *ProjectMemberAdd) (*empty.Empty, error) {
|
func (s *Server) AddProjectMember(ctx context.Context, in *ProjectMemberAdd) (*ProjectMember, error) {
|
||||||
return nil, errors.ThrowUnimplemented(nil, "GRPC-c2dks", "Not implemented")
|
member, err := s.project.AddProjectMember(ctx, projectMemberAddToModel(in))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return projectMemberFromModel(member), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) ChangeProjectMember(ctx context.Context, in *ProjectMemberChange) (*empty.Empty, error) {
|
func (s *Server) ChangeProjectMember(ctx context.Context, in *ProjectMemberChange) (*ProjectMember, error) {
|
||||||
return nil, errors.ThrowUnimplemented(nil, "GRPC-cms47", "Not implemented")
|
member, err := s.project.ChangeProjectMember(ctx, projectMemberChangeToModel(in))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return projectMemberFromModel(member), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) RemoveProjectMember(ctx context.Context, in *ProjectMemberRemove) (*empty.Empty, error) {
|
func (s *Server) RemoveProjectMember(ctx context.Context, in *ProjectMemberRemove) (*empty.Empty, error) {
|
||||||
return nil, errors.ThrowUnimplemented(nil, "GRPC-olw21", "Not implemented")
|
err := s.project.RemoveProjectMember(ctx, in.Id, in.UserId)
|
||||||
|
return &empty.Empty{}, err
|
||||||
}
|
}
|
||||||
|
44
pkg/management/api/grpc/project_member_converter.go
Normal file
44
pkg/management/api/grpc/project_member_converter.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package grpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/caos/logging"
|
||||||
|
"github.com/caos/zitadel/internal/eventstore/models"
|
||||||
|
proj_model "github.com/caos/zitadel/internal/project/model"
|
||||||
|
"github.com/golang/protobuf/ptypes"
|
||||||
|
)
|
||||||
|
|
||||||
|
func projectMemberFromModel(member *proj_model.ProjectMember) *ProjectMember {
|
||||||
|
creationDate, err := ptypes.TimestampProto(member.CreationDate)
|
||||||
|
logging.Log("GRPC-kd8re").OnError(err).Debug("unable to parse timestamp")
|
||||||
|
|
||||||
|
changeDate, err := ptypes.TimestampProto(member.ChangeDate)
|
||||||
|
logging.Log("GRPC-dlei3").OnError(err).Debug("unable to parse timestamp")
|
||||||
|
|
||||||
|
return &ProjectMember{
|
||||||
|
CreationDate: creationDate,
|
||||||
|
ChangeDate: changeDate,
|
||||||
|
Sequence: member.Sequence,
|
||||||
|
UserId: member.UserID,
|
||||||
|
Roles: member.Roles,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func projectMemberAddToModel(member *ProjectMemberAdd) *proj_model.ProjectMember {
|
||||||
|
return &proj_model.ProjectMember{
|
||||||
|
ObjectRoot: models.ObjectRoot{
|
||||||
|
ID: member.Id,
|
||||||
|
},
|
||||||
|
UserID: member.UserId,
|
||||||
|
Roles: member.Roles,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func projectMemberChangeToModel(member *ProjectMemberChange) *proj_model.ProjectMember {
|
||||||
|
return &proj_model.ProjectMember{
|
||||||
|
ObjectRoot: models.ObjectRoot{
|
||||||
|
ID: member.Id,
|
||||||
|
},
|
||||||
|
UserID: member.UserId,
|
||||||
|
Roles: member.Roles,
|
||||||
|
}
|
||||||
|
}
|
@ -674,7 +674,7 @@ service ManagementService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc AddProjectMember(ProjectMemberAdd) returns (google.protobuf.Empty) {
|
rpc AddProjectMember(ProjectMemberAdd) returns (ProjectMember) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
post: "/projects/{id}/members"
|
post: "/projects/{id}/members"
|
||||||
body: "*"
|
body: "*"
|
||||||
@ -686,7 +686,7 @@ service ManagementService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc ChangeProjectMember(ProjectMemberChange) returns (google.protobuf.Empty) {
|
rpc ChangeProjectMember(ProjectMemberChange) returns (ProjectMember) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
put: "/projects/{id}/members/{user_id}"
|
put: "/projects/{id}/members/{user_id}"
|
||||||
body: "*"
|
body: "*"
|
||||||
|
Loading…
Reference in New Issue
Block a user