fix: honor org/user project in new issue (#9906)

Previously, when a project id was passed into the new issue form as a
query parameter, it wouldn’t be selected if the project belonged to the
user or organization instead of directly to the repository.

Resolves forgejo/forgejo#8489

Signed-off-by: Nils Philippsen <nils@redhat.com>
Co-authored-by: Gusted <postmaster@gusted.xyz>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/9906
Reviewed-by: Gusted <gusted@noreply.codeberg.org>
Reviewed-by: Robert Wolff <mahlzahn@posteo.de>
Co-authored-by: Nils Philippsen <nilsph@noreply.codeberg.org>
Co-committed-by: Nils Philippsen <nilsph@noreply.codeberg.org>
This commit is contained in:
Nils Philippsen 2026-02-16 05:52:47 +01:00 committed by Gusted
parent ba2020a333
commit 5589182c54
4 changed files with 114 additions and 11 deletions

View file

@ -42,7 +42,7 @@
is_closed: false
creator_id: 2
board_type: 1
type: 2
type: 1
created_unix: 1688973000
updated_unix: 1688973000
@ -54,7 +54,7 @@
is_closed: false
creator_id: 2
board_type: 1
type: 2
type: 1
created_unix: 1688973000
updated_unix: 1688973000
@ -66,6 +66,18 @@
is_closed: false
creator_id: 2
board_type: 1
type: 2
type: 1
created_unix: 1688973000
updated_unix: 1688973000
-
id: 7
title: project on org3
owner_id: 3
repo_id: 0
is_closed: false
creator_id: 2
board_type: 1
type: 1
created_unix: 1688973000
updated_unix: 1688973000

View file

@ -93,19 +93,19 @@ func TestProjectsSort(t *testing.T) {
}{
{
sortType: "default",
wants: []int64{1, 3, 2, 6, 5, 4},
wants: []int64{1, 3, 2, 7, 6, 5, 4},
},
{
sortType: "oldest",
wants: []int64{4, 5, 6, 2, 3, 1},
wants: []int64{4, 5, 6, 7, 2, 3, 1},
},
{
sortType: "recentupdate",
wants: []int64{1, 3, 2, 6, 5, 4},
wants: []int64{1, 3, 2, 7, 6, 5, 4},
},
{
sortType: "leastupdate",
wants: []int64{4, 5, 6, 2, 3, 1},
wants: []int64{4, 5, 6, 7, 2, 3, 1},
},
}
@ -114,8 +114,8 @@ func TestProjectsSort(t *testing.T) {
OrderBy: GetSearchOrderByBySortType(tt.sortType),
})
require.NoError(t, err)
assert.Equal(t, int64(6), count)
if assert.Len(t, projects, 6) {
assert.Equal(t, int64(7), count)
if assert.Len(t, projects, 7) {
for i := range projects {
assert.Equal(t, tt.wants[i], projects[i].ID)
}

View file

@ -989,8 +989,10 @@ func NewIssue(ctx *context.Context) {
project, err := project_model.GetProjectByID(ctx, projectID)
if err != nil {
log.Error("GetProjectByID: %d: %v", projectID, err)
} else if project.RepoID != ctx.Repo.Repository.ID {
log.Error("GetProjectByID: %d: %v", projectID, fmt.Errorf("project[%d] not in repo [%d]", project.ID, ctx.Repo.Repository.ID))
} else if !project.CanBeAccessedByOwnerRepo(ctx.Repo.Repository.OwnerID, ctx.Repo.Repository) {
log.Error("GetProjectByID: %d: %v", projectID,
fmt.Errorf("project[%d] neither in repo[%d] nor has the same owner (project: [%d] ./. repo: [%d])",
project.ID, ctx.Repo.Repository.ID, project.OwnerID, ctx.Repo.Repository.OwnerID))
} else {
ctx.Data["project_id"] = projectID
ctx.Data["Project"] = project

View file

@ -0,0 +1,89 @@
// Copyright 2025 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package repo
import (
"fmt"
"testing"
"forgejo.org/models/unittest"
"forgejo.org/services/contexttest"
"github.com/stretchr/testify/assert"
)
func TestNewIssueValidateProject(t *testing.T) {
unittest.PrepareTestEnv(t)
for _, testCase := range []struct {
name string
projectID int64
userName string
userID int64
repoName string
repoID int64
isFound bool
}{
{
name: "Project belongs to repository",
projectID: 1,
userName: "user2",
userID: 2,
repoName: "repo1",
repoID: 1,
isFound: true,
},
{
name: "Project belongs to user",
projectID: 4,
userName: "user2",
userID: 2,
repoName: "repo1",
repoID: 1,
isFound: true,
},
{
name: "Project belongs to org",
projectID: 7,
userName: "org3",
userID: 3,
repoName: "repo3",
repoID: 3,
isFound: true,
},
{
name: "Project neither belongs to repo nor the user",
projectID: 2,
userName: "user2",
userID: 2,
repoName: "repo1",
repoID: 1,
isFound: false,
},
} {
t.Run(testCase.name, func(t *testing.T) {
ctx, _ := contexttest.MockContext(
t, fmt.Sprintf(
"/%s/%s/issues/new?project=%d",
testCase.userName,
testCase.repoName,
testCase.projectID,
),
)
contexttest.LoadUser(t, ctx, testCase.userID)
contexttest.LoadRepo(t, ctx, testCase.repoID)
contexttest.LoadGitRepo(t, ctx)
NewIssue(ctx)
if testCase.isFound {
assert.Equal(t, testCase.projectID, ctx.Data["project_id"])
assert.NotNil(t, ctx.Data["Project"])
} else {
assert.Nil(t, ctx.Data["project_id"])
assert.Nil(t, ctx.Data["Project"])
}
})
}
}