Skip to content

Commit 9b247fa

Browse files
author
Gusted
committed
Merge branch 'main' into improve-code-review-comment
2 parents 7cfa8bf + 69fcca2 commit 9b247fa

File tree

85 files changed

+1142
-382
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+1142
-382
lines changed

.eslintrc.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,6 @@ overrides:
3535
rules:
3636
import/no-unresolved: [0]
3737
import/no-extraneous-dependencies: [0]
38-
- files: ["*.test.js"]
39-
env:
40-
jest: true
4138
- files: ["*.config.js"]
4239
rules:
4340
import/no-unused-modules: [0]

docs/content/doc/installation/from-package.zh-cn.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ choco install gitea
7171
macOS 平台下当前我们仅支持通过 `brew` 来安装。如果你没有安装 [Homebrew](http://brew.sh/),你也可以查看 [从二进制安装]({{< relref "from-binary.zh-cn.md" >}})。在你安装了 `brew` 之后, 你可以执行以下命令:
7272

7373
```
74-
brew tap go-gitea/gitea
74+
brew tap gitea/tap https://gitea.com/gitea/homebrew-gitea
7575
brew install gitea
7676
```
7777

models/fixtures/hook_task.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
-
22
id: 1
3-
repo_id: 1
43
hook_id: 1
54
uuid: uuid1
65
is_delivered: true

models/migrations/migrations.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,8 @@ var migrations = []Migration{
417417
NewMigration("Conan and generic packages do not need to be semantically versioned", fixPackageSemverField),
418418
// v227 -> v228
419419
NewMigration("Create key/value table for system settings", createSystemSettingsTable),
420+
// v228 -> v229
421+
NewMigration("Add TeamInvite table", addTeamInviteTable),
420422
}
421423

422424
// GetCurrentDBVersion returns the current db version

models/migrations/v228.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2022 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+
"code.gitea.io/gitea/modules/timeutil"
9+
10+
"xorm.io/xorm"
11+
)
12+
13+
func addTeamInviteTable(x *xorm.Engine) error {
14+
type TeamInvite struct {
15+
ID int64 `xorm:"pk autoincr"`
16+
Token string `xorm:"UNIQUE(token) INDEX NOT NULL DEFAULT ''"`
17+
InviterID int64 `xorm:"NOT NULL DEFAULT 0"`
18+
OrgID int64 `xorm:"INDEX NOT NULL DEFAULT 0"`
19+
TeamID int64 `xorm:"UNIQUE(team_mail) INDEX NOT NULL DEFAULT 0"`
20+
Email string `xorm:"UNIQUE(team_mail) NOT NULL DEFAULT ''"`
21+
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
22+
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
23+
}
24+
25+
return x.Sync2(new(TeamInvite))
26+
}

models/org_team.go

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -431,25 +431,15 @@ func DeleteTeam(t *organization.Team) error {
431431
}
432432
}
433433

