Skip to content

Commit 8be3e43

Browse files
a1012112796lafrikszeripath
authored
Add team support for review request (#12039)
Add team support for review request Block #11355 Signed-off-by: a1012112796 <[email protected]> Signed-off-by: Andrew Thornton <[email protected]> Co-authored-by: Lauris BH <[email protected]> Co-authored-by: Andrew Thornton <[email protected]>
1 parent b546eda commit 8be3e43

File tree

17 files changed

+935
-272
lines changed

17 files changed

+935
-272
lines changed

models/error.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1994,6 +1994,26 @@ func (err ErrReviewNotExist) Error() string {
19941994
return fmt.Sprintf("review does not exist [id: %d]", err.ID)
19951995
}
19961996

1997+
// ErrNotValidReviewRequest an not allowed review request modify
1998+
type ErrNotValidReviewRequest struct {
1999+
Reason string
2000+
UserID int64
2001+
RepoID int64
2002+
}
2003+
2004+
// IsErrNotValidReviewRequest checks if an error is a ErrNotValidReviewRequest.
2005+
func IsErrNotValidReviewRequest(err error) bool {
2006+
_, ok := err.(ErrReviewNotExist)
2007+
return ok
2008+
}
2009+
2010+
func (err ErrNotValidReviewRequest) Error() string {
2011+
return fmt.Sprintf("%s [user_id: %d, repo_id: %d]",
2012+
err.Reason,
2013+
err.UserID,
2014+
err.RepoID)
2015+
}
2016+
19972017
// ________ _____ __ .__
19982018
// \_____ \ / _ \ __ ___/ |_| |__
19992019
// / | \ / /_\ \| | \ __\ | \

models/fixtures/review.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
reviewer_id: 2
4545
issue_id: 3
4646
content: "New review 3"
47+
original_author_id: 0
4748
updated_unix: 946684811
4849
created_unix: 946684811
4950
-
@@ -52,13 +53,15 @@
5253
reviewer_id: 3
5354
issue_id: 3
5455
content: "New review 4"
56+
original_author_id: 0
5557
updated_unix: 946684812
5658
created_unix: 946684812
5759
-
5860
id: 8
5961
type: 1
6062
reviewer_id: 4
6163
issue_id: 3
64+
original_author_id: 0
6265
content: "New review 5"
6366
commit_id: 8091a55037cd59e47293aca02981b5a67076b364
6467
stale: true
@@ -72,6 +75,7 @@
7275
content: "New review 3 rejected"
7376
updated_unix: 946684814
7477
created_unix: 946684814
78+
original_author_id: 0
7579

7680
-
7781
id: 10

models/issue_comment.go

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ type Comment struct {
137137
AssigneeID int64
138138
RemovedAssignee bool
139139
Assignee *User `xorm:"-"`
140+
AssigneeTeamID int64 `xorm:"NOT NULL DEFAULT 0"`
141+
AssigneeTeam *Team `xorm:"-"`
140142
ResolveDoerID int64
141143
ResolveDoer *User `xorm:"-"`
142144
OldTitle string
@@ -487,18 +489,37 @@ func (c *Comment) UpdateAttachments(uuids []string) error {
487489
return sess.Commit()
488490
}
489491

490-
// LoadAssigneeUser if comment.Type is CommentTypeAssignees, then load assignees
491-
func (c *Comment) LoadAssigneeUser() error {
492+
// LoadAssigneeUserAndTeam if comment.Type is CommentTypeAssignees, then load assignees
493+
func (c *Comment) LoadAssigneeUserAndTeam() error {
492494
var err error
493495

494-
if c.AssigneeID > 0 {
496+
if c.AssigneeID > 0 && c.Assignee == nil {
495497
c.Assignee, err = getUserByID(x, c.AssigneeID)
496498
if err != nil {
497499
if !IsErrUserNotExist(err) {
498500
return err
499501
}
500502
c.Assignee = NewGhostUser()
501503
}
504+
} else if c.AssigneeTeamID > 0 && c.AssigneeTeam == nil {
505+
if err = c.LoadIssue(); err != nil {
506+
return err
507+
}
508+
509+
if err = c.Issue.LoadRepo(); err != nil {
510+
return err
511+
}
512+
513+
if err = c.Issue.Repo.GetOwner(); err != nil {
514+
return err
515+
}
516+
517+
if c.Issue.Repo.Owner.IsOrganization() {
518+
c.AssigneeTeam, err = GetTeamByID(c.AssigneeTeamID)
519+
if err != nil && !IsErrTeamNotExist(err) {
520+
return err
521+
}
522+
}
502523
}
503524
return nil
504525
}
@@ -685,6 +706,7 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
685706
ProjectID: opts.ProjectID,
686707
RemovedAssignee: opts.RemovedAssignee,
687708
AssigneeID: opts.AssigneeID,
709+
AssigneeTeamID: opts.AssigneeTeamID,
688710
CommitID: opts.CommitID,
689711
CommitSHA: opts.CommitSHA,
690712
Line: opts.LineNum,
@@ -849,6 +871,7 @@ type CreateCommentOptions struct {
849871
OldProjectID int64
850872
ProjectID int64
851873
AssigneeID int64
874+
AssigneeTeamID int64
852875
RemovedAssignee bool
853876
OldTitle string
854877
NewTitle string

models/migrations/migrations.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,8 @@ var migrations = []Migration{
240240
NewMigration("set default password algorithm to Argon2", setDefaultPasswordToArgon2),
241241
// v152 -> v153
242242
NewMigration("add TrustModel field to Repository", addTrustModelToRepository),
243+
// v153 > v154
244+
NewMigration("add Team review request support", addTeamReviewRequestSupport),
243245
}
244246

245247
// GetCurrentDBVersion returns the current db version

models/migrations/v153.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2020 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package migrations
6+
7+
import (
8+
"xorm.io/xorm"
9+
)
10+
11+
func addTeamReviewRequestSupport(x *xorm.Engine) error {
12+
type Review struct {
13+
ReviewerTeamID int64 `xorm:"NOT NULL DEFAULT 0"`
14+
}
15+
16+
type Comment struct {
17+
AssigneeTeamID int64 `xorm:"NOT NULL DEFAULT 0"`
18+
}
19+
20+
if err := x.Sync2(new(Review)); err != nil {
21+
return err
22+
}
23+
24+
return x.Sync2(new(Comment))
25+
}

models/repo.go

Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -694,32 +694,37 @@ func (repo *Repository) GetAssignees() (_ []*User, err error) {
694694
return repo.getAssignees(x)
695695
}
696696

697-
func (repo *Repository) getReviewersPrivate(e Engine, doerID, posterID int64) (users []*User, err error) {
698-
users = make([]*User, 0, 20)
699-
700-
if err = e.
701-
SQL("SELECT * FROM `user` WHERE id in (SELECT user_id FROM `access` WHERE repo_id = ? AND mode >= ? AND user_id NOT IN ( ?, ?)) ORDER BY name",
702-
repo.ID, AccessModeRead,
703-
doerID, posterID).
704-
Find(&users); err != nil {
697+
func (repo *Repository) getReviewers(e Engine, doerID, posterID int64) ([]*User, error) {
698+
// Get the owner of the repository - this often already pre-cached and if so saves complexity for the following queries
699+
if err := repo.getOwner(e); err != nil {
705700
return nil, err
706701
}
707702

708-
return users, nil
709-
}
710-
711-
func (repo *Repository) getReviewersPublic(e Engine, doerID, posterID int64) (_ []*User, err error) {
703+
var users []*User
712704

713-
users := make([]*User, 0)
705+
if repo.IsPrivate ||
706+
(repo.Owner.IsOrganization() && repo.Owner.Visibility == api.VisibleTypePrivate) {
707+
// This a private repository:
708+
// Anyone who can read the repository is a requestable reviewer
709+
if err := e.
710+
SQL("SELECT * FROM `user` WHERE id in (SELECT user_id FROM `access` WHERE repo_id = ? AND mode >= ? AND user_id NOT IN ( ?, ?)) ORDER BY name",
711+
repo.ID, AccessModeRead,
712+
doerID, posterID).
713+
Find(&users); err != nil {
714+
return nil, err
715+
}
714716

715-
const SQLCmd = "SELECT * FROM `user` WHERE id IN ( " +
716-
"SELECT user_id FROM `access` WHERE repo_id = ? AND mode >= ? AND user_id NOT IN ( ?, ?) " +
717-
"UNION " +
718-
"SELECT user_id FROM `watch` WHERE repo_id = ? AND user_id NOT IN ( ?, ?) AND mode IN (?, ?) " +
719-
") ORDER BY name"
717+
return users, nil
718+
}
720719

721-
if err = e.
722-
SQL(SQLCmd,
720+
// This is a "public" repository:
721+
// Any user that has write access or who is a watcher can be requested to review
722+
if err := e.
723+
SQL("SELECT * FROM `user` WHERE id IN ( "+
724+
"SELECT user_id FROM `access` WHERE repo_id = ? AND mode >= ? AND user_id NOT IN ( ?, ?) "+
725+
"UNION "+
726+
"SELECT user_id FROM `watch` WHERE repo_id = ? AND user_id NOT IN ( ?, ?) AND mode IN (?, ?) "+
727+
") ORDER BY name",
723728
repo.ID, AccessModeRead, doerID, posterID,
724729
repo.ID, doerID, posterID, RepoWatchModeNormal, RepoWatchModeAuto).
725730
Find(&users); err != nil {
@@ -729,27 +734,30 @@ func (repo *Repository) getReviewersPublic(e Engine, doerID, posterID int64) (_
729734
return users, nil
730735
}
731736

732-
func (repo *Repository) getReviewers(e Engine, doerID, posterID int64) (users []*User, err error) {
733-
if err = repo.getOwner(e); err != nil {
737+
// GetReviewers get all users can be requested to review:
738+
// * for private repositories this returns all users that have read access or higher to the repository.
739+
// * for public repositories this returns all users that have write access or higher to the repository,
740+
// and all repo watchers.
741+
// TODO: may be we should hava a busy choice for users to block review request to them.
742+
func (repo *Repository) GetReviewers(doerID, posterID int64) ([]*User, error) {
743+
return repo.getReviewers(x, doerID, posterID)
744+
}
745+
746+
// GetReviewerTeams get all teams can be requested to review
747+
func (repo *Repository) GetReviewerTeams() ([]*Team, error) {
748+
if err := repo.GetOwner(); err != nil {
734749
return nil, err
735750
}
751+
if !repo.Owner.IsOrganization() {
752+
return nil, nil
753+
}
736754

737-
if repo.IsPrivate ||
738-
(repo.Owner.IsOrganization() && repo.Owner.Visibility == api.VisibleTypePrivate) {
739-
users, err = repo.getReviewersPrivate(x, doerID, posterID)
740-
} else {
741-
users, err = repo.getReviewersPublic(x, doerID, posterID)
755+
teams, err := GetTeamsWithAccessToRepo(repo.OwnerID, repo.ID, AccessModeRead)
756+
if err != nil {
757+
return nil, err
742758
}
743-
return
744-
}
745759

746-
// GetReviewers get all users can be requested to review
747-
// for private rpo , that return all users that have read access or higher to the repository.
748-
// but for public rpo, that return all users that have write access or higher to the repository,
749-
// and all repo watchers.
750-
// TODO: may be we should hava a busy choice for users to block review request to them.
751-
func (repo *Repository) GetReviewers(doerID, posterID int64) (_ []*User, err error) {
752-
return repo.getReviewers(x, doerID, posterID)
760+
return teams, err
753761
}
754762

755763
// GetMilestoneByID returns the milestone belongs to repository by given ID.

models/repo_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,3 +193,34 @@ func TestDoctorUserStarNum(t *testing.T) {
193193

194194
assert.NoError(t, DoctorUserStarNum())
195195
}
196+
197+
func TestRepoGetReviewers(t *testing.T) {
198+
assert.NoError(t, PrepareTestDatabase())
199+
200+
// test public repo
201+
repo1 := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
202+
203+
reviewers, err := repo1.GetReviewers(2, 2)
204+
assert.NoError(t, err)
205+
assert.Equal(t, 4, len(reviewers))
206+
207+
// test private repo
208+
repo2 := AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository)
209+
reviewers, err = repo2.GetReviewers(2, 2)
210+
assert.NoError(t, err)
211+
assert.Equal(t, 0, len(reviewers))
212+
}
213+
214+
func TestRepoGetReviewerTeams(t *testing.T) {
215+
assert.NoError(t, PrepareTestDatabase())
216+
217+
repo2 := AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository)
218+
teams, err := repo2.GetReviewerTeams()
219+
assert.NoError(t, err)
220+
assert.Empty(t, teams)
221+
222+
repo3 := AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository)
223+
teams, err = repo3.GetReviewerTeams()
224+
assert.NoError(t, err)
225+
assert.Equal(t, 2, len(teams))
226+
}

0 commit comments

Comments
 (0)