mirror of
https://github.com/go-gitea/gitea
synced 2025-07-22 18:28:37 +00:00
Support org/user level projects (#22235)
Fix #13405 <img width="1151" alt="image" src="https://user-images.githubusercontent.com/81045/209442911-7baa3924-c389-47b6-b63b-a740803e640e.png"> Co-authored-by: 6543 <6543@obermui.de>
This commit is contained in:
@@ -8,6 +8,9 @@ import (
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
@@ -78,12 +81,15 @@ func (err ErrProjectBoardNotExist) Unwrap() error {
|
||||
|
||||
// Project represents a project board
|
||||
type Project struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Title string `xorm:"INDEX NOT NULL"`
|
||||
Description string `xorm:"TEXT"`
|
||||
RepoID int64 `xorm:"INDEX"`
|
||||
CreatorID int64 `xorm:"NOT NULL"`
|
||||
IsClosed bool `xorm:"INDEX"`
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Title string `xorm:"INDEX NOT NULL"`
|
||||
Description string `xorm:"TEXT"`
|
||||
OwnerID int64 `xorm:"INDEX"`
|
||||
Owner *user_model.User `xorm:"-"`
|
||||
RepoID int64 `xorm:"INDEX"`
|
||||
Repo *repo_model.Repository `xorm:"-"`
|
||||
CreatorID int64 `xorm:"NOT NULL"`
|
||||
IsClosed bool `xorm:"INDEX"`
|
||||
BoardType BoardType
|
||||
Type Type
|
||||
|
||||
@@ -94,6 +100,46 @@ type Project struct {
|
||||
ClosedDateUnix timeutil.TimeStamp
|
||||
}
|
||||
|
||||
func (p *Project) LoadOwner(ctx context.Context) (err error) {
|
||||
if p.Owner != nil {
|
||||
return nil
|
||||
}
|
||||
p.Owner, err = user_model.GetUserByID(ctx, p.OwnerID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *Project) LoadRepo(ctx context.Context) (err error) {
|
||||
if p.RepoID == 0 || p.Repo != nil {
|
||||
return nil
|
||||
}
|
||||
p.Repo, err = repo_model.GetRepositoryByID(ctx, p.RepoID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *Project) Link() string {
|
||||
if p.OwnerID > 0 {
|
||||
err := p.LoadOwner(db.DefaultContext)
|
||||
if err != nil {
|
||||
log.Error("LoadOwner: %v", err)
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("/%s/-/projects/%d", p.Owner.Name, p.ID)
|
||||
}
|
||||
if p.RepoID > 0 {
|
||||
err := p.LoadRepo(db.DefaultContext)
|
||||
if err != nil {
|
||||
log.Error("LoadRepo: %v", err)
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("/%s/projects/%d", p.Repo.RepoPath(), p.ID)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *Project) IsOrganizationProject() bool {
|
||||
return p.Type == TypeOrganization
|
||||
}
|
||||
|
||||
func init() {
|
||||
db.RegisterModel(new(Project))
|
||||
}
|
||||
@@ -110,7 +156,7 @@ func GetProjectsConfig() []ProjectsConfig {
|
||||
// IsTypeValid checks if a project type is valid
|
||||
func IsTypeValid(p Type) bool {
|
||||
switch p {
|
||||
case TypeRepository:
|
||||
case TypeRepository, TypeOrganization:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
@@ -119,6 +165,7 @@ func IsTypeValid(p Type) bool {
|
||||
|
||||
// SearchOptions are options for GetProjects
|
||||
type SearchOptions struct {
|
||||
OwnerID int64
|
||||
RepoID int64
|
||||
Page int
|
||||
IsClosed util.OptionalBool
|
||||
@@ -126,12 +173,11 @@ type SearchOptions struct {
|
||||
Type Type
|
||||
}
|
||||
|
||||
// GetProjects returns a list of all projects that have been created in the repository
|
||||
func GetProjects(ctx context.Context, opts SearchOptions) ([]*Project, int64, error) {
|
||||
e := db.GetEngine(ctx)
|
||||
projects := make([]*Project, 0, setting.UI.IssuePagingNum)
|
||||
|
||||
var cond builder.Cond = builder.Eq{"repo_id": opts.RepoID}
|
||||
func (opts *SearchOptions) toConds() builder.Cond {
|
||||
cond := builder.NewCond()
|
||||
if opts.RepoID > 0 {
|
||||
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
|
||||
}
|
||||
switch opts.IsClosed {
|
||||
case util.OptionalBoolTrue:
|
||||
cond = cond.And(builder.Eq{"is_closed": true})
|
||||
@@ -142,6 +188,22 @@ func GetProjects(ctx context.Context, opts SearchOptions) ([]*Project, int64, er
|
||||
if opts.Type > 0 {
|
||||
cond = cond.And(builder.Eq{"type": opts.Type})
|
||||
}
|
||||
if opts.OwnerID > 0 {
|
||||
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
|
||||
}
|
||||
return cond
|
||||
}
|
||||
|
||||
// CountProjects counts projects
|
||||
func CountProjects(ctx context.Context, opts SearchOptions) (int64, error) {
|
||||
return db.GetEngine(ctx).Where(opts.toConds()).Count(new(Project))
|
||||
}
|
||||
|
||||
// FindProjects returns a list of all projects that have been created in the repository
|
||||
func FindProjects(ctx context.Context, opts SearchOptions) ([]*Project, int64, error) {
|
||||
e := db.GetEngine(ctx)
|
||||
projects := make([]*Project, 0, setting.UI.IssuePagingNum)
|
||||
cond := opts.toConds()
|
||||
|
||||
count, err := e.Where(cond).Count(new(Project))
|
||||
if err != nil {
|
||||
@@ -188,8 +250,10 @@ func NewProject(p *Project) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := db.Exec(ctx, "UPDATE `repository` SET num_projects = num_projects + 1 WHERE id = ?", p.RepoID); err != nil {
|
||||
return err
|
||||
if p.RepoID > 0 {
|
||||
if _, err := db.Exec(ctx, "UPDATE `repository` SET num_projects = num_projects + 1 WHERE id = ?", p.RepoID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := createBoardsForProjectsType(ctx, p); err != nil {
|
||||
|
@@ -22,7 +22,7 @@ func TestIsProjectTypeValid(t *testing.T) {
|
||||
}{
|
||||
{TypeIndividual, false},
|
||||
{TypeRepository, true},
|
||||
{TypeOrganization, false},
|
||||
{TypeOrganization, true},
|
||||
{UnknownType, false},
|
||||
}
|
||||
|
||||
@@ -34,13 +34,13 @@ func TestIsProjectTypeValid(t *testing.T) {
|
||||
func TestGetProjects(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
projects, _, err := GetProjects(db.DefaultContext, SearchOptions{RepoID: 1})
|
||||
projects, _, err := FindProjects(db.DefaultContext, SearchOptions{RepoID: 1})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// 1 value for this repo exists in the fixtures
|
||||
assert.Len(t, projects, 1)
|
||||
|
||||
projects, _, err = GetProjects(db.DefaultContext, SearchOptions{RepoID: 3})
|
||||
projects, _, err = FindProjects(db.DefaultContext, SearchOptions{RepoID: 3})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// 1 value for this repo exists in the fixtures
|
||||
|
Reference in New Issue
Block a user