Skip to content

Commit 6fe3c8b

Browse files
lunny6543
andauthored
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 <[email protected]>
1 parent 0c048e5 commit 6fe3c8b

File tree

30 files changed

+1556
-176
lines changed

30 files changed

+1556
-176
lines changed

models/fixtures/project.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,12 @@
2424
creator_id: 5
2525
board_type: 1
2626
type: 2
27+
28+
-
29+
id: 4
30+
title: project on user2
31+
owner_id: 2
32+
is_closed: false
33+
creator_id: 2
34+
board_type: 1
35+
type: 2

models/fixtures/project_board.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,11 @@
2121
creator_id: 2
2222
created_unix: 1588117528
2323
updated_unix: 1588117528
24+
25+
-
26+
id: 4
27+
project_id: 4
28+
title: Done
29+
creator_id: 2
30+
created_unix: 1588117528
31+
updated_unix: 1588117528

models/issues/issue.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1098,7 +1098,7 @@ func GetIssueWithAttrsByID(id int64) (*Issue, error) {
10981098
}
10991099

11001100
// GetIssuesByIDs return issues with the given IDs.
1101-
func GetIssuesByIDs(ctx context.Context, issueIDs []int64) ([]*Issue, error) {
1101+
func GetIssuesByIDs(ctx context.Context, issueIDs []int64) (IssueList, error) {
11021102
issues := make([]*Issue, 0, 10)
11031103
return issues, db.GetEngine(ctx).In("id", issueIDs).Find(&issues)
11041104
}

models/issues/issue_project.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,17 @@ func ChangeProjectAssign(issue *Issue, doer *user_model.User, newProjectID int64
125125
func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.User, newProjectID int64) error {
126126
oldProjectID := issue.projectID(ctx)
127127

128+
if err := issue.LoadRepo(ctx); err != nil {
129+
return err
130+
}
131+
128132
// Only check if we add a new project and not remove it.
129133
if newProjectID > 0 {
130134
newProject, err := project_model.GetProjectByID(ctx, newProjectID)
131135
if err != nil {
132136
return err
133137
}
134-
if newProject.RepoID != issue.RepoID {
138+
if newProject.RepoID != issue.RepoID && newProject.OwnerID != issue.Repo.OwnerID {
135139
return fmt.Errorf("issue's repository is not the same as project's repository")
136140
}
137141
}
@@ -140,10 +144,6 @@ func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.U
140144
return err
141145
}
142146

143-
if err := issue.LoadRepo(ctx); err != nil {
144-
return err
145-
}
146-
147147
if oldProjectID > 0 || newProjectID > 0 {
148148
if _, err := CreateComment(ctx, &CreateCommentOptions{
149149
Type: CommentTypeProject,

models/organization/team.go

Lines changed: 0 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ import (
1616
user_model "code.gitea.io/gitea/models/user"
1717
"code.gitea.io/gitea/modules/log"
1818
"code.gitea.io/gitea/modules/util"
19-
20-
"xorm.io/builder"
2119
)
2220

2321
// ___________
@@ -96,59 +94,6 @@ func init() {
9694
db.RegisterModel(new(TeamInvite))
9795
}
9896

99-
// SearchTeamOptions holds the search options
100-
type SearchTeamOptions struct {
101-
db.ListOptions
102-
UserID int64
103-
Keyword string
104-
OrgID int64
105-
IncludeDesc bool
106-
}
107-
108-
func (opts *SearchTeamOptions) toCond() builder.Cond {
109-
cond := builder.NewCond()
110-
111-
if len(opts.Keyword) > 0 {
112-
lowerKeyword := strings.ToLower(opts.Keyword)
113-
var keywordCond builder.Cond = builder.Like{"lower_name", lowerKeyword}
114-
if opts.IncludeDesc {
115-
keywordCond = keywordCond.Or(builder.Like{"LOWER(description)", lowerKeyword})
116-
}
117-
cond = cond.And(keywordCond)
118-
}
119-
120-
if opts.OrgID > 0 {
121-
cond = cond.And(builder.Eq{"`team`.org_id": opts.OrgID})
122-
}
123-
124-
if opts.UserID > 0 {
125-
cond = cond.And(builder.Eq{"team_user.uid": opts.UserID})
126-
}
127-
128-
return cond
129-
}
130-
131-
// SearchTeam search for teams. Caller is responsible to check permissions.
132-
func SearchTeam(opts *SearchTeamOptions) ([]*Team, int64, error) {
133-
sess := db.GetEngine(db.DefaultContext)
134-
135-
opts.SetDefaultValues()
136-
cond := opts.toCond()
137-
138-
if opts.UserID > 0 {
139-
sess = sess.Join("INNER", "team_user", "team_user.team_id = team.id")
140-
}
141-
sess = db.SetSessionPagination(sess, opts)
142-
143-
teams := make([]*Team, 0, opts.PageSize)
144-
count, err := sess.Where(cond).OrderBy("lower_name").FindAndCount(&teams)
145-
if err != nil {
146-
return nil, 0, err
147-
}
148-
149-
return teams, count, nil
150-
}
151-
15297
// ColorFormat provides a basic color format for a Team
15398
func (t *Team) ColorFormat(s fmt.State) {
15499
if t == nil {
@@ -335,16 +280,6 @@ func GetTeamNamesByID(teamIDs []int64) ([]string, error) {
335280
return teamNames, err
336281
}
337282

338-
// GetRepoTeams gets the list of teams that has access to the repository
339-
func GetRepoTeams(ctx context.Context, repo *repo_model.Repository) (teams []*Team, err error) {
340-
return teams, db.GetEngine(ctx).
341-
Join("INNER", "team_repo", "team_repo.team_id = team.id").
342-
Where("team.org_id = ?", repo.OwnerID).
343-
And("team_repo.repo_id=?", repo.ID).
344-
OrderBy("CASE WHEN name LIKE '" + OwnerTeamName + "' THEN '' ELSE name END").
345-
Find(&teams)
346-
}
347-
348283
// IncrTeamRepoNum increases the number of repos for the given team by 1
349284
func IncrTeamRepoNum(ctx context.Context, teamID int64) error {
350285
_, err := db.GetEngine(ctx).Incr("num_repos").ID(teamID).Update(new(Team))

models/organization/team_list.go

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// Copyright 2022 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package organization
5+
6+
import (
7+
"context"
8+
"strings"
9+
10+
"code.gitea.io/gitea/models/db"
11+
"code.gitea.io/gitea/models/perm"
12+
repo_model "code.gitea.io/gitea/models/repo"
13+
"code.gitea.io/gitea/models/unit"
14+
15+
"xorm.io/builder"
16+
)
17+
18+
type TeamList []*Team
19+
20+
func (t TeamList) LoadUnits(ctx context.Context) error {
21+
for _, team := range t {
22+
if err := team.getUnits(ctx); err != nil {
23+
return err
24+
}
25+
}
26+
return nil
27+
}
28+
29+
func (t TeamList) UnitMaxAccess(tp unit.Type) perm.AccessMode {
30+
maxAccess := perm.AccessModeNone
31+
for _, team := range t {
32+
if team.IsOwnerTeam() {
33+
return perm.AccessModeOwner
34+
}
35+
for _, teamUnit := range team.Units {
36+
if teamUnit.Type != tp {
37+
continue
38+
}
39+
if teamUnit.AccessMode > maxAccess {
40+
maxAccess = teamUnit.AccessMode
41+
}
42+
}
43+
}
44+
return maxAccess
45+
}
46+
47+
// SearchTeamOptions holds the search options
48+
type SearchTeamOptions struct {
49+
db.ListOptions
50+
UserID int64
51+
Keyword string
52+
OrgID int64
53+
IncludeDesc bool
54+
}
55+
56+
func (opts *SearchTeamOptions) toCond() builder.Cond {
57+
cond := builder.NewCond()
58+
59+
if len(opts.Keyword) > 0 {
60+
lowerKeyword := strings.ToLower(opts.Keyword)
61+
var keywordCond builder.Cond = builder.Like{"lower_name", lowerKeyword}
62+
if opts.IncludeDesc {
63+
keywordCond = keywordCond.Or(builder.Like{"LOWER(description)", lowerKeyword})
64+
}
65+
cond = cond.And(keywordCond)
66+
}
67+
68+
if opts.OrgID > 0 {
69+
cond = cond.And(builder.Eq{"`team`.org_id": opts.OrgID})
70+
}
71+
72+
if opts.UserID > 0 {
73+
cond = cond.And(builder.Eq{"team_user.uid": opts.UserID})
74+
}
75+
76+
return cond
77+
}
78+
79+
// SearchTeam search for teams. Caller is responsible to check permissions.
80+
func SearchTeam(opts *SearchTeamOptions) (TeamList, int64, error) {
81+
sess := db.GetEngine(db.DefaultContext)
82+
83+
opts.SetDefaultValues()
84+
cond := opts.toCond()
85+
86+
if opts.UserID > 0 {
87+
sess = sess.Join("INNER", "team_user", "team_user.team_id = team.id")
88+
}
89+
sess = db.SetSessionPagination(sess, opts)
90+
91+
teams := make([]*Team, 0, opts.PageSize)
92+
count, err := sess.Where(cond).OrderBy("lower_name").FindAndCount(&teams)
93+
if err != nil {
94+
return nil, 0, err
95+
}
96+
97+
return teams, count, nil
98+
}
99+
100+
// GetRepoTeams gets the list of teams that has access to the repository
101+
func GetRepoTeams(ctx context.Context, repo *repo_model.Repository) (teams TeamList, err error) {
102+
return teams, db.GetEngine(ctx).
103+
Join("INNER", "team_repo", "team_repo.team_id = team.id").
104+
Where("team.org_id = ?", repo.OwnerID).
105+
And("team_repo.repo_id=?", repo.ID).
106+
OrderBy("CASE WHEN name LIKE '" + OwnerTeamName + "' THEN '' ELSE name END").
107+
Find(&teams)
108+
}
109+
110+
// GetUserOrgTeams returns all teams that user belongs to in given organization.
111+
func GetUserOrgTeams(ctx context.Context, orgID, userID int64) (teams TeamList, err error) {
112+
return teams, db.GetEngine(ctx).
113+
Join("INNER", "team_user", "team_user.team_id = team.id").
114+
Where("team.org_id = ?", orgID).
115+
And("team_user.uid=?", userID).
116+
Find(&teams)
117+
}
118+
119+
// GetUserRepoTeams returns user repo's teams
120+
func GetUserRepoTeams(ctx context.Context, orgID, userID, repoID int64) (teams TeamList, err error) {
121+
return teams, db.GetEngine(ctx).
122+
Join("INNER", "team_user", "team_user.team_id = team.id").
123+
Join("INNER", "team_repo", "team_repo.team_id = team.id").
124+
Where("team.org_id = ?", orgID).
125+
And("team_user.uid=?", userID).
126+
And("team_repo.repo_id=?", repoID).
127+
Find(&teams)
128+
}

models/organization/team_user.go

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -72,26 +72,6 @@ func GetTeamMembers(ctx context.Context, opts *SearchMembersOptions) ([]*user_mo
7272
return members, nil
7373
}
7474

75-
// GetUserOrgTeams returns all teams that user belongs to in given organization.
76-
func GetUserOrgTeams(ctx context.Context, orgID, userID int64) (teams []*Team, err error) {
77-
return teams, db.GetEngine(ctx).
78-
Join("INNER", "team_user", "team_user.team_id = team.id").
79-
Where("team.org_id = ?", orgID).
80-
And("team_user.uid=?", userID).
81-
Find(&teams)
82-
}
83-
84-
// GetUserRepoTeams returns user repo's teams
85-
func GetUserRepoTeams(ctx context.Context, orgID, userID, repoID int64) (teams []*Team, err error) {
86-
return teams, db.GetEngine(ctx).
87-
Join("INNER", "team_user", "team_user.team_id = team.id").
88-
Join("INNER", "team_repo", "team_repo.team_id = team.id").
89-
Where("team.org_id = ?", orgID).
90-
And("team_user.uid=?", userID).
91-
And("team_repo.repo_id=?", repoID).
92-
Find(&teams)
93-
}
94-
9575
// IsUserInTeams returns if a user in some teams
9676
func IsUserInTeams(ctx context.Context, userID int64, teamIDs []int64) (bool, error) {
9777
return db.GetEngine(ctx).Where("uid=?", userID).In("team_id", teamIDs).Exist(new(TeamUser))

0 commit comments

Comments
 (0)