fix: assign bot-created projects to the bot's owner

When a bot user creates a project, the bot's owner (the human who
created the bot) now owns the project instead of the bot itself. The bot
retains admin access via an explicit project share. This ensures the
human can always see and manage projects their bots create.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Bradley Erickson
2026-07-01 11:53:19 -07:00
committed by kolaente
parent 82f86ef7d8
commit 61d74ee2ef
2 changed files with 46 additions and 2 deletions

View File

@@ -1046,8 +1046,17 @@ func CreateProject(s *xorm.Session, project *Project, auth web.Auth, createBackl
}
project.ID = 0
project.OwnerID = doer.ID
project.Owner = doer
if doer.IsBot() {
project.OwnerID = doer.BotOwnerID
owner, err := user.GetUserByID(s, doer.BotOwnerID)
if err != nil {
return err
}
project.Owner = owner
} else {
project.OwnerID = doer.ID
project.Owner = doer
}
err = checkProjectBeforeUpdateOrDelete(s, project)
if err != nil {
@@ -1061,6 +1070,18 @@ func CreateProject(s *xorm.Session, project *Project, auth web.Auth, createBackl
return
}
// Give the bot continued access to the project it created.
if doer.IsBot() {
pu := &ProjectUser{
ProjectID: project.ID,
Username: doer.Username,
Permission: PermissionAdmin,
}
if err = pu.Create(s, auth); err != nil {
return err
}
}
project.Position = calculateDefaultPosition(project.ID, project.Position)
_, err = s.Where("id = ?", project.ID).Update(project)
if err != nil {

View File

@@ -79,6 +79,29 @@ func TestProject_CreateOrUpdate(t *testing.T) {
"project_view_id": kanbanView.ID,
}, false)
})
t.Run("bot project owned by bot owner", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := db.NewSession()
defer s.Close()
bot := &user.User{ID: 23, Username: "bot-owner-a-assistant", BotOwnerID: 21}
project := Project{Title: "bot-created"}
err := project.Create(s, bot)
require.NoError(t, err)
require.NoError(t, s.Commit())
// The bot's owner should own the project.
db.AssertExists(t, "projects", map[string]interface{}{
"id": project.ID,
"owner_id": 21,
}, false)
// The bot should retain access via a share.
db.AssertExists(t, "users_projects", map[string]interface{}{
"user_id": 23,
"project_id": project.ID,
"permission": PermissionAdmin,
}, false)
})
t.Run("kanban view creates To-Do, doing, done buckets", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := db.NewSession()