diff --git a/pkg/login/social/connectors/org_role_mapper.go b/pkg/login/social/connectors/org_role_mapper.go new file mode 100644 index 000000000000..bb3d7974cb78 --- /dev/null +++ b/pkg/login/social/connectors/org_role_mapper.go @@ -0,0 +1,255 @@ +package connectors + +import ( + "context" + "fmt" + "strconv" + "strings" + + "github.com/grafana/grafana/pkg/infra/log" + "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/setting" +) + +const mapperMatchAllOrgID = -1 + +// OrgRoleMapper maps external orgs/groups to Grafana orgs and basic roles. +type OrgRoleMapper struct { + cfg *setting.Cfg + logger log.Logger + orgService org.Service +} + +// MappingConfiguration represents the mapping configuration from external orgs to Grafana orgs and roles. +// orgMapping: mapping from external orgs to Grafana orgs and roles +// strictRoleMapping: if true, the mapper ensures that the evaluated role from orgMapping or the directlyMappedRole is a valid role, otherwise it will return nil. +type MappingConfiguration struct { + orgMapping map[string]map[int64]org.RoleType + strictRoleMapping bool +} + +func ProvideOrgRoleMapper(cfg *setting.Cfg, orgService org.Service) *OrgRoleMapper { + return &OrgRoleMapper{ + cfg: cfg, + logger: log.New("orgrole.mapper"), + orgService: orgService, + } +} + +// MapOrgRoles maps the external orgs/groups to Grafana orgs and roles. It returns a map or orgID to role. +// +// mappingCfg: mapping configuration from external orgs to Grafana orgs and roles. Use `ParseOrgMappingSettings` to convert the raw setting to this format. +// +// externalOrgs: list of orgs/groups from the provider +// +// directlyMappedRole: role that is directly mapped to the user (ex: through `role_attribute_path`) +func (m *OrgRoleMapper) MapOrgRoles( + mappingCfg *MappingConfiguration, + externalOrgs []string, + directlyMappedRole org.RoleType, +) map[int64]org.RoleType { + if len(mappingCfg.orgMapping) == 0 { + // Org mapping is not configured + return m.getDefaultOrgMapping(mappingCfg.strictRoleMapping, directlyMappedRole) + } + + userOrgRoles := getMappedOrgRoles(externalOrgs, mappingCfg.orgMapping) + + if err := m.handleGlobalOrgMapping(userOrgRoles); err != nil { + // Cannot map global org roles, return nil (prevent resetting asignments) + return nil + } + + if len(userOrgRoles) == 0 { + return m.getDefaultOrgMapping(mappingCfg.strictRoleMapping, directlyMappedRole) + } + + if directlyMappedRole == "" { + m.logger.Debug("No direct role mapping found") + return userOrgRoles + } + + m.logger.Debug("Direct role mapping found", "role", directlyMappedRole) + + // Merge roles from org mapping `org_mapping` with role from direct mapping + for orgID, role := range userOrgRoles { + userOrgRoles[orgID] = getTopRole(directlyMappedRole, role) + } + + return userOrgRoles +} + +func (m *OrgRoleMapper) getDefaultOrgMapping(strictRoleMapping bool, directlyMappedRole org.RoleType) map[int64]org.RoleType { + if strictRoleMapping && !directlyMappedRole.IsValid() { + m.logger.Debug("Prevent default org role mapping, role attribute strict requested") + return nil + } + orgRoles := make(map[int64]org.RoleType, 0) + + orgID := int64(1) + if m.cfg.AutoAssignOrg && m.cfg.AutoAssignOrgId > 0 { + orgID = int64(m.cfg.AutoAssignOrgId) + } + + orgRoles[orgID] = directlyMappedRole + if !directlyMappedRole.IsValid() { + orgRoles[orgID] = org.RoleType(m.cfg.AutoAssignOrgRole) + } + + return orgRoles +} + +func (m *OrgRoleMapper) handleGlobalOrgMapping(orgRoles map[int64]org.RoleType) error { + // No global role mapping => return + globalRole, ok := orgRoles[mapperMatchAllOrgID] + if !ok { + return nil + } + + allOrgIDs, err := m.getAllOrgs() + if err != nil { + // Prevent resetting assignments + clear(orgRoles) + m.logger.Warn("error fetching all orgs, removing org mapping to prevent org sync") + return err + } + + // Remove the global role mapping + delete(orgRoles, mapperMatchAllOrgID) + + // Global mapping => for all orgs get top role mapping + for orgID := range allOrgIDs { + orgRoles[orgID] = getTopRole(orgRoles[orgID], globalRole) + } + + return nil +} + +// ParseOrgMappingSettings parses the `org_mapping` setting and returns an internal representation of the mapping. +// If the roleStrict is enabled, the mapping should contain a valid role for each org. +// FIXME: Consider introducing a struct to represent the org mapping settings +func (m *OrgRoleMapper) ParseOrgMappingSettings(ctx context.Context, mappings []string, roleStrict bool) *MappingConfiguration { + res := map[string]map[int64]org.RoleType{} + + for _, v := range mappings { + kv := strings.Split(v, ":") + if !isValidOrgMappingFormat(kv) { + m.logger.Error("Skipping org mapping due to invalid format.", "mapping", fmt.Sprintf("%v", v)) + if roleStrict { + // Return empty mapping if the mapping format is invalied and roleStrict is enabled + return &MappingConfiguration{orgMapping: map[string]map[int64]org.RoleType{}, strictRoleMapping: roleStrict} + } + continue + } + + orgID, err := m.getOrgIDForInternalMapping(ctx, kv[1]) + if err != nil { + m.logger.Warn("Could not fetch OrgID. Skipping.", "err", err, "mapping", fmt.Sprintf("%v", v), "org", kv[1]) + if roleStrict { + // Return empty mapping if at least one org name cannot be resolved when roleStrict is enabled + return &MappingConfiguration{orgMapping: map[string]map[int64]org.RoleType{}, strictRoleMapping: roleStrict} + } + continue + } + + if roleStrict && (len(kv) < 3 || !org.RoleType(kv[2]).IsValid()) { + // Return empty mapping if at least one org mapping is invalid (missing role, invalid role) + m.logger.Warn("Skipping org mapping due to missing or invalid role in mapping when roleStrict is enabled.", "mapping", fmt.Sprintf("%v", v)) + return &MappingConfiguration{orgMapping: map[string]map[int64]org.RoleType{}, strictRoleMapping: roleStrict} + } + + orga := kv[0] + if res[orga] == nil { + res[orga] = map[int64]org.RoleType{} + } + + res[orga][int64(orgID)] = getRoleForInternalOrgMapping(kv) + } + + return &MappingConfiguration{orgMapping: res, strictRoleMapping: roleStrict} +} + +func (m *OrgRoleMapper) getOrgIDForInternalMapping(ctx context.Context, orgIdCfg string) (int, error) { + if orgIdCfg == "*" { + return mapperMatchAllOrgID, nil + } + + orgID, err := strconv.Atoi(orgIdCfg) + if err != nil { + res, getErr := m.orgService.GetByName(ctx, &org.GetOrgByNameQuery{Name: orgIdCfg}) + + if getErr != nil { + // skip in case of error + m.logger.Warn("Could not fetch organization. Skipping.", "err", err, "org", orgIdCfg) + return 0, getErr + } + orgID = int(res.ID) + } + + return orgID, nil +} + +func (m *OrgRoleMapper) getAllOrgs() (map[int64]bool, error) { + allOrgIDs := map[int64]bool{} + allOrgs, err := m.orgService.Search(context.Background(), &org.SearchOrgsQuery{}) + if err != nil { + // In case of error, return no orgs + return nil, err + } + + for _, org := range allOrgs { + allOrgIDs[org.ID] = true + } + return allOrgIDs, nil +} + +func getRoleForInternalOrgMapping(kv []string) org.RoleType { + if len(kv) > 2 && org.RoleType(kv[2]).IsValid() { + return org.RoleType(kv[2]) + } + + return org.RoleViewer +} + +func isValidOrgMappingFormat(kv []string) bool { + return len(kv) > 1 && len(kv) < 4 +} + +func getMappedOrgRoles(externalOrgs []string, orgMapping map[string]map[int64]org.RoleType) map[int64]org.RoleType { + userOrgRoles := map[int64]org.RoleType{} + + if len(orgMapping) == 0 { + return nil + } + + if orgRoles, ok := orgMapping["*"]; ok { + for orgID, role := range orgRoles { + userOrgRoles[orgID] = role + } + } + + for _, org := range externalOrgs { + orgRoles, ok := orgMapping[org] + if !ok { + continue + } + + for orgID, role := range orgRoles { + userOrgRoles[orgID] = getTopRole(userOrgRoles[orgID], role) + } + } + + return userOrgRoles +} + +func getTopRole(currRole org.RoleType, otherRole org.RoleType) org.RoleType { + if currRole == "" { + return otherRole + } + + if currRole.Includes(otherRole) { + return currRole + } + + return otherRole +} diff --git a/pkg/login/social/connectors/org_role_mapper_test.go b/pkg/login/social/connectors/org_role_mapper_test.go new file mode 100644 index 000000000000..75aebe596be5 --- /dev/null +++ b/pkg/login/social/connectors/org_role_mapper_test.go @@ -0,0 +1,342 @@ +package connectors + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + + "github.com/grafana/grafana/pkg/services/org" + "github.com/grafana/grafana/pkg/services/org/orgtest" + "github.com/grafana/grafana/pkg/setting" +) + +func TestOrgRoleMapper_MapOrgRoles(t *testing.T) { + testCases := []struct { + name string + externalOrgs []string + orgMappingSettings []string + directlyMappedRole org.RoleType + strictRoleMapping bool + getAllOrgsError error + expected map[int64]org.RoleType + }{ + { + name: "should return the default mapping when no org mapping settings are provided and directly mapped role is not set", + externalOrgs: []string{}, + orgMappingSettings: []string{}, + directlyMappedRole: "", + expected: map[int64]org.RoleType{2: org.RoleViewer}, + }, + { + name: "should return the default mapping when no org mapping settings are provided and direcly mapped role is set", + externalOrgs: []string{}, + orgMappingSettings: []string{}, + directlyMappedRole: org.RoleEditor, + expected: map[int64]org.RoleType{2: org.RoleEditor}, + }, + { + name: "should return the default mapping when org mapping doesn't match any of the external orgs and no directly mapped role is provided", + externalOrgs: []string{"First"}, + orgMappingSettings: []string{"Second:1:Editor"}, + directlyMappedRole: "", + expected: map[int64]org.RoleType{2: org.RoleViewer}, + }, + { + name: "should return Viewer role for the org if the specified role is invalid", + externalOrgs: []string{"First"}, + orgMappingSettings: []string{"First:1:SuperEditor"}, + directlyMappedRole: "", + expected: map[int64]org.RoleType{1: org.RoleViewer}, + }, + { + name: "should return nil when no org mapping settings are provided and directly mapped role is not set and strict role mapping is enabled", + externalOrgs: []string{}, + orgMappingSettings: []string{}, + directlyMappedRole: "", + strictRoleMapping: true, + expected: nil, + }, + { + name: "should return nil when org mapping doesn't match any of the external orgs and no directly mapped role is provided and strict role mapping is enabled", + externalOrgs: []string{"First"}, + orgMappingSettings: []string{"Second:1:Editor"}, + directlyMappedRole: "", + strictRoleMapping: true, + expected: nil, + }, + // In this case the parsed org mapping will be empty because the role is invalid + { + name: "should return nil for the org if the specified role is invalid and strict role mapping is enabled", + externalOrgs: []string{"First"}, + orgMappingSettings: []string{"First:1:SuperEditor"}, + directlyMappedRole: "", + strictRoleMapping: true, + expected: nil, + }, + { + name: "should map the directly mapped role to default org if the org mapping is invalid and strict role mapping is enabled", + externalOrgs: []string{"First"}, + orgMappingSettings: []string{"First:1:SuperEditor"}, + directlyMappedRole: "Editor", + strictRoleMapping: true, + expected: map[int64]org.RoleType{2: org.RoleEditor}, + }, + { + name: "should return nil if the org mapping contains at least one invalid setting and directly mapped role is empty and strict role mapping is enabled", + externalOrgs: []string{"First"}, + orgMappingSettings: []string{"First:1:SuperEditor", "First:1:Admin"}, + directlyMappedRole: "", + strictRoleMapping: true, + expected: nil, + }, + { + name: "should map the higher role if directly mapped role is lower than the role found in the org mapping", + externalOrgs: []string{"First"}, + orgMappingSettings: []string{"First:1:Editor"}, + directlyMappedRole: org.RoleViewer, + expected: map[int64]org.RoleType{1: org.RoleEditor}, + }, + { + name: "should map the directly mapped role if it is higher than the role found in the org mapping", + externalOrgs: []string{"First"}, + orgMappingSettings: []string{"First:1:Viewer"}, + directlyMappedRole: org.RoleEditor, + expected: map[int64]org.RoleType{1: org.RoleEditor}, + }, + { + name: "should map to multiple organizations and set the directly mapped role for those if it is higher than the role found in the org mapping", + externalOrgs: []string{"First", "Second"}, + orgMappingSettings: []string{"First:1:Viewer", "Second:2:Viewer"}, + directlyMappedRole: org.RoleEditor, + expected: map[int64]org.RoleType{1: org.RoleEditor, 2: org.RoleEditor}, + }, + { + name: "should map to multiple organizations and set the directly mapped role for those if the directly mapped role is not set", + externalOrgs: []string{"First", "Second"}, + orgMappingSettings: []string{"First:1:Viewer", "Second:2:Viewer"}, + directlyMappedRole: "", + expected: map[int64]org.RoleType{1: org.RoleViewer, 2: org.RoleViewer}, + }, + { + name: "should map to all of the organizations if global org mapping is provided and the directly mapped role is set", + externalOrgs: []string{"First"}, + orgMappingSettings: []string{"First:*:Editor"}, + directlyMappedRole: org.RoleViewer, + expected: map[int64]org.RoleType{1: org.RoleEditor, 2: org.RoleEditor, 3: org.RoleEditor}, + }, + { + name: "should map to all of the organizations if global org mapping is provided and the directly mapped role is not set", + externalOrgs: []string{"First"}, + orgMappingSettings: []string{"First:*:Editor"}, + directlyMappedRole: "", + expected: map[int64]org.RoleType{1: org.RoleEditor, 2: org.RoleEditor, 3: org.RoleEditor}, + }, + { + name: "should map to all of the organizations if global org mapping is provided and the directly mapped role is higher than the role found in the org mappings", + externalOrgs: []string{"First"}, + orgMappingSettings: []string{"First:*:Viewer"}, + directlyMappedRole: org.RoleEditor, + expected: map[int64]org.RoleType{1: org.RoleEditor, 2: org.RoleEditor, 3: org.RoleEditor}, + }, + { + name: "should map correctly when fallback org mapping is provided and fallback has a higher role", + externalOrgs: []string{"First", "Second", "Third"}, + orgMappingSettings: []string{"First:1:Viewer", "*:1:Editor", "Second:2:Viewer"}, + directlyMappedRole: "", + expected: map[int64]org.RoleType{1: org.RoleEditor, 2: org.RoleViewer}, + }, + { + name: "should map correctly when fallback org mapping is provided and fallback has a lower role", + externalOrgs: []string{"First", "Second", "Third"}, + orgMappingSettings: []string{"First:1:Editor", "*:1:Viewer", "Second:2:Viewer"}, + directlyMappedRole: "", + expected: map[int64]org.RoleType{1: org.RoleEditor, 2: org.RoleViewer}, + }, + { + name: "should map correctly and respect wildcard precedence when global org mapping is provided", + externalOrgs: []string{"First", "Second"}, + orgMappingSettings: []string{"*:1:Editor", "First:1:Viewer", "Second:2:Viewer"}, + directlyMappedRole: "", + expected: map[int64]org.RoleType{1: org.RoleEditor, 2: org.RoleViewer}, + }, + { + name: "should map directly mapped role when global org mapping is provided and the directly mapped role is higher than the role found in the org mappings", + externalOrgs: []string{"First", "Second", "Third"}, + orgMappingSettings: []string{"First:1:Viewer", "*:1:Editor", "Second:2:Viewer"}, + directlyMappedRole: org.RoleAdmin, + expected: map[int64]org.RoleType{1: org.RoleAdmin, 2: org.RoleAdmin}, + }, + { + name: "should map correctly and respect the mapping precedence when multiple org mappings are provided for the same org", + externalOrgs: []string{"First"}, + orgMappingSettings: []string{"First:1:Editor", "First:1:Viewer"}, + directlyMappedRole: "", + expected: map[int64]org.RoleType{1: org.RoleViewer}, + }, + { + name: "should map to all organizations when global org mapping is provided and the directly mapped role is higher than the role found in the org mappings", + externalOrgs: []string{"First"}, + orgMappingSettings: []string{"First:*:Editor"}, + directlyMappedRole: org.RoleAdmin, + expected: map[int64]org.RoleType{1: org.RoleAdmin, 2: org.RoleAdmin, 3: org.RoleAdmin}, + }, + { + name: "should skip map to all organizations if org service returns an error", + externalOrgs: []string{"First"}, + orgMappingSettings: []string{"First:*:Editor"}, + getAllOrgsError: assert.AnError, + directlyMappedRole: org.RoleAdmin, + expected: nil, + }, + } + orgService := orgtest.NewOrgServiceFake() + cfg := setting.NewCfg() + cfg.AutoAssignOrg = true + cfg.AutoAssignOrgId = 2 + cfg.AutoAssignOrgRole = string(org.RoleViewer) + mapper := ProvideOrgRoleMapper(cfg, orgService) + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + if tc.getAllOrgsError != nil { + orgService.ExpectedError = tc.getAllOrgsError + } else { + orgService.ExpectedOrgs = []*org.OrgDTO{ + {Name: "First", ID: 1}, + {Name: "Second", ID: 2}, + {Name: "Third", ID: 3}, + } + } + mappingCfg := mapper.ParseOrgMappingSettings(context.Background(), tc.orgMappingSettings, tc.strictRoleMapping) + actual := mapper.MapOrgRoles(mappingCfg, tc.externalOrgs, tc.directlyMappedRole) + + assert.EqualValues(t, tc.expected, actual) + }) + } +} + +func TestOrgRoleMapper_ParseOrgMappingSettings(t *testing.T) { + testCases := []struct { + name string + rawMapping []string + roleStrict bool + setupMock func(*orgtest.MockService) + expected *MappingConfiguration + }{ + { + name: "should return empty mapping when no org mapping settings are provided", + rawMapping: []string{}, + expected: &MappingConfiguration{ + orgMapping: map[string]map[int64]org.RoleType{}, + strictRoleMapping: false, + }, + }, + { + name: "should return empty mapping when role is invalid and role strict is enabled", + rawMapping: []string{"Second:1:SuperEditor"}, + roleStrict: true, + expected: &MappingConfiguration{ + orgMapping: map[string]map[int64]org.RoleType{}, + strictRoleMapping: true, + }, + }, + { + name: "should return default mapping when role is invalid and strict role mapping is disabled", + rawMapping: []string{"Second:1:SuperEditor"}, + roleStrict: false, + expected: &MappingConfiguration{ + orgMapping: map[string]map[int64]org.RoleType{"Second": {1: org.RoleViewer}}, + strictRoleMapping: false, + }, + }, + { + name: "should return empty mapping when org mapping doesn't contain any role and strict role mapping is enabled", + rawMapping: []string{"Second:1"}, + roleStrict: true, + expected: &MappingConfiguration{ + orgMapping: map[string]map[int64]org.RoleType{}, + strictRoleMapping: true, + }, + }, + { + name: "should return default mapping when org mapping doesn't contain any role and strict is disabled", + rawMapping: []string{"Second:1"}, + expected: &MappingConfiguration{ + orgMapping: map[string]map[int64]org.RoleType{"Second": {1: org.RoleViewer}}, + strictRoleMapping: false, + }, + }, + { + name: "should return empty mapping when org mapping is nil", + rawMapping: nil, + expected: &MappingConfiguration{ + orgMapping: map[string]map[int64]org.RoleType{}, + strictRoleMapping: false, + }, + }, + { + name: "should return empty mapping when the org mapping format is invalid and strict role mapping is enabled", + rawMapping: []string{"External:Org1:First:Organization:Editor"}, + roleStrict: true, + expected: &MappingConfiguration{ + orgMapping: map[string]map[int64]org.RoleType{}, + strictRoleMapping: true, + }, + }, + { + name: "should return only the valid mappings from the raw mappings when strict role mapping is disabled", + rawMapping: []string{"External:Org1:First:Organization:Editor", "Second:1:Editor"}, + roleStrict: false, + expected: &MappingConfiguration{ + orgMapping: map[string]map[int64]org.RoleType{"Second": {1: org.RoleEditor}}, + strictRoleMapping: false, + }, + }, + { + name: "should return empty mapping if at least one org was not found or the resolution failed and strict role mapping is enabled", + rawMapping: []string{"ExternalOrg1:First:Editor", "ExternalOrg1:NonExistent:Viewer"}, + roleStrict: true, + setupMock: func(orgService *orgtest.MockService) { + orgService.On("GetByName", mock.Anything, mock.MatchedBy(func(query *org.GetOrgByNameQuery) bool { + return query.Name == "First" + })).Return(&org.Org{ID: 1}, nil) + orgService.On("GetByName", mock.Anything, mock.Anything).Return(nil, assert.AnError) + }, + expected: &MappingConfiguration{ + orgMapping: map[string]map[int64]org.RoleType{}, + strictRoleMapping: true, + }, + }, + { + name: "should skip org mapping if org was not found or the resolution fails and strict role mapping is disabled", + rawMapping: []string{"ExternalOrg1:First:Editor", "ExternalOrg1:NonExistent:Viewer"}, + roleStrict: false, + setupMock: func(orgService *orgtest.MockService) { + orgService.On("GetByName", mock.Anything, mock.MatchedBy(func(query *org.GetOrgByNameQuery) bool { + return query.Name == "First" + })).Return(&org.Org{ID: 1}, nil) + orgService.On("GetByName", mock.Anything, mock.Anything).Return(nil, assert.AnError) + }, + expected: &MappingConfiguration{ + orgMapping: map[string]map[int64]org.RoleType{"ExternalOrg1": {1: org.RoleEditor}}, + strictRoleMapping: false, + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + cfg := setting.NewCfg() + orgService := orgtest.NewMockService(t) + if tc.setupMock != nil { + tc.setupMock(orgService) + } + mapper := ProvideOrgRoleMapper(cfg, orgService) + + actual := mapper.ParseOrgMappingSettings(context.Background(), tc.rawMapping, tc.roleStrict) + + assert.EqualValues(t, tc.expected, actual) + }) + } +} diff --git a/pkg/services/org/org.go b/pkg/services/org/org.go index b41c7a80a6fd..cb531aea33e7 100644 --- a/pkg/services/org/org.go +++ b/pkg/services/org/org.go @@ -4,6 +4,7 @@ import ( "context" ) +//go:generate mockery --name Service --structname MockService --outpkg orgtest --filename mock.go --output ./orgtest/ type Service interface { GetIDForNewUser(context.Context, GetOrgIDForNewUserCommand) (int64, error) InsertOrgUser(context.Context, *OrgUser) (int64, error) diff --git a/pkg/services/org/orgtest/mock.go b/pkg/services/org/orgtest/mock.go new file mode 100644 index 000000000000..7dc2b16d34d6 --- /dev/null +++ b/pkg/services/org/orgtest/mock.go @@ -0,0 +1,454 @@ +// Code generated by mockery v2.42.1. DO NOT EDIT. + +package orgtest + +import ( + context "context" + + org "github.com/grafana/grafana/pkg/services/org" + mock "github.com/stretchr/testify/mock" +) + +// MockService is an autogenerated mock type for the Service type +type MockService struct { + mock.Mock +} + +// AddOrgUser provides a mock function with given fields: _a0, _a1 +func (_m *MockService) AddOrgUser(_a0 context.Context, _a1 *org.AddOrgUserCommand) error { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for AddOrgUser") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *org.AddOrgUserCommand) error); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// CreateWithMember provides a mock function with given fields: _a0, _a1 +func (_m *MockService) CreateWithMember(_a0 context.Context, _a1 *org.CreateOrgCommand) (*org.Org, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for CreateWithMember") + } + + var r0 *org.Org + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *org.CreateOrgCommand) (*org.Org, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *org.CreateOrgCommand) *org.Org); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*org.Org) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *org.CreateOrgCommand) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Delete provides a mock function with given fields: _a0, _a1 +func (_m *MockService) Delete(_a0 context.Context, _a1 *org.DeleteOrgCommand) error { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for Delete") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *org.DeleteOrgCommand) error); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteUserFromAll provides a mock function with given fields: _a0, _a1 +func (_m *MockService) DeleteUserFromAll(_a0 context.Context, _a1 int64) error { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for DeleteUserFromAll") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// GetByID provides a mock function with given fields: _a0, _a1 +func (_m *MockService) GetByID(_a0 context.Context, _a1 *org.GetOrgByIDQuery) (*org.Org, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for GetByID") + } + + var r0 *org.Org + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *org.GetOrgByIDQuery) (*org.Org, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *org.GetOrgByIDQuery) *org.Org); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*org.Org) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *org.GetOrgByIDQuery) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetByName provides a mock function with given fields: _a0, _a1 +func (_m *MockService) GetByName(_a0 context.Context, _a1 *org.GetOrgByNameQuery) (*org.Org, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for GetByName") + } + + var r0 *org.Org + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *org.GetOrgByNameQuery) (*org.Org, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *org.GetOrgByNameQuery) *org.Org); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*org.Org) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *org.GetOrgByNameQuery) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetIDForNewUser provides a mock function with given fields: _a0, _a1 +func (_m *MockService) GetIDForNewUser(_a0 context.Context, _a1 org.GetOrgIDForNewUserCommand) (int64, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for GetIDForNewUser") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, org.GetOrgIDForNewUserCommand) (int64, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, org.GetOrgIDForNewUserCommand) int64); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, org.GetOrgIDForNewUserCommand) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetOrCreate provides a mock function with given fields: _a0, _a1 +func (_m *MockService) GetOrCreate(_a0 context.Context, _a1 string) (int64, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for GetOrCreate") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (int64, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, string) int64); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetOrgUsers provides a mock function with given fields: _a0, _a1 +func (_m *MockService) GetOrgUsers(_a0 context.Context, _a1 *org.GetOrgUsersQuery) ([]*org.OrgUserDTO, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for GetOrgUsers") + } + + var r0 []*org.OrgUserDTO + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *org.GetOrgUsersQuery) ([]*org.OrgUserDTO, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *org.GetOrgUsersQuery) []*org.OrgUserDTO); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*org.OrgUserDTO) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *org.GetOrgUsersQuery) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetUserOrgList provides a mock function with given fields: _a0, _a1 +func (_m *MockService) GetUserOrgList(_a0 context.Context, _a1 *org.GetUserOrgListQuery) ([]*org.UserOrgDTO, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for GetUserOrgList") + } + + var r0 []*org.UserOrgDTO + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *org.GetUserOrgListQuery) ([]*org.UserOrgDTO, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *org.GetUserOrgListQuery) []*org.UserOrgDTO); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*org.UserOrgDTO) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *org.GetUserOrgListQuery) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// InsertOrgUser provides a mock function with given fields: _a0, _a1 +func (_m *MockService) InsertOrgUser(_a0 context.Context, _a1 *org.OrgUser) (int64, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for InsertOrgUser") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *org.OrgUser) (int64, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *org.OrgUser) int64); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, *org.OrgUser) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RegisterDelete provides a mock function with given fields: query +func (_m *MockService) RegisterDelete(query string) { + _m.Called(query) +} + +// RemoveOrgUser provides a mock function with given fields: _a0, _a1 +func (_m *MockService) RemoveOrgUser(_a0 context.Context, _a1 *org.RemoveOrgUserCommand) error { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for RemoveOrgUser") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *org.RemoveOrgUserCommand) error); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Search provides a mock function with given fields: _a0, _a1 +func (_m *MockService) Search(_a0 context.Context, _a1 *org.SearchOrgsQuery) ([]*org.OrgDTO, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for Search") + } + + var r0 []*org.OrgDTO + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *org.SearchOrgsQuery) ([]*org.OrgDTO, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *org.SearchOrgsQuery) []*org.OrgDTO); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*org.OrgDTO) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *org.SearchOrgsQuery) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// SearchOrgUsers provides a mock function with given fields: _a0, _a1 +func (_m *MockService) SearchOrgUsers(_a0 context.Context, _a1 *org.SearchOrgUsersQuery) (*org.SearchOrgUsersQueryResult, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for SearchOrgUsers") + } + + var r0 *org.SearchOrgUsersQueryResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *org.SearchOrgUsersQuery) (*org.SearchOrgUsersQueryResult, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, *org.SearchOrgUsersQuery) *org.SearchOrgUsersQueryResult); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*org.SearchOrgUsersQueryResult) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *org.SearchOrgUsersQuery) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// UpdateAddress provides a mock function with given fields: _a0, _a1 +func (_m *MockService) UpdateAddress(_a0 context.Context, _a1 *org.UpdateOrgAddressCommand) error { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for UpdateAddress") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *org.UpdateOrgAddressCommand) error); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// UpdateOrg provides a mock function with given fields: _a0, _a1 +func (_m *MockService) UpdateOrg(_a0 context.Context, _a1 *org.UpdateOrgCommand) error { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for UpdateOrg") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *org.UpdateOrgCommand) error); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// UpdateOrgUser provides a mock function with given fields: _a0, _a1 +func (_m *MockService) UpdateOrgUser(_a0 context.Context, _a1 *org.UpdateOrgUserCommand) error { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for UpdateOrgUser") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *org.UpdateOrgUserCommand) error); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// NewMockService creates a new instance of MockService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockService(t interface { + mock.TestingT + Cleanup(func()) +}) *MockService { + mock := &MockService{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +}