mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-02-23 06:36:17 +00:00
Merge branch 'origin/main' into 'next-release/main'
This commit is contained in:
commit
0d64c2c1d4
13 changed files with 64 additions and 56 deletions
|
@ -15,8 +15,8 @@
|
|||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.4
|
||||
// protoc v5.29.3
|
||||
// protoc-gen-go v1.36.5
|
||||
// protoc v5.29.2
|
||||
// source: woodpecker.proto
|
||||
|
||||
package proto
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc v5.29.3
|
||||
// - protoc v5.29.2
|
||||
// source: woodpecker.proto
|
||||
|
||||
package proto
|
||||
|
|
|
@ -110,7 +110,7 @@ func HandleAuth(c *gin.Context) {
|
|||
|
||||
_forge, err := server.Config.Services.Manager.ForgeByID(forgeID)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("Cannot get forge by id %d", forgeID)
|
||||
log.Error().Err(err).Msgf("cannot get forge by id %d", forgeID)
|
||||
c.Redirect(http.StatusSeeOther, server.Config.Server.RootPath+"/login?error=internal_error")
|
||||
return
|
||||
}
|
||||
|
@ -183,21 +183,25 @@ func HandleAuth(c *gin.Context) {
|
|||
// create or set the user's organization if it isn't linked yet
|
||||
if user.OrgID == 0 {
|
||||
// check if an org with the same name exists already and assign it to the user if it does
|
||||
if org, err := _store.OrgFindByName(user.Login); err == nil && org != nil {
|
||||
org.IsUser = true
|
||||
user.OrgID = org.ID
|
||||
|
||||
if err := _store.OrgUpdate(org); err != nil {
|
||||
log.Error().Err(err).Msgf("on user creation, could not mark org as user")
|
||||
}
|
||||
}
|
||||
org, err := _store.OrgFindByName(user.Login, forgeID)
|
||||
if err != nil && !errors.Is(err, types.RecordNotExist) {
|
||||
log.Error().Err(err).Msgf("cannot get org %s", user.Login)
|
||||
log.Error().Err(err).Msgf("cannot get org for user %s", user.Login)
|
||||
c.Redirect(http.StatusSeeOther, server.Config.Server.RootPath+"/login?error=internal_error")
|
||||
return
|
||||
}
|
||||
|
||||
if user.OrgID == 0 {
|
||||
// if an org with the same name exists => assign org to the user
|
||||
if err == nil && org != nil {
|
||||
org.IsUser = true
|
||||
user.OrgID = org.ID
|
||||
|
||||
if err := _store.OrgUpdate(org); err != nil {
|
||||
log.Error().Err(err).Msgf("cannot assign user %s to existing org %d", user.Login, org.ID)
|
||||
}
|
||||
}
|
||||
|
||||
// if still no org with the same name exists => create a new org
|
||||
if user.OrgID == 0 || errors.Is(err, types.RecordNotExist) {
|
||||
org := &model.Org{
|
||||
Name: user.Login,
|
||||
IsUser: true,
|
||||
|
@ -205,7 +209,7 @@ func HandleAuth(c *gin.Context) {
|
|||
ForgeID: user.ForgeID,
|
||||
}
|
||||
if err := _store.OrgCreate(org); err != nil {
|
||||
log.Error().Err(err).Msgf("on user creation, could not create org for user")
|
||||
log.Error().Err(err).Msgf("cannot create org for user %s", user.Login)
|
||||
}
|
||||
user.OrgID = org.ID
|
||||
}
|
||||
|
@ -213,14 +217,14 @@ func HandleAuth(c *gin.Context) {
|
|||
// update org name if necessary
|
||||
org, err := _store.OrgGet(user.OrgID)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("cannot get org %s", user.Login)
|
||||
log.Error().Err(err).Msgf("cannot get org %d for user %s", user.OrgID, user.Login)
|
||||
c.Redirect(http.StatusSeeOther, server.Config.Server.RootPath+"/login?error=internal_error")
|
||||
return
|
||||
}
|
||||
if org != nil && org.Name != user.Login {
|
||||
org.Name = user.Login
|
||||
if err := _store.OrgUpdate(org); err != nil {
|
||||
log.Error().Err(err).Msgf("on user creation, could not mark org as user")
|
||||
log.Error().Err(err).Msgf("cannot update org %d name to user name %s", org.ID, user.Login)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -236,7 +240,7 @@ func HandleAuth(c *gin.Context) {
|
|||
user.Admin = user.Admin || server.Config.Permissions.Admins.IsAdmin(userFromForge)
|
||||
|
||||
if err := _store.UpdateUser(user); err != nil {
|
||||
log.Error().Err(err).Msgf("cannot update %s", user.Login)
|
||||
log.Error().Err(err).Msgf("cannot update user %s", user.Login)
|
||||
c.Redirect(http.StatusSeeOther, server.Config.Server.RootPath+"/login?error=internal_error")
|
||||
return
|
||||
}
|
||||
|
@ -246,14 +250,14 @@ func HandleAuth(c *gin.Context) {
|
|||
_token.Set("user-id", strconv.FormatInt(user.ID, 10))
|
||||
tokenString, err := _token.SignExpires(user.Hash, exp)
|
||||
if err != nil {
|
||||
log.Error().Msgf("cannot create token for %s", user.Login)
|
||||
log.Error().Msgf("cannot create token for user %s", user.Login)
|
||||
c.Redirect(http.StatusSeeOther, server.Config.Server.RootPath+"/login?error=internal_error")
|
||||
return
|
||||
}
|
||||
|
||||
err = updateRepoPermissions(c, user, _store, _forge)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msgf("cannot update repo permissions for %s", user.Login)
|
||||
log.Error().Err(err).Msgf("cannot update repo permissions for user %s", user.Login)
|
||||
c.Redirect(http.StatusSeeOther, server.Config.Server.RootPath+"/login?error=internal_error")
|
||||
return
|
||||
}
|
||||
|
@ -279,7 +283,7 @@ func updateRepoPermissions(c *gin.Context, user *model.User, _store store.Store,
|
|||
continue
|
||||
}
|
||||
|
||||
log.Debug().Msgf("synced user permission for %s %s", user.Login, dbRepo.FullName)
|
||||
log.Debug().Msgf("synced user permission for user %s and repo %s", user.Login, dbRepo.FullName)
|
||||
perm := forgeRepo.Perm
|
||||
perm.Repo = dbRepo
|
||||
perm.RepoID = dbRepo.ID
|
||||
|
|
|
@ -160,7 +160,7 @@ func TestHandleAuth(t *testing.T) {
|
|||
_forge.On("Login", mock.Anything, mock.Anything).Return(user, "", nil)
|
||||
_store.On("GetUserRemoteID", user.ForgeRemoteID, user.Login).Return(nil, types.RecordNotExist)
|
||||
_store.On("CreateUser", mock.Anything).Return(nil)
|
||||
_store.On("OrgFindByName", user.Login).Return(nil, nil)
|
||||
_store.On("OrgFindByName", user.Login, user.ForgeID).Return(nil, nil)
|
||||
_store.On("OrgCreate", mock.Anything).Return(nil)
|
||||
_store.On("UpdateUser", mock.Anything).Return(nil)
|
||||
_forge.On("Repos", mock.Anything, mock.Anything).Return(nil, nil)
|
||||
|
@ -264,7 +264,7 @@ func TestHandleAuth(t *testing.T) {
|
|||
assert.Equal(t, "/login?error=org_access_denied", c.Writer.Header().Get("Location"))
|
||||
})
|
||||
|
||||
t.Run("User org should be created if it does not exists", func(t *testing.T) {
|
||||
t.Run("should create an user org if it does not exists", func(t *testing.T) {
|
||||
_manager := mocks_services.NewManager(t)
|
||||
_forge := mocks_forge.NewForge(t)
|
||||
_store := mocks_store.NewStore(t)
|
||||
|
@ -286,7 +286,7 @@ func TestHandleAuth(t *testing.T) {
|
|||
_manager.On("ForgeByID", int64(1)).Return(_forge, nil)
|
||||
_forge.On("Login", mock.Anything, mock.Anything).Return(user, "", nil)
|
||||
_store.On("GetUserRemoteID", user.ForgeRemoteID, user.Login).Return(user, nil)
|
||||
_store.On("OrgFindByName", user.Login).Return(nil, types.RecordNotExist)
|
||||
_store.On("OrgFindByName", user.Login, user.ForgeID).Return(nil, types.RecordNotExist)
|
||||
_store.On("OrgCreate", mock.Anything).Return(nil)
|
||||
_store.On("UpdateUser", mock.Anything).Return(nil)
|
||||
_forge.On("Repos", mock.Anything, mock.Anything).Return(nil, nil)
|
||||
|
@ -298,7 +298,7 @@ func TestHandleAuth(t *testing.T) {
|
|||
assert.NotEmpty(t, c.Writer.Header().Get("Set-Cookie"))
|
||||
})
|
||||
|
||||
t.Run("User org should be linked if it has the same name as the user", func(t *testing.T) {
|
||||
t.Run("should link an user org if it has the same name as the user", func(t *testing.T) {
|
||||
_manager := mocks_services.NewManager(t)
|
||||
_forge := mocks_forge.NewForge(t)
|
||||
_store := mocks_store.NewStore(t)
|
||||
|
@ -320,7 +320,7 @@ func TestHandleAuth(t *testing.T) {
|
|||
_manager.On("ForgeByID", int64(1)).Return(_forge, nil)
|
||||
_forge.On("Login", mock.Anything, mock.Anything).Return(user, "", nil)
|
||||
_store.On("GetUserRemoteID", user.ForgeRemoteID, user.Login).Return(user, nil)
|
||||
_store.On("OrgFindByName", user.Login).Return(org, nil)
|
||||
_store.On("OrgFindByName", user.Login, user.ForgeID).Return(org, nil)
|
||||
_store.On("OrgUpdate", mock.Anything).Return(nil)
|
||||
_store.On("UpdateUser", mock.Anything).Return(nil)
|
||||
_forge.On("Repos", mock.Anything, mock.Anything).Return(nil, nil)
|
||||
|
@ -332,7 +332,7 @@ func TestHandleAuth(t *testing.T) {
|
|||
assert.NotEmpty(t, c.Writer.Header().Get("Set-Cookie"))
|
||||
})
|
||||
|
||||
t.Run("User org should be updated if the user name was changed", func(t *testing.T) {
|
||||
t.Run("should update an user org if the user name was changed", func(t *testing.T) {
|
||||
_manager := mocks_services.NewManager(t)
|
||||
_forge := mocks_forge.NewForge(t)
|
||||
_store := mocks_store.NewStore(t)
|
||||
|
|
|
@ -127,7 +127,7 @@ func LookupOrg(c *gin.Context) {
|
|||
|
||||
orgFullName := strings.TrimLeft(c.Param("org_full_name"), "/")
|
||||
|
||||
org, err := _store.OrgFindByName(orgFullName)
|
||||
org, err := _store.OrgFindByName(orgFullName, user.ForgeID)
|
||||
if err != nil {
|
||||
handleDBError(c, err)
|
||||
return
|
||||
|
|
|
@ -120,8 +120,7 @@ func PostRepo(c *gin.Context) {
|
|||
|
||||
// find org of repo
|
||||
var org *model.Org
|
||||
// TODO: find org by name and forge id
|
||||
org, err = _store.OrgFindByName(repo.Owner)
|
||||
org, err = _store.OrgFindByName(repo.Owner, user.ForgeID)
|
||||
if err != nil && !errors.Is(err, types.RecordNotExist) {
|
||||
c.String(http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
|
|
|
@ -31,7 +31,7 @@ func wrapGet(exist bool, err error) error {
|
|||
return types.RecordNotExist
|
||||
}
|
||||
if err != nil {
|
||||
// we only ask for the function's name if needed, as it's not as preformatted as to just execute it
|
||||
// we only ask for the function's name if needed for performance reasons
|
||||
fnName := callerName(2)
|
||||
return fmt.Errorf("%s: %w", fnName, err)
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ func wrapDelete(c int64, err error) error {
|
|||
return types.RecordNotExist
|
||||
}
|
||||
if err != nil {
|
||||
// we only ask for the function's name if needed, as it's not as preformatted as to just execute it
|
||||
// we only ask for the function's name if needed for performance reasons
|
||||
fnName := callerName(2)
|
||||
return fmt.Errorf("%s: %w", fnName, err)
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ package datastore
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"xorm.io/xorm"
|
||||
|
||||
|
@ -73,14 +74,14 @@ func (s storage) orgDelete(sess *xorm.Session, id int64) error {
|
|||
return wrapDelete(sess.ID(id).Delete(new(model.Org)))
|
||||
}
|
||||
|
||||
func (s storage) OrgFindByName(name string) (*model.Org, error) {
|
||||
return s.orgFindByName(s.engine.NewSession(), name)
|
||||
func (s storage) OrgFindByName(name string, forgeID int64) (*model.Org, error) {
|
||||
return s.orgFindByName(s.engine.NewSession(), name, forgeID)
|
||||
}
|
||||
|
||||
func (s storage) orgFindByName(sess *xorm.Session, name string) (*model.Org, error) {
|
||||
func (s storage) orgFindByName(sess *xorm.Session, name string, forgeID int64) (*model.Org, error) {
|
||||
// sanitize
|
||||
org := new(model.Org)
|
||||
return org, wrapGet(sess.Where("name = ?", name).Get(org))
|
||||
return org, wrapGet(sess.Where("LOWER(name) = ?", strings.ToLower(name)).And("forge_id = ?", forgeID).Get(org))
|
||||
}
|
||||
|
||||
func (s storage) OrgRepoList(org *model.Org, p *model.ListOptions) ([]*model.Repo, error) {
|
||||
|
|
|
@ -28,6 +28,7 @@ func TestOrgCRUD(t *testing.T) {
|
|||
|
||||
org1 := &model.Org{
|
||||
Name: "someAwesomeOrg",
|
||||
ForgeID: 1,
|
||||
IsUser: false,
|
||||
Private: true,
|
||||
}
|
||||
|
@ -45,10 +46,10 @@ func TestOrgCRUD(t *testing.T) {
|
|||
assert.EqualValues(t, org1, orgOne)
|
||||
|
||||
// change name
|
||||
assert.NoError(t, store.OrgUpdate(&model.Org{ID: org1.ID, Name: "RenamedOrg"}))
|
||||
assert.NoError(t, store.OrgUpdate(&model.Org{ID: org1.ID, ForgeID: 1, Name: "RenamedOrg"}))
|
||||
|
||||
// find updated org by name
|
||||
orgOne, err = store.OrgFindByName("RenamedOrg")
|
||||
orgOne, err = store.OrgFindByName("RenamedOrg", 1)
|
||||
assert.NoError(t, err)
|
||||
assert.NotEqualValues(t, org1, orgOne)
|
||||
assert.EqualValues(t, org1.ID, orgOne.ID)
|
||||
|
|
|
@ -60,11 +60,12 @@ func (s storage) GetUserCount() (int64, error) {
|
|||
func (s storage) CreateUser(user *model.User) error {
|
||||
sess := s.engine.NewSession()
|
||||
org := &model.Org{
|
||||
Name: user.Login,
|
||||
IsUser: true,
|
||||
Name: user.Login,
|
||||
ForgeID: user.ForgeID,
|
||||
IsUser: true,
|
||||
}
|
||||
|
||||
existingOrg, err := s.orgFindByName(sess, org.Name)
|
||||
existingOrg, err := s.orgFindByName(sess, org.Name, user.ForgeID)
|
||||
if err != nil && !errors.Is(err, types.RecordNotExist) {
|
||||
return fmt.Errorf("failed to check if org exists: %w", err)
|
||||
}
|
||||
|
|
|
@ -112,8 +112,9 @@ func TestCreateUserWithExistingOrg(t *testing.T) {
|
|||
|
||||
// Create a new user with the same name as the existing organization
|
||||
newUser := &model.User{
|
||||
Login: "existingOrg",
|
||||
Hash: "A",
|
||||
Login: "existingOrg",
|
||||
Hash: "A",
|
||||
ForgeID: 1,
|
||||
}
|
||||
err = store.CreateUser(newUser)
|
||||
assert.NoError(t, err)
|
||||
|
@ -123,13 +124,14 @@ func TestCreateUserWithExistingOrg(t *testing.T) {
|
|||
assert.Equal(t, "existingOrg", updatedOrg.Name)
|
||||
|
||||
newUser2 := &model.User{
|
||||
Login: "new-user",
|
||||
Hash: "B",
|
||||
Login: "new-user",
|
||||
ForgeID: 1,
|
||||
Hash: "B",
|
||||
}
|
||||
err = store.CreateUser(newUser2)
|
||||
assert.NoError(t, err)
|
||||
|
||||
newOrg, err := store.OrgFindByName("new-user")
|
||||
newOrg, err := store.OrgFindByName("new-user", 1)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "new-user", newOrg.Name)
|
||||
}
|
||||
|
|
|
@ -1550,9 +1550,9 @@ func (_m *Store) OrgDelete(_a0 int64) error {
|
|||
return r0
|
||||
}
|
||||
|
||||
// OrgFindByName provides a mock function with given fields: _a0
|
||||
func (_m *Store) OrgFindByName(_a0 string) (*model.Org, error) {
|
||||
ret := _m.Called(_a0)
|
||||
// OrgFindByName provides a mock function with given fields: _a0, _a1
|
||||
func (_m *Store) OrgFindByName(_a0 string, _a1 int64) (*model.Org, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for OrgFindByName")
|
||||
|
@ -1560,19 +1560,19 @@ func (_m *Store) OrgFindByName(_a0 string) (*model.Org, error) {
|
|||
|
||||
var r0 *model.Org
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(string) (*model.Org, error)); ok {
|
||||
return rf(_a0)
|
||||
if rf, ok := ret.Get(0).(func(string, int64) (*model.Org, error)); ok {
|
||||
return rf(_a0, _a1)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(string) *model.Org); ok {
|
||||
r0 = rf(_a0)
|
||||
if rf, ok := ret.Get(0).(func(string, int64) *model.Org); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.Org)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||
r1 = rf(_a0)
|
||||
if rf, ok := ret.Get(1).(func(string, int64) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
|
|
@ -196,7 +196,7 @@ type Store interface {
|
|||
// Org
|
||||
OrgCreate(*model.Org) error
|
||||
OrgGet(int64) (*model.Org, error)
|
||||
OrgFindByName(string) (*model.Org, error)
|
||||
OrgFindByName(string, int64) (*model.Org, error)
|
||||
OrgUpdate(*model.Org) error
|
||||
OrgDelete(int64) error
|
||||
OrgList(*model.ListOptions) ([]*model.Org, error)
|
||||
|
|
Loading…
Reference in a new issue