diff --git a/server/api/org.go b/server/api/org.go index b23bc6d55bd..aaa54fe939e 100644 --- a/server/api/org.go +++ b/server/api/org.go @@ -127,15 +127,27 @@ func LookupOrg(c *gin.Context) { orgFullName := strings.TrimLeft(c.Param("org_full_name"), "/") - org, err := _store.OrgFindByName(orgFullName, user.ForgeID) - if err != nil { - handleDBError(c, err) - return + var org *model.Org + if user == nil { + org, err = _store.OrgLookup(orgFullName) + if err != nil { + if err.Error() == "found more than one org with this name" { + _ = c.AbortWithError(http.StatusBadRequest, err) + return + } + handleDBError(c, err) + return + } + } else { + org, err = _store.OrgFindByName(orgFullName, user.ForgeID) + if err != nil { + handleDBError(c, err) + return + } } // don't leak private org infos if org.Private { - user := session.User(c) if user == nil { c.AbortWithStatus(http.StatusNotFound) return diff --git a/server/store/datastore/org.go b/server/store/datastore/org.go index b6d9f410d9a..997a10b2982 100644 --- a/server/store/datastore/org.go +++ b/server/store/datastore/org.go @@ -21,6 +21,7 @@ import ( "xorm.io/xorm" "go.woodpecker-ci.org/woodpecker/v3/server/model" + "go.woodpecker-ci.org/woodpecker/v3/server/store/types" ) func (s storage) OrgCreate(org *model.Org) error { @@ -82,6 +83,22 @@ func (s storage) orgFindByName(sess *xorm.Session, name string, forgeID int64) ( return org, wrapGet(sess.Where("LOWER(name) = ?", strings.ToLower(name)).And("forge_id = ?", forgeID).Get(org)) } +func (s storage) OrgLookup(name string) (*model.Org, error) { + var orgs []*model.Org + // we limit to 2 orgs, if we have >= 2 we return an error anyways. + err := s.engine.Where("LOWER(name) = ?", strings.ToLower(name)).Limit(2).Find(&orgs) //nolint:mnd + if err != nil { + return nil, err + } + if len(orgs) < 1 { + return nil, types.ErrRecordNotExist + } + if len(orgs) > 1 { + return nil, fmt.Errorf("found more than one org with this name") + } + return orgs[0], nil +} + func (s storage) OrgRepoList(org *model.Org, p *model.ListOptions) ([]*model.Repo, error) { var repos []*model.Repo return repos, s.paginate(p).OrderBy("id").Where("org_id = ?", org.ID).Find(&repos) diff --git a/server/store/mocks/mock_Store.go b/server/store/mocks/mock_Store.go index 3344bbb874c..51acf2a34f1 100644 --- a/server/store/mocks/mock_Store.go +++ b/server/store/mocks/mock_Store.go @@ -3816,6 +3816,68 @@ func (_c *MockStore_OrgList_Call) RunAndReturn(run func(listOptions *model.ListO return _c } +// OrgLookup provides a mock function for the type MockStore +func (_mock *MockStore) OrgLookup(s string) (*model.Org, error) { + ret := _mock.Called(s) + + if len(ret) == 0 { + panic("no return value specified for OrgLookup") + } + + var r0 *model.Org + var r1 error + if returnFunc, ok := ret.Get(0).(func(string) (*model.Org, error)); ok { + return returnFunc(s) + } + if returnFunc, ok := ret.Get(0).(func(string) *model.Org); ok { + r0 = returnFunc(s) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.Org) + } + } + if returnFunc, ok := ret.Get(1).(func(string) error); ok { + r1 = returnFunc(s) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// MockStore_OrgLookup_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OrgLookup' +type MockStore_OrgLookup_Call struct { + *mock.Call +} + +// OrgLookup is a helper method to define mock.On call +// - s string +func (_e *MockStore_Expecter) OrgLookup(s interface{}) *MockStore_OrgLookup_Call { + return &MockStore_OrgLookup_Call{Call: _e.mock.On("OrgLookup", s)} +} + +func (_c *MockStore_OrgLookup_Call) Run(run func(s string)) *MockStore_OrgLookup_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 string + if args[0] != nil { + arg0 = args[0].(string) + } + run( + arg0, + ) + }) + return _c +} + +func (_c *MockStore_OrgLookup_Call) Return(org *model.Org, err error) *MockStore_OrgLookup_Call { + _c.Call.Return(org, err) + return _c +} + +func (_c *MockStore_OrgLookup_Call) RunAndReturn(run func(s string) (*model.Org, error)) *MockStore_OrgLookup_Call { + _c.Call.Return(run) + return _c +} + // OrgRegistryFind provides a mock function for the type MockStore func (_mock *MockStore) OrgRegistryFind(n int64, s string) (*model.Registry, error) { ret := _mock.Called(n, s) diff --git a/server/store/store.go b/server/store/store.go index 34efb8249ee..1174fb711c4 100644 --- a/server/store/store.go +++ b/server/store/store.go @@ -195,6 +195,7 @@ type Store interface { OrgCreate(*model.Org) error OrgGet(int64) (*model.Org, error) OrgFindByName(string, int64) (*model.Org, error) + OrgLookup(string) (*model.Org, error) OrgUpdate(*model.Org) error OrgDelete(int64) error OrgList(*model.ListOptions) ([]*model.Org, error)