diff --git a/internal/modules/team/group.go b/internal/modules/team/group.go new file mode 100644 index 0000000..9aad928 --- /dev/null +++ b/internal/modules/team/group.go @@ -0,0 +1,63 @@ +package team + +import ( + "management/internal/shared/db" + + "github.com/netbirdio/netbird/management/server/integration_reference" +) + +type Group struct { + // ID of the group + ID string `gorm:"primaryKey"` + + // AccountID is a reference to Account that this object belongs + AccountID string `json:"-" gorm:"index"` + + // Name visible in the UI + Name string + + // Issued defines how this group was created (enum of "api", "integration" or "jwt") + Issued string + + // Peers list of the group + Peers []string `gorm:"serializer:json"` + + // Resources contains a list of resources in that group + Resources []Resource `gorm:"serializer:json"` + + IntegrationReference integration_reference.IntegrationReference `gorm:"embedded;embeddedPrefix:integration_ref_"` +} + +func (Group) TableName() string { + return "groups" +} + +type Resource struct { + ID string + Type string +} + +// func (r *Resource) ToAPIResponse() *api.Resource { +// if r.ID == "" && r.Type == "" { +// return nil +// } + +// return &api.Resource{ +// Id: r.ID, +// Type: api.ResourceType(r.Type), +// } +// } + +// func (r *Resource) FromAPIRequest(req *api.Resource) { +// if req == nil { +// return +// } + +// r.ID = req.Id +// r.Type = string(req.Type) +// } + +type ( + GroupEvent = db.ModelEvent[Group] + GroupErrorEvent = db.ModelErrorEvent[Group] +) diff --git a/internal/modules/team/handler/group.go b/internal/modules/team/handler/group.go new file mode 100644 index 0000000..e69de29 diff --git a/internal/modules/team/handler/handler.go b/internal/modules/team/handler/handler.go new file mode 100644 index 0000000..e69de29 diff --git a/internal/modules/team/handler/pat.go b/internal/modules/team/handler/pat.go new file mode 100644 index 0000000..e69de29 diff --git a/internal/modules/team/handler/user.go b/internal/modules/team/handler/user.go new file mode 100644 index 0000000..e69de29 diff --git a/internal/modules/team/manager.go b/internal/modules/team/manager.go new file mode 100644 index 0000000..b20d1f9 --- /dev/null +++ b/internal/modules/team/manager.go @@ -0,0 +1,47 @@ +package team + +//go:generate go run github.com/golang/mock/mockgen -package team -destination=manager_mock.go -source=./manager.go -build_flags=-mod=mod + +import ( + "context" + "management/internal/shared/db" + "management/internal/shared/hook" +) + +// needed for go:generate's mock run +// https://github.com/golang/mock/issues/621 +type ( + GroupHookEvent = *hook.Hook[*GroupEvent] + GroupHookErrorEvent = *hook.Hook[*GroupErrorEvent] +) + +type Manager interface { + // User methods + GetUsersByAccount(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID string) ([]*User, error) + GetUserById(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID, userID string) (*User, error) + CreateUser(ctx context.Context, tx db.Transaction, user *User) (*User, error) + UpdateUser(ctx context.Context, tx db.Transaction, user *User) (*User, error) + DeleteUser(ctx context.Context, tx db.Transaction, user *User) error + + // Group methods + GetGroupsByAccount(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID string) ([]*Group, error) + GetGroupsByUser(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID, userID string) ([]*Group, error) + GetGroupById(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID, groupID string) (*Group, error) + CreateGroup(ctx context.Context, tx db.Transaction, group *Group) (*Group, error) + UpdateGroup(ctx context.Context, tx db.Transaction, group *Group) (*Group, error) + DeleteGroup(ctx context.Context, tx db.Transaction, group *Group) error + OnGroupCreate() GroupHookEvent + OnGroupCreateError() GroupHookErrorEvent + OnGroupUpdate() GroupHookEvent + OnGroupUpdateError() GroupHookErrorEvent + OnGroupDelete() GroupHookEvent + OnGroupDeleteError() GroupHookErrorEvent + + // PAT methods + GetPATSByAccount(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID string) ([]*PersonalAccessToken, error) + GetPATSByUser(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID, userID string) ([]*PersonalAccessToken, error) + GetPATById(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID, patID string) (*PersonalAccessToken, error) + CreatePAT(ctx context.Context, tx db.Transaction, group *PersonalAccessToken) (*PersonalAccessToken, error) + UpdatePAT(ctx context.Context, tx db.Transaction, group *PersonalAccessToken) (*PersonalAccessToken, error) + DeletePAT(ctx context.Context, tx db.Transaction, group *PersonalAccessToken) error +} diff --git a/internal/modules/team/manager/group.go b/internal/modules/team/manager/group.go new file mode 100644 index 0000000..2bb0918 --- /dev/null +++ b/internal/modules/team/manager/group.go @@ -0,0 +1,96 @@ +package manager + +import ( + "context" + "fmt" + "management/internal/modules/team" + "management/internal/shared/db" + "management/internal/shared/hook" +) + +// GetGroupById implements team.Manager. +func (m *manager) GetGroupById(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID string, groupID string) (*team.Group, error) { + panic("unimplemented") +} + +// GetGroupsByAccount implements team.Manager. +func (m *manager) GetGroupsByAccount(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID string) ([]*team.Group, error) { + panic("unimplemented") +} + +// GetGroupsByUser implements team.Manager. +func (m *manager) GetGroupsByUser(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID string, userID string) ([]*team.Group, error) { + panic("unimplemented") +} + +// CreateGroup implements team.Manager. +func (m *manager) CreateGroup(ctx context.Context, tx db.Transaction, group *team.Group) (*team.Group, error) { + panic("unimplemented") +} + +// DeleteGroup implements team.Manager. +func (m *manager) DeleteGroup(ctx context.Context, tx db.Transaction, group *team.Group) error { + panic("unimplemented") +} + +// UpdateGroup implements team.Manager. +func (m *manager) UpdateGroup(ctx context.Context, tx db.Transaction, group *team.Group) (*team.Group, error) { + err := db.WithTx(m.repository.Store(), tx, func(tx db.Transaction) error { + ev := &team.GroupEvent{ + Tx: tx, + Context: ctx, + Model: group, + } + + err := m.OnGroupUpdate().Trigger(ev, func(ge *team.GroupEvent) error { + if err := m.repository.Store().Update(tx, ge.Model); err != nil { + return fmt.Errorf("failed to update group: %w", err) + } + + tx.AddEvent(func() { + // addActivityEvent("Network deleted") + // noop + }) + return nil + }) + + return err + }) + if err != nil { + return nil, err + } + return group, nil +} + +func (m *manager) OnGroupUpdate() team.GroupHookEvent { + return m.onGroupUpdate +} + +func (m *manager) OnGroupUpdateError() team.GroupHookErrorEvent { + return m.onGroupUpdateError +} + +func (m *manager) OnGroupCreate() team.GroupHookEvent { + panic("unimplemented") +} + +func (m *manager) OnGroupCreateError() team.GroupHookErrorEvent { + panic("unimplemented") +} + +func (m *manager) OnGroupDelete() team.GroupHookEvent { + panic("unimplemented") +} + +func (m *manager) OnGroupDeleteError() team.GroupHookErrorEvent { + panic("unimplemented") +} + +func (m *manager) initGroupHooks() { + m.onGroupCreate = &hook.Hook[*team.GroupEvent]{} + m.onGroupCreateError = &hook.Hook[*team.GroupErrorEvent]{} + m.onGroupUpdate = &hook.Hook[*team.GroupEvent]{} + m.onGroupUpdateError = &hook.Hook[*team.GroupErrorEvent]{} + m.onGroupDelete = &hook.Hook[*team.GroupEvent]{} + m.onGroupDeleteError = &hook.Hook[*team.GroupErrorEvent]{} +} diff --git a/internal/modules/team/manager/manager.go b/internal/modules/team/manager/manager.go new file mode 100644 index 0000000..229e924 --- /dev/null +++ b/internal/modules/team/manager/manager.go @@ -0,0 +1,29 @@ +package manager + +import ( + "management/internal/modules/team" + "management/internal/shared/hook" +) + +var _ team.Manager = (*manager)(nil) + +type manager struct { + repository team.Repository + + onGroupCreate *hook.Hook[*team.GroupEvent] + onGroupCreateError *hook.Hook[*team.GroupErrorEvent] + onGroupUpdate *hook.Hook[*team.GroupEvent] + onGroupUpdateError *hook.Hook[*team.GroupErrorEvent] + onGroupDelete *hook.Hook[*team.GroupEvent] + onGroupDeleteError *hook.Hook[*team.GroupErrorEvent] + + // @todo user and pat events +} + +func NewManager(repository team.Repository) *manager { + m := &manager{ + repository: repository, + } + m.initGroupHooks() + return m +} diff --git a/internal/modules/team/manager/pat.go b/internal/modules/team/manager/pat.go new file mode 100644 index 0000000..63282e8 --- /dev/null +++ b/internal/modules/team/manager/pat.go @@ -0,0 +1,37 @@ +package manager + +import ( + "context" + "management/internal/modules/team" + "management/internal/shared/db" +) + +// GetPATSByAccount implements team.Manager. +func (m *manager) GetPATSByAccount(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID string) ([]*team.PersonalAccessToken, error) { + panic("unimplemented") +} + +// GetPATById implements team.Manager. +func (m *manager) GetPATById(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID string, patID string) (*team.PersonalAccessToken, error) { + panic("unimplemented") +} + +// CreatePAT implements team.Manager. +func (m *manager) CreatePAT(ctx context.Context, tx db.Transaction, group *team.PersonalAccessToken) (*team.PersonalAccessToken, error) { + panic("unimplemented") +} + +// DeletePAT implements team.Manager. +func (m *manager) DeletePAT(ctx context.Context, tx db.Transaction, group *team.PersonalAccessToken) error { + panic("unimplemented") +} + +// UpdatePAT implements team.Manager. +func (m *manager) UpdatePAT(ctx context.Context, tx db.Transaction, group *team.PersonalAccessToken) (*team.PersonalAccessToken, error) { + panic("unimplemented") +} + +// GetPATSByUser implements team.Manager. +func (m *manager) GetPATSByUser(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID string, userID string) ([]*team.PersonalAccessToken, error) { + panic("unimplemented") +} diff --git a/internal/modules/team/manager/user.go b/internal/modules/team/manager/user.go new file mode 100644 index 0000000..06a012a --- /dev/null +++ b/internal/modules/team/manager/user.go @@ -0,0 +1,32 @@ +package manager + +import ( + "context" + "management/internal/modules/team" + "management/internal/shared/db" +) + +// GetUserById implements team.Manager. +func (m *manager) GetUserById(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID string, userID string) (*team.User, error) { + panic("unimplemented") +} + +// GetUsersByAccount implements team.Manager. +func (m *manager) GetUsersByAccount(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID string) ([]*team.User, error) { + panic("unimplemented") +} + +// UpdateUser implements team.Manager. +func (m *manager) UpdateUser(ctx context.Context, tx db.Transaction, user *team.User) (*team.User, error) { + panic("unimplemented") +} + +// CreateUser implements team.Manager. +func (m *manager) CreateUser(ctx context.Context, tx db.Transaction, user *team.User) (*team.User, error) { + panic("unimplemented") +} + +// DeleteUser implements team.Manager. +func (m *manager) DeleteUser(ctx context.Context, tx db.Transaction, user *team.User) error { + panic("unimplemented") +} diff --git a/internal/modules/team/manager_mock.go b/internal/modules/team/manager_mock.go new file mode 100644 index 0000000..5544488 --- /dev/null +++ b/internal/modules/team/manager_mock.go @@ -0,0 +1,372 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ./manager.go + +// Package team is a generated GoMock package. +package team + +import ( + context "context" + db "management/internal/shared/db" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" +) + +// MockManager is a mock of Manager interface. +type MockManager struct { + ctrl *gomock.Controller + recorder *MockManagerMockRecorder +} + +// MockManagerMockRecorder is the mock recorder for MockManager. +type MockManagerMockRecorder struct { + mock *MockManager +} + +// NewMockManager creates a new mock instance. +func NewMockManager(ctrl *gomock.Controller) *MockManager { + mock := &MockManager{ctrl: ctrl} + mock.recorder = &MockManagerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockManager) EXPECT() *MockManagerMockRecorder { + return m.recorder +} + +// CreateGroup mocks base method. +func (m *MockManager) CreateGroup(ctx context.Context, tx db.Transaction, group *Group) (*Group, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateGroup", ctx, tx, group) + ret0, _ := ret[0].(*Group) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateGroup indicates an expected call of CreateGroup. +func (mr *MockManagerMockRecorder) CreateGroup(ctx, tx, group interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateGroup", reflect.TypeOf((*MockManager)(nil).CreateGroup), ctx, tx, group) +} + +// CreatePAT mocks base method. +func (m *MockManager) CreatePAT(ctx context.Context, tx db.Transaction, group *PersonalAccessToken) (*PersonalAccessToken, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreatePAT", ctx, tx, group) + ret0, _ := ret[0].(*PersonalAccessToken) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreatePAT indicates an expected call of CreatePAT. +func (mr *MockManagerMockRecorder) CreatePAT(ctx, tx, group interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatePAT", reflect.TypeOf((*MockManager)(nil).CreatePAT), ctx, tx, group) +} + +// CreateUser mocks base method. +func (m *MockManager) CreateUser(ctx context.Context, tx db.Transaction, user *User) (*User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateUser", ctx, tx, user) + ret0, _ := ret[0].(*User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateUser indicates an expected call of CreateUser. +func (mr *MockManagerMockRecorder) CreateUser(ctx, tx, user interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateUser", reflect.TypeOf((*MockManager)(nil).CreateUser), ctx, tx, user) +} + +// DeleteGroup mocks base method. +func (m *MockManager) DeleteGroup(ctx context.Context, tx db.Transaction, group *Group) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteGroup", ctx, tx, group) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteGroup indicates an expected call of DeleteGroup. +func (mr *MockManagerMockRecorder) DeleteGroup(ctx, tx, group interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteGroup", reflect.TypeOf((*MockManager)(nil).DeleteGroup), ctx, tx, group) +} + +// DeletePAT mocks base method. +func (m *MockManager) DeletePAT(ctx context.Context, tx db.Transaction, group *PersonalAccessToken) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeletePAT", ctx, tx, group) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeletePAT indicates an expected call of DeletePAT. +func (mr *MockManagerMockRecorder) DeletePAT(ctx, tx, group interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePAT", reflect.TypeOf((*MockManager)(nil).DeletePAT), ctx, tx, group) +} + +// DeleteUser mocks base method. +func (m *MockManager) DeleteUser(ctx context.Context, tx db.Transaction, user *User) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteUser", ctx, tx, user) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteUser indicates an expected call of DeleteUser. +func (mr *MockManagerMockRecorder) DeleteUser(ctx, tx, user interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteUser", reflect.TypeOf((*MockManager)(nil).DeleteUser), ctx, tx, user) +} + +// GetGroupById mocks base method. +func (m *MockManager) GetGroupById(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID, groupID string) (*Group, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetGroupById", ctx, tx, strength, accountID, groupID) + ret0, _ := ret[0].(*Group) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetGroupById indicates an expected call of GetGroupById. +func (mr *MockManagerMockRecorder) GetGroupById(ctx, tx, strength, accountID, groupID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupById", reflect.TypeOf((*MockManager)(nil).GetGroupById), ctx, tx, strength, accountID, groupID) +} + +// GetGroupsByAccount mocks base method. +func (m *MockManager) GetGroupsByAccount(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID string) ([]*Group, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetGroupsByAccount", ctx, tx, strength, accountID) + ret0, _ := ret[0].([]*Group) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetGroupsByAccount indicates an expected call of GetGroupsByAccount. +func (mr *MockManagerMockRecorder) GetGroupsByAccount(ctx, tx, strength, accountID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupsByAccount", reflect.TypeOf((*MockManager)(nil).GetGroupsByAccount), ctx, tx, strength, accountID) +} + +// GetGroupsByUser mocks base method. +func (m *MockManager) GetGroupsByUser(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID, userID string) ([]*Group, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetGroupsByUser", ctx, tx, strength, accountID, userID) + ret0, _ := ret[0].([]*Group) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetGroupsByUser indicates an expected call of GetGroupsByUser. +func (mr *MockManagerMockRecorder) GetGroupsByUser(ctx, tx, strength, accountID, userID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupsByUser", reflect.TypeOf((*MockManager)(nil).GetGroupsByUser), ctx, tx, strength, accountID, userID) +} + +// GetPATById mocks base method. +func (m *MockManager) GetPATById(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID, patID string) (*PersonalAccessToken, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPATById", ctx, tx, strength, accountID, patID) + ret0, _ := ret[0].(*PersonalAccessToken) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPATById indicates an expected call of GetPATById. +func (mr *MockManagerMockRecorder) GetPATById(ctx, tx, strength, accountID, patID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPATById", reflect.TypeOf((*MockManager)(nil).GetPATById), ctx, tx, strength, accountID, patID) +} + +// GetPATSByAccount mocks base method. +func (m *MockManager) GetPATSByAccount(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID string) ([]*PersonalAccessToken, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPATSByAccount", ctx, tx, strength, accountID) + ret0, _ := ret[0].([]*PersonalAccessToken) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPATSByAccount indicates an expected call of GetPATSByAccount. +func (mr *MockManagerMockRecorder) GetPATSByAccount(ctx, tx, strength, accountID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPATSByAccount", reflect.TypeOf((*MockManager)(nil).GetPATSByAccount), ctx, tx, strength, accountID) +} + +// GetPATSByUser mocks base method. +func (m *MockManager) GetPATSByUser(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID, userID string) ([]*PersonalAccessToken, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPATSByUser", ctx, tx, strength, accountID, userID) + ret0, _ := ret[0].([]*PersonalAccessToken) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPATSByUser indicates an expected call of GetPATSByUser. +func (mr *MockManagerMockRecorder) GetPATSByUser(ctx, tx, strength, accountID, userID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPATSByUser", reflect.TypeOf((*MockManager)(nil).GetPATSByUser), ctx, tx, strength, accountID, userID) +} + +// GetUserById mocks base method. +func (m *MockManager) GetUserById(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID, userID string) (*User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUserById", ctx, tx, strength, accountID, userID) + ret0, _ := ret[0].(*User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUserById indicates an expected call of GetUserById. +func (mr *MockManagerMockRecorder) GetUserById(ctx, tx, strength, accountID, userID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserById", reflect.TypeOf((*MockManager)(nil).GetUserById), ctx, tx, strength, accountID, userID) +} + +// GetUsersByAccount mocks base method. +func (m *MockManager) GetUsersByAccount(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID string) ([]*User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUsersByAccount", ctx, tx, strength, accountID) + ret0, _ := ret[0].([]*User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUsersByAccount indicates an expected call of GetUsersByAccount. +func (mr *MockManagerMockRecorder) GetUsersByAccount(ctx, tx, strength, accountID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUsersByAccount", reflect.TypeOf((*MockManager)(nil).GetUsersByAccount), ctx, tx, strength, accountID) +} + +// OnGroupCreate mocks base method. +func (m *MockManager) OnGroupCreate() GroupHookEvent { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnGroupCreate") + ret0, _ := ret[0].(GroupHookEvent) + return ret0 +} + +// OnGroupCreate indicates an expected call of OnGroupCreate. +func (mr *MockManagerMockRecorder) OnGroupCreate() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnGroupCreate", reflect.TypeOf((*MockManager)(nil).OnGroupCreate)) +} + +// OnGroupCreateError mocks base method. +func (m *MockManager) OnGroupCreateError() GroupHookErrorEvent { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnGroupCreateError") + ret0, _ := ret[0].(GroupHookErrorEvent) + return ret0 +} + +// OnGroupCreateError indicates an expected call of OnGroupCreateError. +func (mr *MockManagerMockRecorder) OnGroupCreateError() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnGroupCreateError", reflect.TypeOf((*MockManager)(nil).OnGroupCreateError)) +} + +// OnGroupDelete mocks base method. +func (m *MockManager) OnGroupDelete() GroupHookEvent { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnGroupDelete") + ret0, _ := ret[0].(GroupHookEvent) + return ret0 +} + +// OnGroupDelete indicates an expected call of OnGroupDelete. +func (mr *MockManagerMockRecorder) OnGroupDelete() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnGroupDelete", reflect.TypeOf((*MockManager)(nil).OnGroupDelete)) +} + +// OnGroupDeleteError mocks base method. +func (m *MockManager) OnGroupDeleteError() GroupHookErrorEvent { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnGroupDeleteError") + ret0, _ := ret[0].(GroupHookErrorEvent) + return ret0 +} + +// OnGroupDeleteError indicates an expected call of OnGroupDeleteError. +func (mr *MockManagerMockRecorder) OnGroupDeleteError() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnGroupDeleteError", reflect.TypeOf((*MockManager)(nil).OnGroupDeleteError)) +} + +// OnGroupUpdate mocks base method. +func (m *MockManager) OnGroupUpdate() GroupHookEvent { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnGroupUpdate") + ret0, _ := ret[0].(GroupHookEvent) + return ret0 +} + +// OnGroupUpdate indicates an expected call of OnGroupUpdate. +func (mr *MockManagerMockRecorder) OnGroupUpdate() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnGroupUpdate", reflect.TypeOf((*MockManager)(nil).OnGroupUpdate)) +} + +// OnGroupUpdateError mocks base method. +func (m *MockManager) OnGroupUpdateError() GroupHookErrorEvent { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnGroupUpdateError") + ret0, _ := ret[0].(GroupHookErrorEvent) + return ret0 +} + +// OnGroupUpdateError indicates an expected call of OnGroupUpdateError. +func (mr *MockManagerMockRecorder) OnGroupUpdateError() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnGroupUpdateError", reflect.TypeOf((*MockManager)(nil).OnGroupUpdateError)) +} + +// UpdateGroup mocks base method. +func (m *MockManager) UpdateGroup(ctx context.Context, tx db.Transaction, group *Group) (*Group, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateGroup", ctx, tx, group) + ret0, _ := ret[0].(*Group) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateGroup indicates an expected call of UpdateGroup. +func (mr *MockManagerMockRecorder) UpdateGroup(ctx, tx, group interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateGroup", reflect.TypeOf((*MockManager)(nil).UpdateGroup), ctx, tx, group) +} + +// UpdatePAT mocks base method. +func (m *MockManager) UpdatePAT(ctx context.Context, tx db.Transaction, group *PersonalAccessToken) (*PersonalAccessToken, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdatePAT", ctx, tx, group) + ret0, _ := ret[0].(*PersonalAccessToken) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdatePAT indicates an expected call of UpdatePAT. +func (mr *MockManagerMockRecorder) UpdatePAT(ctx, tx, group interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatePAT", reflect.TypeOf((*MockManager)(nil).UpdatePAT), ctx, tx, group) +} + +// UpdateUser mocks base method. +func (m *MockManager) UpdateUser(ctx context.Context, tx db.Transaction, user *User) (*User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateUser", ctx, tx, user) + ret0, _ := ret[0].(*User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateUser indicates an expected call of UpdateUser. +func (mr *MockManagerMockRecorder) UpdateUser(ctx, tx, user interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUser", reflect.TypeOf((*MockManager)(nil).UpdateUser), ctx, tx, user) +} diff --git a/internal/modules/team/pat.go b/internal/modules/team/pat.go new file mode 100644 index 0000000..2ed3d06 --- /dev/null +++ b/internal/modules/team/pat.go @@ -0,0 +1,26 @@ +package team + +import ( + "management/internal/shared/db" + "time" +) + +// PersonalAccessToken holds all information about a PAT including a hashed version of it for verification +type PersonalAccessToken struct { + ID string `gorm:"primaryKey"` + // User is a reference to Account that this object belongs + UserID string `gorm:"index"` + Name string + HashedToken string + ExpirationDate *time.Time + // scope could be added in future + CreatedBy string + CreatedAt time.Time + LastUsed *time.Time +} + +func (PersonalAccessToken) TableName() string { + return "personal_access_tokens" +} + +type PersonalAccessTokenEvent = db.ModelEvent[PersonalAccessToken] diff --git a/internal/modules/team/repository.go b/internal/modules/team/repository.go new file mode 100644 index 0000000..a5527a2 --- /dev/null +++ b/internal/modules/team/repository.go @@ -0,0 +1,9 @@ +package team + +//go:generate go run github.com/golang/mock/mockgen -package team -destination=repository_mock.go -source=./repository.go -build_flags=-mod=mod + +import "management/internal/shared/db" + +type Repository interface { + Store() *db.Store +} diff --git a/internal/modules/team/repository/group.go b/internal/modules/team/repository/group.go new file mode 100644 index 0000000..50a4378 --- /dev/null +++ b/internal/modules/team/repository/group.go @@ -0,0 +1 @@ +package repository diff --git a/internal/modules/team/repository/pat.go b/internal/modules/team/repository/pat.go new file mode 100644 index 0000000..50a4378 --- /dev/null +++ b/internal/modules/team/repository/pat.go @@ -0,0 +1 @@ +package repository diff --git a/internal/modules/team/repository/repository.go b/internal/modules/team/repository/repository.go new file mode 100644 index 0000000..1ae8613 --- /dev/null +++ b/internal/modules/team/repository/repository.go @@ -0,0 +1,20 @@ +package repository + +import ( + "management/internal/modules/team" + "management/internal/shared/db" +) + +var _ team.Repository = (*repository)(nil) + +type repository struct { + store *db.Store +} + +func NewRepository(s *db.Store) *repository { + return &repository{store: s} +} + +func (r *repository) Store() *db.Store { + return r.store +} diff --git a/internal/modules/team/repository/user.go b/internal/modules/team/repository/user.go new file mode 100644 index 0000000..50a4378 --- /dev/null +++ b/internal/modules/team/repository/user.go @@ -0,0 +1 @@ +package repository diff --git a/internal/modules/team/repository_mock.go b/internal/modules/team/repository_mock.go new file mode 100644 index 0000000..9b2a8e5 --- /dev/null +++ b/internal/modules/team/repository_mock.go @@ -0,0 +1,49 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ./repository.go + +// Package team is a generated GoMock package. +package team + +import ( + db "management/internal/shared/db" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" +) + +// MockRepository is a mock of Repository interface. +type MockRepository struct { + ctrl *gomock.Controller + recorder *MockRepositoryMockRecorder +} + +// MockRepositoryMockRecorder is the mock recorder for MockRepository. +type MockRepositoryMockRecorder struct { + mock *MockRepository +} + +// NewMockRepository creates a new mock instance. +func NewMockRepository(ctrl *gomock.Controller) *MockRepository { + mock := &MockRepository{ctrl: ctrl} + mock.recorder = &MockRepositoryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder { + return m.recorder +} + +// Store mocks base method. +func (m *MockRepository) Store() *db.Store { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Store") + ret0, _ := ret[0].(*db.Store) + return ret0 +} + +// Store indicates an expected call of Store. +func (mr *MockRepositoryMockRecorder) Store() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Store", reflect.TypeOf((*MockRepository)(nil).Store)) +} diff --git a/internal/modules/team/user.go b/internal/modules/team/user.go new file mode 100644 index 0000000..da525e5 --- /dev/null +++ b/internal/modules/team/user.go @@ -0,0 +1,43 @@ +package team + +import ( + "management/internal/shared/db" + "time" + + "github.com/netbirdio/netbird/management/server/integration_reference" +) + +type User struct { + Id string `gorm:"primaryKey"` + // AccountID is a reference to Account that this object belongs + AccountID string `json:"-" gorm:"index"` + Role string + IsServiceUser bool + // NonDeletable indicates whether the service user can be deleted + NonDeletable bool + // ServiceUserName is only set if IsServiceUser is true + ServiceUserName string + // AutoGroups is a list of Group IDs to auto-assign to peers registered by this user + AutoGroups []string `gorm:"serializer:json"` + PATs map[string]*PersonalAccessToken `gorm:"-"` + PATsG []PersonalAccessToken `json:"-" gorm:"foreignKey:UserID;references:id;constraint:OnDelete:CASCADE;"` + // Blocked indicates whether the user is blocked. Blocked users can't use the system. + Blocked bool + // LastLogin is the last time the user logged in to IdP + LastLogin *time.Time + // CreatedAt records the time the user was created + CreatedAt time.Time + + // Issued of the user + Issued string `gorm:"default:api"` + + IntegrationReference integration_reference.IntegrationReference `gorm:"embedded;embeddedPrefix:integration_ref_"` +} + +func (l User) TableName() string { + return "users" +} + +type UserEvent struct { + db.ModelEvent[*User] +} diff --git a/internal/shared/db/event.go b/internal/shared/db/event.go new file mode 100644 index 0000000..f37dbc5 --- /dev/null +++ b/internal/shared/db/event.go @@ -0,0 +1,30 @@ +package db + +import ( + "context" + "management/internal/shared/hook" +) + +type Model interface { + TableName() string +} + +type ModelEvent[T Model] struct { + hook.Event + + Tx Transaction + Context context.Context + Model *T +} + +type ModelErrorEvent[T Model] struct { + Error error + ModelEvent[T] +} + +func (e *ModelEvent[T]) Tags() []string { + if e.Model == nil { + return nil + } + return []string{(*e.Model).TableName()} +}