434-
// Delete team-user.
435-
if _, err := sess.
436-
Where("org_id=?", t.OrgID).
437-
Where("team_id=?", t.ID).
438-
Delete(new(organization.TeamUser)); err != nil {
439-
return err
440-
}
441-
442-
// Delete team-unit.
443-
if _, err := sess.
444-
Where("team_id=?", t.ID).
445-
Delete(new(organization.TeamUnit)); err != nil {
434+
if err := db.DeleteBeans(ctx,
435+
&organization.Team{ID: t.ID},
436+
&organization.TeamUser{OrgID: t.OrgID, TeamID: t.ID},
437+
&organization.TeamUnit{TeamID: t.ID},
438+
&organization.TeamInvite{TeamID: t.ID},
439+
); err != nil {
446440
return err
447441
}
448442

449-
// Delete team.
450-
if _, err := sess.ID(t.ID).Delete(new(organization.Team)); err != nil {
451-
return err
452-
}
453443
// Update organization number of teams.
454444
if _, err := sess.Exec("UPDATE `user` SET num_teams=num_teams-1 WHERE id=?", t.OrgID); err != nil {
455445
return err

models/organization/org.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,8 +370,9 @@ func DeleteOrganization(ctx context.Context, org *Organization) error {
370370
&OrgUser{OrgID: org.ID},
371371
&TeamUser{OrgID: org.ID},
372372
&TeamUnit{OrgID: org.ID},
373+
&TeamInvite{OrgID: org.ID},
373374
); err != nil {
374-
return fmt.Errorf("deleteBeans: %v", err)
375+
return fmt.Errorf("DeleteBeans: %v", err)
375376
}
376377

377378
if _, err := db.GetEngine(ctx).ID(org.ID).Delete(new(user_model.User)); err != nil {

models/organization/team.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ func init() {
9494
db.RegisterModel(new(TeamUser))
9595
db.RegisterModel(new(TeamRepo))
9696
db.RegisterModel(new(TeamUnit))
97+
db.RegisterModel(new(TeamInvite))
9798
}
9899

99100
// SearchTeamOptions holds the search options

models/organization/team_invite.go

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
// Copyright 2022 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 organization
6+
7+
import (
8+
"context"
9+
"fmt"
10+
11+
"code.gitea.io/gitea/models/db"
12+
user_model "code.gitea.io/gitea/models/user"
13+
"code.gitea.io/gitea/modules/timeutil"
14+
"code.gitea.io/gitea/modules/util"
15+
16+
"xorm.io/builder"
17+
)
18+
19+
type ErrTeamInviteAlreadyExist struct {
20+
TeamID int64
21+
Email string
22+
}
23+
24+
func IsErrTeamInviteAlreadyExist(err error) bool {
25+
_, ok := err.(ErrTeamInviteAlreadyExist)
26+
return ok
27+
}
28+
29+
func (err ErrTeamInviteAlreadyExist) Error() string {
30+
return fmt.Sprintf("team invite already exists [team_id: %d, email: %s]", err.TeamID, err.Email)
31+
}
32+
33+
func (err ErrTeamInviteAlreadyExist) Unwrap() error {
34+
return util.ErrAlreadyExist
35+
}
36+
37+
type ErrTeamInviteNotFound struct {
38+
Token string
39+
}
40+
41+
func IsErrTeamInviteNotFound(err error) bool {
42+
_, ok := err.(ErrTeamInviteNotFound)
43+
return ok
44+
}
45+
46+
func (err ErrTeamInviteNotFound) Error() string {
47+
return fmt.Sprintf("team invite was not found [token: %s]", err.Token)
48+
}
49+
50+
func (err ErrTeamInviteNotFound) Unwrap() error {
51+
return util.ErrNotExist
52+
}
53+
54+
// ErrUserEmailAlreadyAdded represents a "user by email already added to team" error.
55+
type ErrUserEmailAlreadyAdded struct {
56+
Email string
57+
}
58+
59+
// IsErrUserEmailAlreadyAdded checks if an error is a ErrUserEmailAlreadyAdded.
60+
func IsErrUserEmailAlreadyAdded(err error) bool {
61+
_, ok := err.(ErrUserEmailAlreadyAdded)
62+
return ok
63+
}
64+
65+
func (err ErrUserEmailAlreadyAdded) Error() string {
66+
return fmt.Sprintf("user with email already added [email: %s]", err.Email)
67+
}
68+
69+
func (err ErrUserEmailAlreadyAdded) Unwrap() error {
70+
return util.ErrAlreadyExist
71+
}
72+
73+
// TeamInvite represents an invite to a team
74+
type TeamInvite struct {
75+
ID int64 `xorm:"pk autoincr"`
76+
Token string `xorm:"UNIQUE(token) INDEX NOT NULL DEFAULT ''"`
77+
InviterID int64 `xorm:"NOT NULL DEFAULT 0"`
78+
OrgID int64 `xorm:"INDEX NOT NULL DEFAULT 0"`
79+
TeamID int64 `xorm:"UNIQUE(team_mail) INDEX NOT NULL DEFAULT 0"`
80+
Email string `xorm:"UNIQUE(team_mail) NOT NULL DEFAULT ''"`
81+
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
82+
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
83+
}
84+
85+
func CreateTeamInvite(ctx context.Context, doer *user_model.User, team *Team, email string) (*TeamInvite, error) {
86+
has, err := db.GetEngine(ctx).Exist(&TeamInvite{
87+
TeamID: team.ID,
88+
Email: email,
89+
})
90+
if err != nil {
91+
return nil, err
92+
}
93+
if has {
94+
return nil, ErrTeamInviteAlreadyExist{
95+
TeamID: team.ID,
96+
Email: email,
97+
}
98+
}
99+
100+
// check if the user is already a team member by email
101+
exist, err := db.GetEngine(ctx).
102+
Where(builder.Eq{
103+
"team_user.org_id": team.OrgID,
104+
"team_user.team_id": team.ID,
105+
"`user`.email": email,
106+
}).
107+
Join("INNER", "`user`", "`user`.id = team_user.uid").
108+
Table("team_user").
109+
Exist()
110+
if err != nil {
111+
return nil, err
112+
}
113+
114+
if exist {
115+
return nil, ErrUserEmailAlreadyAdded{
116+
Email: email,
117+
}
118+
}
119+
120+
token, err := util.CryptoRandomString(25)
121+
if err != nil {
122+
return nil, err
123+
}
124+
125+
invite := &TeamInvite{
126+
Token: token,
127+
InviterID: doer.ID,
128+
OrgID: team.OrgID,
129+
TeamID: team.ID,
130+
Email: email,
131+
}
132+
133+
return invite, db.Insert(ctx, invite)
134+
}
135+
136+
func RemoveInviteByID(ctx context.Context, inviteID, teamID int64) error {
137+
_, err := db.DeleteByBean(ctx, &TeamInvite{
138+
ID: inviteID,
139+
TeamID: teamID,
140+
})
141+
return err
142+
}
143+
144+
func GetInvitesByTeamID(ctx context.Context, teamID int64) ([]*TeamInvite, error) {
145+
invites := make([]*TeamInvite, 0, 10)
146+
return invites, db.GetEngine(ctx).
147+
Where("team_id=?", teamID).
148+
Find(&invites)
149+
}
150+
151+
func GetInviteByToken(ctx context.Context, token string) (*TeamInvite, error) {
152+
invite := &TeamInvite{}
153+
154+
has, err := db.GetEngine(ctx).Where("token=?", token).Get(invite)
155+
if err != nil {
156+
return nil, err
157+
}
158+
if !has {
159+
return nil, ErrTeamInviteNotFound{Token: token}
160+
}
161+
return invite, nil
162+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2022 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 organization_test
6+
7+
import (
8+
"testing"
9+
10+
"code.gitea.io/gitea/models/db"
11+
"code.gitea.io/gitea/models/organization"
12+
"code.gitea.io/gitea/models/unittest"
13+
user_model "code.gitea.io/gitea/models/user"
14+
15+
"github.com/stretchr/testify/assert"
16+
)
17+
18+
func TestTeamInvite(t *testing.T) {
19+
assert.NoError(t, unittest.PrepareTestDatabase())
20+
21+
team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2})
22+
23+
t.Run("MailExistsInTeam", func(t *testing.T) {
24+
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
25+
26+
// user 2 already added to team 2, should result in error
27+
_, err := organization.CreateTeamInvite(db.DefaultContext, user2, team, user2.Email)
28+
assert.Error(t, err)
29+
})
30+
31+
t.Run("CreateAndRemove", func(t *testing.T) {
32+
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
33+
34+
invite, err := organization.CreateTeamInvite(db.DefaultContext, user1, team, "[email protected]")
35+
assert.NotNil(t, invite)
36+
assert.NoError(t, err)
37+
38+
// Shouldn't allow duplicate invite
39+
_, err = organization.CreateTeamInvite(db.DefaultContext, user1, team, "[email protected]")
40+
assert.Error(t, err)
41+
42+
// should remove invite
43+
assert.NoError(t, organization.RemoveInviteByID(db.DefaultContext, invite.ID, invite.TeamID))
44+
45+
// invite should not exist
46+
_, err = organization.GetInviteByToken(db.DefaultContext, invite.Token)
47+
assert.Error(t, err)
48+
})
49+
}

models/repo.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,18 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
123123
return err
124124
}
125125

126+
if _, err := db.GetEngine(ctx).In("hook_id", builder.Select("id").From("webhook").Where(builder.Eq{"webhook.repo_id": repo.ID})).
127+
Delete(&webhook.HookTask{}); err != nil {
128+
return err
129+
}
130+
126131
if err := db.DeleteBeans(ctx,
127132
&access_model.Access{RepoID: repo.ID},
128133
&activities_model.Action{RepoID: repo.ID},
129134
&repo_model.Collaboration{RepoID: repoID},
130135
&issues_model.Comment{RefRepoID: repoID},
131136
&git_model.CommitStatus{RepoID: repoID},
132137
&git_model.DeletedBranch{RepoID: repoID},
133-
&webhook.HookTask{RepoID: repoID},
134138
&git_model.LFSLock{RepoID: repoID},
135139
&repo_model.LanguageStat{RepoID: repoID},
136140
&issues_model.Milestone{RepoID: repoID},

0 commit comments

Comments
 (0)