summaryrefslogtreecommitdiffstats
path: root/models
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2021-11-24 17:49:20 +0800
committerGitHub <noreply@github.com>2021-11-24 17:49:20 +0800
commita666829a37be6f9fd98f9e7dd1767c420f7f3b32 (patch)
tree9ab1434b759a8a2cb275a83149903a823851e309 /models
parent4e7ca946da2a2642a62f114825129bf5d7ed9196 (diff)
downloadgitea-a666829a37be6f9fd98f9e7dd1767c420f7f3b32.tar.gz
gitea-a666829a37be6f9fd98f9e7dd1767c420f7f3b32.zip
Move user related model into models/user (#17781)
* Move user related model into models/user * Fix lint for windows * Fix windows lint * Fix windows lint * Move some tests in models * Merge
Diffstat (limited to 'models')
-rw-r--r--models/access.go7
-rw-r--r--models/access_test.go13
-rw-r--r--models/action.go37
-rw-r--r--models/action_list.go7
-rw-r--r--models/action_test.go11
-rw-r--r--models/branches.go17
-rw-r--r--models/commit.go3
-rw-r--r--models/commit_status.go7
-rw-r--r--models/consistency.go5
-rw-r--r--models/db/error.go4
-rw-r--r--models/db/name.go91
-rw-r--r--models/db/search.go30
-rw-r--r--models/error.go116
-rw-r--r--models/external_login_user.go11
-rw-r--r--models/gpg_key.go8
-rw-r--r--models/gpg_key_commit_verification.go34
-rw-r--r--models/gpg_key_test.go3
-rw-r--r--models/gpg_key_verify.go3
-rw-r--r--models/helper.go5
-rw-r--r--models/helper_environment.go7
-rw-r--r--models/issue.go83
-rw-r--r--models/issue_assignees.go19
-rw-r--r--models/issue_assignees_test.go21
-rw-r--r--models/issue_comment.go61
-rw-r--r--models/issue_comment_list.go11
-rw-r--r--models/issue_comment_test.go7
-rw-r--r--models/issue_dependency.go5
-rw-r--r--models/issue_dependency_test.go3
-rw-r--r--models/issue_label.go13
-rw-r--r--models/issue_label_test.go7
-rw-r--r--models/issue_list.go11
-rw-r--r--models/issue_lock.go7
-rw-r--r--models/issue_milestone.go5
-rw-r--r--models/issue_milestone_test.go3
-rw-r--r--models/issue_reaction.go27
-rw-r--r--models/issue_reaction_test.go31
-rw-r--r--models/issue_stopwatch.go13
-rw-r--r--models/issue_stopwatch_test.go7
-rw-r--r--models/issue_test.go13
-rw-r--r--models/issue_tracked_time.go35
-rw-r--r--models/issue_tracked_time_test.go3
-rw-r--r--models/issue_watch.go3
-rw-r--r--models/issue_xref.go7
-rw-r--r--models/issue_xref_test.go11
-rw-r--r--models/lfs.go5
-rw-r--r--models/lfs_lock.go21
-rw-r--r--models/main_test.go3
-rw-r--r--models/notification.go31
-rw-r--r--models/notification_test.go9
-rw-r--r--models/org.go76
-rw-r--r--models/org_team.go17
-rw-r--r--models/org_team_test.go12
-rw-r--r--models/org_test.go73
-rw-r--r--models/project_issue.go5
-rw-r--r--models/pull.go11
-rw-r--r--models/pull_list.go5
-rw-r--r--models/pull_sign.go3
-rw-r--r--models/pull_test.go3
-rw-r--r--models/release.go19
-rw-r--r--models/repo.go82
-rw-r--r--models/repo_activity.go7
-rw-r--r--models/repo_collaboration.go15
-rw-r--r--models/repo_collaboration_test.go5
-rw-r--r--models/repo_list.go46
-rw-r--r--models/repo_permission.go31
-rw-r--r--models/repo_permission_test.go33
-rw-r--r--models/repo_sign.go7
-rw-r--r--models/repo_test.go11
-rw-r--r--models/repo_transfer.go19
-rw-r--r--models/repo_transfer_test.go9
-rw-r--r--models/repo_watch.go9
-rw-r--r--models/review.go35
-rw-r--r--models/review_test.go13
-rw-r--r--models/ssh_key.go7
-rw-r--r--models/ssh_key_deploy.go5
-rw-r--r--models/ssh_key_principals.go2
-rw-r--r--models/star.go7
-rw-r--r--models/statistic.go2
-rw-r--r--models/task.go21
-rw-r--r--models/user.go1416
-rw-r--r--models/user/avatar.go (renamed from models/user_avatar.go)10
-rw-r--r--models/user/error.go80
-rw-r--r--models/user/main_test.go3
-rw-r--r--models/user/search.go167
-rw-r--r--models/user/user.go1125
-rw-r--r--models/user/user_test.go355
-rw-r--r--models/user_email.go24
-rw-r--r--models/user_email_test.go4
-rw-r--r--models/user_heatmap.go7
-rw-r--r--models/user_heatmap_test.go5
-rw-r--r--models/user_test.go411
-rw-r--r--models/userlist.go15
-rw-r--r--models/wiki.go3
93 files changed, 2642 insertions, 2467 deletions
diff --git a/models/access.go b/models/access.go
index 7af88e1b4a..01b37dd7ae 100644
--- a/models/access.go
+++ b/models/access.go
@@ -9,6 +9,7 @@ import (
"fmt"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
)
@@ -76,7 +77,7 @@ func init() {
db.RegisterModel(new(Access))
}
-func accessLevel(e db.Engine, user *User, repo *Repository) (AccessMode, error) {
+func accessLevel(e db.Engine, user *user_model.User, repo *Repository) (AccessMode, error) {
mode := AccessModeNone
var userID int64
restricted := false
@@ -116,12 +117,12 @@ func maxAccessMode(modes ...AccessMode) AccessMode {
}
type userAccess struct {
- User *User
+ User *user_model.User
Mode AccessMode
}
// updateUserAccess updates an access map so that user has at least mode
-func updateUserAccess(accessMap map[int64]*userAccess, user *User, mode AccessMode) {
+func updateUserAccess(accessMap map[int64]*userAccess, user *user_model.User, mode AccessMode) {
if ua, ok := accessMap[user.ID]; ok {
ua.Mode = maxAccessMode(ua.Mode, mode)
} else {
diff --git a/models/access_test.go b/models/access_test.go
index 81e36ed2e0..a2fd05a033 100644
--- a/models/access_test.go
+++ b/models/access_test.go
@@ -9,6 +9,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"github.com/stretchr/testify/assert"
)
@@ -16,9 +17,9 @@ import (
func TestAccessLevel(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- user2 := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
- user5 := unittest.AssertExistsAndLoadBean(t, &User{ID: 5}).(*User)
- user29 := unittest.AssertExistsAndLoadBean(t, &User{ID: 29}).(*User)
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
+ user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User)
+ user29 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 29}).(*user_model.User)
// A public repository owned by User 2
repo1 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
assert.False(t, repo1.IsPrivate)
@@ -67,8 +68,8 @@ func TestAccessLevel(t *testing.T) {
func TestHasAccess(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- user1 := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
- user2 := unittest.AssertExistsAndLoadBean(t, &User{ID: 5}).(*User)
+ user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User)
// A public repository owned by User 2
repo1 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
assert.False(t, repo1.IsPrivate)
@@ -125,7 +126,7 @@ func TestRepository_RecalculateAccesses2(t *testing.T) {
func TestRepository_RecalculateAccesses3(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
team5 := unittest.AssertExistsAndLoadBean(t, &Team{ID: 5}).(*Team)
- user29 := unittest.AssertExistsAndLoadBean(t, &User{ID: 29}).(*User)
+ user29 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 29}).(*user_model.User)
has, err := db.GetEngine(db.DefaultContext).Get(&Access{UserID: 29, RepoID: 23})
assert.NoError(t, err)
diff --git a/models/action.go b/models/action.go
index d790cd6678..66fa78f268 100644
--- a/models/action.go
+++ b/models/action.go
@@ -14,6 +14,7 @@ import (
"time"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
@@ -63,13 +64,13 @@ type Action struct {
ID int64 `xorm:"pk autoincr"`
UserID int64 `xorm:"INDEX"` // Receiver user id.
OpType ActionType
- ActUserID int64 `xorm:"INDEX"` // Action user id.
- ActUser *User `xorm:"-"`
- RepoID int64 `xorm:"INDEX"`
- Repo *Repository `xorm:"-"`
- CommentID int64 `xorm:"INDEX"`
- Comment *Comment `xorm:"-"`
- IsDeleted bool `xorm:"INDEX NOT NULL DEFAULT false"`
+ ActUserID int64 `xorm:"INDEX"` // Action user id.
+ ActUser *user_model.User `xorm:"-"`
+ RepoID int64 `xorm:"INDEX"`
+ Repo *Repository `xorm:"-"`
+ CommentID int64 `xorm:"INDEX"`
+ Comment *Comment `xorm:"-"`
+ IsDeleted bool `xorm:"INDEX NOT NULL DEFAULT false"`
RefName string
IsPrivate bool `xorm:"INDEX NOT NULL DEFAULT false"`
Content string `xorm:"TEXT"`
@@ -91,11 +92,11 @@ func (a *Action) LoadActUser() {
return
}
var err error
- a.ActUser, err = GetUserByID(a.ActUserID)
+ a.ActUser, err = user_model.GetUserByID(a.ActUserID)
if err == nil {
return
- } else if IsErrUserNotExist(err) {
- a.ActUser = NewGhostUser()
+ } else if user_model.IsErrUserNotExist(err) {
+ a.ActUser = user_model.NewGhostUser()
} else {
log.Error("GetUserByID(%d): %v", a.ActUserID, err)
}
@@ -294,13 +295,13 @@ func (a *Action) GetIssueContent() string {
// GetFeedsOptions options for retrieving feeds
type GetFeedsOptions struct {
- RequestedUser *User // the user we want activity for
- RequestedTeam *Team // the team we want activity for
- Actor *User // the user viewing the activity
- IncludePrivate bool // include private actions
- OnlyPerformedBy bool // only actions performed by requested user
- IncludeDeleted bool // include deleted actions
- Date string // the day we want activity for: YYYY-MM-DD
+ RequestedUser *user_model.User // the user we want activity for
+ RequestedTeam *Team // the team we want activity for
+ Actor *user_model.User // the user viewing the activity
+ IncludePrivate bool // include private actions
+ OnlyPerformedBy bool // only actions performed by requested user
+ IncludeDeleted bool // include deleted actions
+ Date string // the day we want activity for: YYYY-MM-DD
}
// GetFeeds returns actions according to the provided options
@@ -327,7 +328,7 @@ func GetFeeds(opts GetFeedsOptions) ([]*Action, error) {
return actions, nil
}
-func activityReadable(user, doer *User) bool {
+func activityReadable(user, doer *user_model.User) bool {
var doerID int64
if doer != nil {
doerID = doer.ID
diff --git a/models/action_list.go b/models/action_list.go
index 69e6aa7312..4f2024cfcf 100644
--- a/models/action_list.go
+++ b/models/action_list.go
@@ -8,6 +8,7 @@ import (
"fmt"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
)
// ActionList defines a list of actions
@@ -23,13 +24,13 @@ func (actions ActionList) getUserIDs() []int64 {
return keysInt64(userIDs)
}
-func (actions ActionList) loadUsers(e db.Engine) ([]*User, error) {
+func (actions ActionList) loadUsers(e db.Engine) ([]*user_model.User, error) {
if len(actions) == 0 {
return nil, nil
}
userIDs := actions.getUserIDs()
- userMaps := make(map[int64]*User, len(userIDs))
+ userMaps := make(map[int64]*user_model.User, len(userIDs))
err := e.
In("id", userIDs).
Find(&userMaps)
@@ -44,7 +45,7 @@ func (actions ActionList) loadUsers(e db.Engine) ([]*User, error) {
}
// LoadUsers loads actions' all users
-func (actions ActionList) LoadUsers() ([]*User, error) {
+func (actions ActionList) LoadUsers() ([]*user_model.User, error) {
return actions.loadUsers(db.GetEngine(db.DefaultContext))
}
diff --git a/models/action_test.go b/models/action_test.go
index 87bbcf3fb7..8ab88bb97e 100644
--- a/models/action_test.go
+++ b/models/action_test.go
@@ -9,6 +9,7 @@ import (
"testing"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"github.com/stretchr/testify/assert"
@@ -17,7 +18,7 @@ import (
func TestAction_GetRepoPath(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
repo := unittest.AssertExistsAndLoadBean(t, &Repository{}).(*Repository)
- owner := unittest.AssertExistsAndLoadBean(t, &User{ID: repo.OwnerID}).(*User)
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
action := &Action{RepoID: repo.ID}
assert.Equal(t, path.Join(owner.Name, repo.Name), action.GetRepoPath())
}
@@ -25,7 +26,7 @@ func TestAction_GetRepoPath(t *testing.T) {
func TestAction_GetRepoLink(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
repo := unittest.AssertExistsAndLoadBean(t, &Repository{}).(*Repository)
- owner := unittest.AssertExistsAndLoadBean(t, &User{ID: repo.OwnerID}).(*User)
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
action := &Action{RepoID: repo.ID}
setting.AppSubURL = "/suburl"
expected := path.Join(setting.AppSubURL, owner.Name, repo.Name)
@@ -35,7 +36,7 @@ func TestAction_GetRepoLink(t *testing.T) {
func TestGetFeeds(t *testing.T) {
// test with an individual user
assert.NoError(t, unittest.PrepareTestDatabase())
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
actions, err := GetFeeds(GetFeedsOptions{
RequestedUser: user,
@@ -63,8 +64,8 @@ func TestGetFeeds(t *testing.T) {
func TestGetFeeds2(t *testing.T) {
// test with an organization user
assert.NoError(t, unittest.PrepareTestDatabase())
- org := unittest.AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
actions, err := GetFeeds(GetFeedsOptions{
RequestedUser: org,
diff --git a/models/branches.go b/models/branches.go
index fc0da58e38..f5ed570ea2 100644
--- a/models/branches.go
+++ b/models/branches.go
@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unit"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
@@ -69,7 +70,7 @@ func (protectBranch *ProtectedBranch) CanUserPush(userID int64) bool {
}
if !protectBranch.EnableWhitelist {
- if user, err := GetUserByID(userID); err != nil {
+ if user, err := user_model.GetUserByID(userID); err != nil {
log.Error("GetUserByID: %v", err)
return false
} else if repo, err := GetRepositoryByID(protectBranch.RepoID); err != nil {
@@ -123,11 +124,11 @@ func (protectBranch *ProtectedBranch) IsUserMergeWhitelisted(userID int64, permi
}
// IsUserOfficialReviewer check if user is official reviewer for the branch (counts towards required approvals)
-func (protectBranch *ProtectedBranch) IsUserOfficialReviewer(user *User) (bool, error) {
+func (protectBranch *ProtectedBranch) IsUserOfficialReviewer(user *user_model.User) (bool, error) {
return protectBranch.isUserOfficialReviewer(db.GetEngine(db.DefaultContext), user)
}
-func (protectBranch *ProtectedBranch) isUserOfficialReviewer(e db.Engine, user *User) (bool, error) {
+func (protectBranch *ProtectedBranch) isUserOfficialReviewer(e db.Engine, user *user_model.User) (bool, error) {
repo, err := getRepositoryByID(e, protectBranch.RepoID)
if err != nil {
return false, err
@@ -446,7 +447,7 @@ func updateUserWhitelist(repo *Repository, currentWhitelist, newWhitelist []int6
whitelist = make([]int64, 0, len(newWhitelist))
for _, userID := range newWhitelist {
- user, err := GetUserByID(userID)
+ user, err := user_model.GetUserByID(userID)
if err != nil {
return nil, fmt.Errorf("GetUserByID [user_id: %d, repo_id: %d]: %v", userID, repo.ID, err)
}
@@ -511,7 +512,7 @@ type DeletedBranch struct {
Name string `xorm:"UNIQUE(s) NOT NULL"`
Commit string `xorm:"UNIQUE(s) NOT NULL"`
DeletedByID int64 `xorm:"INDEX"`
- DeletedBy *User `xorm:"-"`
+ DeletedBy *user_model.User `xorm:"-"`
DeletedUnix timeutil.TimeStamp `xorm:"INDEX created"`
}
@@ -564,11 +565,11 @@ func (repo *Repository) RemoveDeletedBranch(id int64) (err error) {
}
// LoadUser loads the user that deleted the branch
-// When there's no user found it returns a NewGhostUser
+// When there's no user found it returns a user_model.NewGhostUser
func (deletedBranch *DeletedBranch) LoadUser() {
- user, err := GetUserByID(deletedBranch.DeletedByID)
+ user, err := user_model.GetUserByID(deletedBranch.DeletedByID)
if err != nil {
- user = NewGhostUser()
+ user = user_model.NewGhostUser()
}
deletedBranch.DeletedBy = user
}
diff --git a/models/commit.go b/models/commit.go
index 474825820a..12aecdae84 100644
--- a/models/commit.go
+++ b/models/commit.go
@@ -5,6 +5,7 @@
package models
import (
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
)
@@ -12,7 +13,7 @@ import (
func ConvertFromGitCommit(commits []*git.Commit, repo *Repository) []*SignCommitWithStatuses {
return ParseCommitsWithStatus(
ParseCommitsWithSignature(
- ValidateCommitsWithEmails(commits),
+ user_model.ValidateCommitsWithEmails(commits),
repo,
),
repo,
diff --git a/models/commit_status.go b/models/commit_status.go
index df34b93ec5..bba39fde87 100644
--- a/models/commit_status.go
+++ b/models/commit_status.go
@@ -12,6 +12,7 @@ import (
"time"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
@@ -32,7 +33,7 @@ type CommitStatus struct {
Description string `xorm:"TEXT"`
ContextHash string `xorm:"char(40) index"`
Context string `xorm:"TEXT"`
- Creator *User `xorm:"-"`
+ Creator *user_model.User `xorm:"-"`
CreatorID int64
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
@@ -127,7 +128,7 @@ func (status *CommitStatus) loadAttributes(e db.Engine) (err error) {
}
}
if status.Creator == nil && status.CreatorID > 0 {
- status.Creator, err = getUserByID(e, status.CreatorID)
+ status.Creator, err = user_model.GetUserByIDEngine(e, status.CreatorID)
if err != nil {
return fmt.Errorf("getUserByID [%d]: %v", status.CreatorID, err)
}
@@ -274,7 +275,7 @@ func FindRepoRecentCommitStatusContexts(repoID int64, before time.Duration) ([]s
// NewCommitStatusOptions holds options for creating a CommitStatus
type NewCommitStatusOptions struct {
Repo *Repository
- Creator *User
+ Creator *user_model.User
SHA string
CommitStatus *CommitStatus
}
diff --git a/models/consistency.go b/models/consistency.go
index ba669628b9..d16e7f5e99 100644
--- a/models/consistency.go
+++ b/models/consistency.go
@@ -7,6 +7,7 @@ package models
import (
admin_model "code.gitea.io/gitea/models/admin"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"xorm.io/builder"
)
@@ -169,12 +170,12 @@ func FixNullArchivedRepository() (int64, error) {
// CountWrongUserType count OrgUser who have wrong type
func CountWrongUserType() (int64, error) {
- return db.GetEngine(db.DefaultContext).Where(builder.Eq{"type": 0}.And(builder.Neq{"num_teams": 0})).Count(new(User))
+ return db.GetEngine(db.DefaultContext).Where(builder.Eq{"type": 0}.And(builder.Neq{"num_teams": 0})).Count(new(user_model.User))
}
// FixWrongUserType fix OrgUser who have wrong type
func FixWrongUserType() (int64, error) {
- return db.GetEngine(db.DefaultContext).Where(builder.Eq{"type": 0}.And(builder.Neq{"num_teams": 0})).Cols("type").NoAutoTime().Update(&User{Type: 1})
+ return db.GetEngine(db.DefaultContext).Where(builder.Eq{"type": 0}.And(builder.Neq{"num_teams": 0})).Cols("type").NoAutoTime().Update(&user_model.User{Type: 1})
}
// CountCommentTypeLabelWithEmptyLabel count label comments with empty label
diff --git a/models/db/error.go b/models/db/error.go
index 675247ed87..adaeedcc09 100644
--- a/models/db/error.go
+++ b/models/db/error.go
@@ -4,7 +4,9 @@
package db
-import "fmt"
+import (
+ "fmt"
+)
// ErrCancelled represents an error due to context cancellation
type ErrCancelled struct {
diff --git a/models/db/name.go b/models/db/name.go
new file mode 100644
index 0000000000..9c9d18f184
--- /dev/null
+++ b/models/db/name.go
@@ -0,0 +1,91 @@
+// Copyright 2021 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package db
+
+import (
+ "errors"
+ "fmt"
+ "regexp"
+ "strings"
+ "unicode/utf8"
+)
+
+var (
+ // ErrNameEmpty name is empty error
+ ErrNameEmpty = errors.New("Name is empty")
+
+ // AlphaDashDotPattern characters prohibited in a user name (anything except A-Za-z0-9_.-)
+ AlphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
+)
+
+// ErrNameReserved represents a "reserved name" error.
+type ErrNameReserved struct {
+ Name string
+}
+
+// IsErrNameReserved checks if an error is a ErrNameReserved.
+func IsErrNameReserved(err error) bool {
+ _, ok := err.(ErrNameReserved)
+ return ok
+}
+
+func (err ErrNameReserved) Error() string {
+ return fmt.Sprintf("name is reserved [name: %s]", err.Name)
+}
+
+// ErrNamePatternNotAllowed represents a "pattern not allowed" error.
+type ErrNamePatternNotAllowed struct {
+ Pattern string
+}
+
+// IsErrNamePatternNotAllowed checks if an error is an ErrNamePatternNotAllowed.
+func IsErrNamePatternNotAllowed(err error) bool {
+ _, ok := err.(ErrNamePatternNotAllowed)
+ return ok
+}
+
+func (err ErrNamePatternNotAllowed) Error() string {
+ return fmt.Sprintf("name pattern is not allowed [pattern: %s]", err.Pattern)
+}
+
+// ErrNameCharsNotAllowed represents a "character not allowed in name" error.
+type ErrNameCharsNotAllowed struct {
+ Name string
+}
+
+// IsErrNameCharsNotAllowed checks if an error is an ErrNameCharsNotAllowed.
+func IsErrNameCharsNotAllowed(err error) bool {
+ _, ok := err.(ErrNameCharsNotAllowed)
+ return ok
+}
+
+func (err ErrNameCharsNotAllowed) Error() string {
+ return fmt.Sprintf("User name is invalid [%s]: must be valid alpha or numeric or dash(-_) or dot characters", err.Name)
+}
+
+// IsUsableName checks if name is reserved or pattern of name is not allowed
+// based on given reserved names and patterns.
+// Names are exact match, patterns can be prefix or suffix match with placeholder '*'.
+func IsUsableName(names, patterns []string, name string) error {
+ name = strings.TrimSpace(strings.ToLower(name))
+ if utf8.RuneCountInString(name) == 0 {
+ return ErrNameEmpty
+ }
+
+ for i := range names {
+ if name == names[i] {
+ return ErrNameReserved{name}
+ }
+ }
+
+ for _, pat := range patterns {
+ if pat[0] == '*' && strings.HasSuffix(name, pat[1:]) ||
+ (pat[len(pat)-1] == '*' && strings.HasPrefix(name, pat[:len(pat)-1])) {
+ return ErrNamePatternNotAllowed{pat}
+ }
+ }
+
+ return nil
+}
diff --git a/models/db/search.go b/models/db/search.go
new file mode 100644
index 0000000000..704a48ed1e
--- /dev/null
+++ b/models/db/search.go
@@ -0,0 +1,30 @@
+// Copyright 2021 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package db
+
+// SearchOrderBy is used to sort the result
+type SearchOrderBy string
+
+func (s SearchOrderBy) String() string {
+ return string(s)
+}
+
+// Strings for sorting result
+const (
+ SearchOrderByAlphabetically SearchOrderBy = "name ASC"
+ SearchOrderByAlphabeticallyReverse SearchOrderBy = "name DESC"
+ SearchOrderByLeastUpdated SearchOrderBy = "updated_unix ASC"
+ SearchOrderByRecentUpdated SearchOrderBy = "updated_unix DESC"
+ SearchOrderByOldest SearchOrderBy = "created_unix ASC"
+ SearchOrderByNewest SearchOrderBy = "created_unix DESC"
+ SearchOrderBySize SearchOrderBy = "size ASC"
+ SearchOrderBySizeReverse SearchOrderBy = "size DESC"
+ SearchOrderByID SearchOrderBy = "id ASC"
+ SearchOrderByIDReverse SearchOrderBy = "id DESC"
+ SearchOrderByStars SearchOrderBy = "num_stars ASC"
+ SearchOrderByStarsReverse SearchOrderBy = "num_stars DESC"
+ SearchOrderByForks SearchOrderBy = "num_forks ASC"
+ SearchOrderByForksReverse SearchOrderBy = "num_forks DESC"
+)
diff --git a/models/error.go b/models/error.go
index d0691c1c69..5ef96683e7 100644
--- a/models/error.go
+++ b/models/error.go
@@ -26,51 +26,6 @@ func (err ErrNotExist) Error() string {
return fmt.Sprintf("record does not exist [id: %d]", err.ID)
}
-// ErrNameReserved represents a "reserved name" error.
-type ErrNameReserved struct {
- Name string
-}
-
-// IsErrNameReserved checks if an error is a ErrNameReserved.
-func IsErrNameReserved(err error) bool {
- _, ok := err.(ErrNameReserved)
- return ok
-}
-
-func (err ErrNameReserved) Error() string {
- return fmt.Sprintf("name is reserved [name: %s]", err.Name)
-}
-
-// ErrNamePatternNotAllowed represents a "pattern not allowed" error.
-type ErrNamePatternNotAllowed struct {
- Pattern string
-}
-
-// IsErrNamePatternNotAllowed checks if an error is an ErrNamePatternNotAllowed.
-func IsErrNamePatternNotAllowed(err error) bool {
- _, ok := err.(ErrNamePatternNotAllowed)
- return ok
-}
-
-func (err ErrNamePatternNotAllowed) Error() string {
- return fmt.Sprintf("name pattern is not allowed [pattern: %s]", err.Pattern)
-}
-
-// ErrNameCharsNotAllowed represents a "character not allowed in name" error.
-type ErrNameCharsNotAllowed struct {
- Name string
-}
-
-// IsErrNameCharsNotAllowed checks if an error is an ErrNameCharsNotAllowed.
-func IsErrNameCharsNotAllowed(err error) bool {
- _, ok := err.(ErrNameCharsNotAllowed)
- return ok
-}
-
-func (err ErrNameCharsNotAllowed) Error() string {
- return fmt.Sprintf("User name is invalid [%s]: must be valid alpha or numeric or dash(-_) or dot characters", err.Name)
-}
-
// ErrSSHDisabled represents an "SSH disabled" error.
type ErrSSHDisabled struct{}
@@ -84,77 +39,6 @@ func (err ErrSSHDisabled) Error() string {
return "SSH is disabled"
}
-// ____ ___
-// | | \______ ___________
-// | | / ___// __ \_ __ \
-// | | /\___ \\ ___/| | \/
-// |______//____ >\___ >__|
-// \/ \/
-
-// ErrUserAlreadyExist represents a "user already exists" error.
-type ErrUserAlreadyExist struct {
- Name string
-}
-
-// IsErrUserAlreadyExist checks if an error is a ErrUserAlreadyExists.
-func IsErrUserAlreadyExist(err error) bool {
- _, ok := err.(ErrUserAlreadyExist)
- return ok
-}
-
-func (err ErrUserAlreadyExist) Error() string {
- return fmt.Sprintf("user already exists [name: %s]", err.Name)
-}
-
-// ErrUserNotExist represents a "UserNotExist" kind of error.
-type ErrUserNotExist struct {
- UID int64
- Name string
- KeyID int64
-}
-
-// IsErrUserNotExist checks if an error is a ErrUserNotExist.
-func IsErrUserNotExist(err error) bool {
- _, ok := err.(ErrUserNotExist)
- return ok
-}
-
-func (err ErrUserNotExist) Error() string {
- return fmt.Sprintf("user does not exist [uid: %d, name: %s, keyid: %d]", err.UID, err.Name, err.KeyID)
-}
-
-// ErrUserProhibitLogin represents a "ErrUserProhibitLogin" kind of error.
-type ErrUserProhibitLogin struct {
- UID int64
- Name string
-}
-
-// IsErrUserProhibitLogin checks if an error is a ErrUserProhibitLogin
-func IsErrUserProhibitLogin(err error) bool {
- _, ok := err.(ErrUserProhibitLogin)
- return ok
-}
-
-func (err ErrUserProhibitLogin) Error() string {
- return fmt.Sprintf("user is not allowed login [uid: %d, name: %s]", err.UID, err.Name)
-}
-
-// ErrUserInactive represents a "ErrUserInactive" kind of error.
-type ErrUserInactive struct {
- UID int64
- Name string
-}
-
-// IsErrUserInactive checks if an error is a ErrUserInactive
-func IsErrUserInactive(err error) bool {
- _, ok := err.(ErrUserInactive)
- return ok
-}
-
-func (err ErrUserInactive) Error() string {
- return fmt.Sprintf("user is inactive [uid: %d, name: %s]", err.UID, err.Name)
-}
-
// ErrUserOwnRepos represents a "UserOwnRepos" kind of error.
type ErrUserOwnRepos struct {
UID int64
diff --git a/models/external_login_user.go b/models/external_login_user.go
index 6b023a4cb2..4be1307225 100644
--- a/models/external_login_user.go
+++ b/models/external_login_user.go
@@ -9,6 +9,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/login"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/structs"
"github.com/markbates/goth"
@@ -46,7 +47,7 @@ func GetExternalLogin(externalLoginUser *ExternalLoginUser) (bool, error) {
}
// ListAccountLinks returns a map with the ExternalLoginUser and its LoginSource
-func ListAccountLinks(user *User) ([]*ExternalLoginUser, error) {
+func ListAccountLinks(user *user_model.User) ([]*ExternalLoginUser, error) {
externalAccounts := make([]*ExternalLoginUser, 0, 5)
err := db.GetEngine(db.DefaultContext).Where("user_id=?", user.ID).
Desc("login_source_id").
@@ -59,7 +60,7 @@ func ListAccountLinks(user *User) ([]*ExternalLoginUser, error) {
}
// LinkExternalToUser link the external user to the user
-func LinkExternalToUser(user *User, externalLoginUser *ExternalLoginUser) error {
+func LinkExternalToUser(user *user_model.User, externalLoginUser *ExternalLoginUser) error {
has, err := db.GetEngine(db.DefaultContext).Where("external_id=? AND login_source_id=?", externalLoginUser.ExternalID, externalLoginUser.LoginSourceID).
NoAutoCondition().
Exist(externalLoginUser)
@@ -74,7 +75,7 @@ func LinkExternalToUser(user *User, externalLoginUser *ExternalLoginUser) error
}
// RemoveAccountLink will remove all external login sources for the given user
-func RemoveAccountLink(user *User, loginSourceID int64) (int64, error) {
+func RemoveAccountLink(user *user_model.User, loginSourceID int64) (int64, error) {
deleted, err := db.GetEngine(db.DefaultContext).Delete(&ExternalLoginUser{UserID: user.ID, LoginSourceID: loginSourceID})
if err != nil {
return deleted, err
@@ -86,7 +87,7 @@ func RemoveAccountLink(user *User, loginSourceID int64) (int64, error) {
}
// removeAllAccountLinks will remove all external login sources for the given user
-func removeAllAccountLinks(e db.Engine, user *User) error {
+func removeAllAccountLinks(e db.Engine, user *user_model.User) error {
_, err := e.Delete(&ExternalLoginUser{UserID: user.ID})
return err
}
@@ -106,7 +107,7 @@ func GetUserIDByExternalUserID(provider, userID string) (int64, error) {
}
// UpdateExternalUser updates external user's information
-func UpdateExternalUser(user *User, gothUser goth.User) error {
+func UpdateExternalUser(user *user_model.User, gothUser goth.User) error {
loginSource, err := login.GetActiveOAuth2LoginSourceByName(gothUser.Provider)
if err != nil {
return err
diff --git a/models/gpg_key.go b/models/gpg_key.go
index 357dc2b964..ce27a9237e 100644
--- a/models/gpg_key.go
+++ b/models/gpg_key.go
@@ -214,7 +214,7 @@ func deleteGPGKey(e db.Engine, keyID string) (int64, error) {
}
// DeleteGPGKey deletes GPG key information in database.
-func DeleteGPGKey(doer *User, id int64) (err error) {
+func DeleteGPGKey(doer *user_model.User, id int64) (err error) {
key, err := GetGPGKeyByID(id)
if err != nil {
if IsErrGPGKeyNotExist(err) {
@@ -244,7 +244,7 @@ func DeleteGPGKey(doer *User, id int64) (err error) {
func checkKeyEmails(email string, keys ...*GPGKey) (bool, string) {
uid := int64(0)
var userEmails []*user_model.EmailAddress
- var user *User
+ var user *user_model.User
for _, key := range keys {
for _, e := range key.Emails {
if e.IsActivated && (email == "" || strings.EqualFold(e.Email, email)) {
@@ -255,8 +255,8 @@ func checkKeyEmails(email string, keys ...*GPGKey) (bool, string) {
if uid != key.OwnerID {
userEmails, _ = user_model.GetEmailAddresses(key.OwnerID)
uid = key.OwnerID
- user = &User{ID: uid}
- _, _ = GetUser(user)
+ user = &user_model.User{ID: uid}
+ _, _ = user_model.GetUser(user)
}
for _, e := range userEmails {
if e.IsActivated && (email == "" || strings.EqualFold(e.Email, email)) {
diff --git a/models/gpg_key_commit_verification.go b/models/gpg_key_commit_verification.go
index 6da65d3697..5eeeb69ef5 100644
--- a/models/gpg_key_commit_verification.go
+++ b/models/gpg_key_commit_verification.go
@@ -44,8 +44,8 @@ type CommitVerification struct {
Verified bool
Warning bool
Reason string
- SigningUser *User
- CommittingUser *User
+ SigningUser *user_model.User
+ CommittingUser *user_model.User
SigningEmail string
SigningKey *GPGKey
TrustStatus string
@@ -54,7 +54,7 @@ type CommitVerification struct {
// SignCommit represents a commit with validation of signature.
type SignCommit struct {
Verification *CommitVerification
- *UserCommit
+ *user_model.UserCommit
}
const (
@@ -69,7 +69,7 @@ const (
)
// ParseCommitsWithSignature checks if signaute of commits are corresponding to users gpg keys.
-func ParseCommitsWithSignature(oldCommits []*UserCommit, repository *Repository) []*SignCommit {
+func ParseCommitsWithSignature(oldCommits []*user_model.UserCommit, repository *Repository) []*SignCommit {
newCommits := make([]*SignCommit, 0, len(oldCommits))
keyMap := map[string]bool{}
@@ -88,19 +88,19 @@ func ParseCommitsWithSignature(oldCommits []*UserCommit, repository *Repository)
// ParseCommitWithSignature check if signature is good against keystore.
func ParseCommitWithSignature(c *git.Commit) *CommitVerification {
- var committer *User
+ var committer *user_model.User
if c.Committer != nil {
var err error
// Find Committer account
- committer, err = GetUserByEmail(c.Committer.Email) // This finds the user by primary email or activated email so commit will not be valid if email is not
- if err != nil { // Skipping not user for committer
- committer = &User{
+ committer, err = user_model.GetUserByEmail(c.Committer.Email) // This finds the user by primary email or activated email so commit will not be valid if email is not
+ if err != nil { // Skipping not user for committer
+ committer = &user_model.User{
Name: c.Committer.Name,
Email: c.Committer.Email,
}
// We can expect this to often be an ErrUserNotExist. in the case
// it is not, however, it is important to log it.
- if !IsErrUserNotExist(err) {
+ if !user_model.IsErrUserNotExist(err) {
log.Error("GetUserByEmail: %v", err)
return &CommitVerification{
CommittingUser: committer,
@@ -250,7 +250,7 @@ func ParseCommitWithSignature(c *git.Commit) *CommitVerification {
}
}
-func verifyWithGPGSettings(gpgSettings *git.GPGSettings, sig *packet.Signature, payload string, committer *User, keyID string) *CommitVerification {
+func verifyWithGPGSettings(gpgSettings *git.GPGSettings, sig *packet.Signature, payload string, committer *user_model.User, keyID string) *CommitVerification {
// First try to find the key in the db
if commitVerification := hashAndVerifyForKeyID(sig, payload, committer, gpgSettings.KeyID, gpgSettings.Name, gpgSettings.Email); commitVerification != nil {
return commitVerification
@@ -296,7 +296,7 @@ func verifyWithGPGSettings(gpgSettings *git.GPGSettings, sig *packet.Signature,
KeyID: subKey.PublicKey.KeyIdString(),
})
}
- if commitVerification := hashAndVerifyWithSubKeysCommitVerification(sig, payload, k, committer, &User{
+ if commitVerification := hashAndVerifyWithSubKeysCommitVerification(sig, payload, k, committer, &user_model.User{
Name: gpgSettings.Name,
Email: gpgSettings.Email,
}, gpgSettings.Email); commitVerification != nil {
@@ -357,7 +357,7 @@ func hashAndVerifyWithSubKeys(sig *packet.Signature, payload string, k *GPGKey)
return nil, nil
}
-func hashAndVerifyWithSubKeysCommitVerification(sig *packet.Signature, payload string, k *GPGKey, committer, signer *User, email string) *CommitVerification {
+func hashAndVerifyWithSubKeysCommitVerification(sig *packet.Signature, payload string, k *GPGKey, committer, signer *user_model.User, email string) *CommitVerification {
key, err := hashAndVerifyWithSubKeys(sig, payload, k)
if err != nil { // Skipping failed to generate hash
return &CommitVerification{
@@ -380,7 +380,7 @@ func hashAndVerifyWithSubKeysCommitVerification(sig *packet.Signature, payload s
return nil
}
-func hashAndVerifyForKeyID(sig *packet.Signature, payload string, committer *User, keyID, name, email string) *CommitVerification {
+func hashAndVerifyForKeyID(sig *packet.Signature, payload string, committer *user_model.User, keyID, name, email string) *CommitVerification {
if keyID == "" {
return nil
}
@@ -415,16 +415,16 @@ func hashAndVerifyForKeyID(sig *packet.Signature, payload string, committer *Use
continue
}
- signer := &User{
+ signer := &user_model.User{
Name: name,
Email: email,
}
if key.OwnerID != 0 {
- owner, err := GetUserByID(key.OwnerID)
+ owner, err := user_model.GetUserByID(key.OwnerID)
if err == nil {
signer = owner
- } else if !IsErrUserNotExist(err) {
- log.Error("Failed to GetUserByID: %d for key ID: %d (%s) %v", key.OwnerID, key.ID, key.KeyID, err)
+ } else if !user_model.IsErrUserNotExist(err) {
+ log.Error("Failed to user_model.GetUserByID: %d for key ID: %d (%s) %v", key.OwnerID, key.ID, key.KeyID, err)
return &CommitVerification{
CommittingUser: committer,
Verified: false,
diff --git a/models/gpg_key_test.go b/models/gpg_key_test.go
index e5f4960b76..8f51c146aa 100644
--- a/models/gpg_key_test.go
+++ b/models/gpg_key_test.go
@@ -9,6 +9,7 @@ import (
"time"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/timeutil"
"github.com/stretchr/testify/assert"
@@ -195,7 +196,7 @@ Unknown GPG key with good email
func TestCheckGPGUserEmail(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- _ = unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
+ _ = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
testEmailWithUpperCaseLetters := `-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1
diff --git a/models/gpg_key_verify.go b/models/gpg_key_verify.go
index 1c6b79ec5f..1824086021 100644
--- a/models/gpg_key_verify.go
+++ b/models/gpg_key_verify.go
@@ -9,6 +9,7 @@ import (
"time"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log"
)
@@ -104,7 +105,7 @@ func VerifyGPGKey(ownerID int64, keyID, token, signature string) (string, error)
}
// VerificationToken returns token for the user that will be valid in minutes (time)
-func VerificationToken(user *User, minutes int) string {
+func VerificationToken(user *user_model.User, minutes int) string {
return base.EncodeSha256(
time.Now().Truncate(1*time.Minute).Add(time.Duration(minutes)*time.Minute).Format(time.RFC1123Z) + ":" +
user.CreatedUnix.FormatLong() + ":" +
diff --git a/models/helper.go b/models/helper.go
index 710c15a978..41dd1ccd53 100644
--- a/models/helper.go
+++ b/models/helper.go
@@ -7,6 +7,7 @@ package models
import (
"encoding/binary"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/json"
)
@@ -26,8 +27,8 @@ func valuesRepository(m map[int64]*Repository) []*Repository {
return values
}
-func valuesUser(m map[int64]*User) []*User {
- values := make([]*User, 0, len(m))
+func valuesUser(m map[int64]*user_model.User) []*user_model.User {
+ values := make([]*user_model.User, 0, len(m))
for _, v := range m {
values = append(values, v)
}
diff --git a/models/helper_environment.go b/models/helper_environment.go
index 922a5790be..3e98f60ffd 100644
--- a/models/helper_environment.go
+++ b/models/helper_environment.go
@@ -9,6 +9,7 @@ import (
"os"
"strings"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
)
@@ -32,19 +33,19 @@ const (
// It is recommended to avoid using this unless you are pushing within a transaction
// or if you absolutely are sure that post-receive and pre-receive will do nothing
// We provide the full pushing-environment for other hook providers
-func InternalPushingEnvironment(doer *User, repo *Repository) []string {
+func InternalPushingEnvironment(doer *user_model.User, repo *Repository) []string {
return append(PushingEnvironment(doer, repo),
EnvIsInternal+"=true",
)
}
// PushingEnvironment returns an os environment to allow hooks to work on push
-func PushingEnvironment(doer *User, repo *Repository) []string {
+func PushingEnvironment(doer *user_model.User, repo *Repository) []string {
return FullPushingEnvironment(doer, doer, repo, repo.Name, 0)
}
// FullPushingEnvironment returns an os environment to allow hooks to work on push
-func FullPushingEnvironment(author, committer *User, repo *Repository, repoName string, prID int64) []string {
+func FullPushingEnvironment(author, committer *user_model.User, repo *Repository, repoName string, prID int64) []string {
isWiki := "false"
if strings.HasSuffix(repoName, ".wiki") {
isWiki = "true"
diff --git a/models/issue.go b/models/issue.go
index 7aab8b9399..557d19e739 100644
--- a/models/issue.go
+++ b/models/issue.go
@@ -17,6 +17,7 @@ import (
"code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/references"
@@ -30,12 +31,12 @@ import (
// Issue represents an issue or pull request of repository.
type Issue struct {
- ID int64 `xorm:"pk autoincr"`
- RepoID int64 `xorm:"INDEX UNIQUE(repo_index)"`
- Repo *Repository `xorm:"-"`
- Index int64 `xorm:"UNIQUE(repo_index)"` // Index in one repository.
- PosterID int64 `xorm:"INDEX"`
- Poster *User `xorm:"-"`
+ ID int64 `xorm:"pk autoincr"`
+ RepoID int64 `xorm:"INDEX UNIQUE(repo_index)"`
+ Repo *Repository `xorm:"-"`
+ Index int64 `xorm:"UNIQUE(repo_index)"` // Index in one repository.
+ PosterID int64 `xorm:"INDEX"`
+ Poster *user_model.User `xorm:"-"`
OriginalAuthor string
OriginalAuthorID int64 `xorm:"index"`
Title string `xorm:"name"`
@@ -46,12 +47,12 @@ type Issue struct {
Milestone *Milestone `xorm:"-"`
Project *Project `xorm:"-"`
Priority int
- AssigneeID int64 `xorm:"-"`
- Assignee *User `xorm:"-"`
- IsClosed bool `xorm:"INDEX"`
- IsRead bool `xorm:"-"`
- IsPull bool `xorm:"INDEX"` // Indicates whether is a pull request or not.
- PullRequest *PullRequest `xorm:"-"`
+ AssigneeID int64 `xorm:"-"`
+ Assignee *user_model.User `xorm:"-"`
+ IsClosed bool `xorm:"INDEX"`
+ IsRead bool `xorm:"-"`
+ IsPull bool `xorm:"INDEX"` // Indicates whether is a pull request or not.
+ PullRequest *PullRequest `xorm:"-"`
NumComments int
Ref string
@@ -65,7 +66,7 @@ type Issue struct {
Comments []*Comment `xorm:"-"`
Reactions ReactionList `xorm:"-"`
TotalTrackedTime int64 `xorm:"-"`
- Assignees []*User `xorm:"-"`
+ Assignees []*user_model.User `xorm:"-"`
// IsLocked limits commenting abilities to users on an issue
// with write access
@@ -177,11 +178,11 @@ func (issue *Issue) LoadPoster() error {
func (issue *Issue) loadPoster(e db.Engine) (err error) {
if issue.Poster == nil {
- issue.Poster, err = getUserByID(e, issue.PosterID)
+ issue.Poster, err = user_model.GetUserByIDEngine(e, issue.PosterID)
if err != nil {
issue.PosterID = -1
- issue.Poster = NewGhostUser()
- if !IsErrUserNotExist(err) {
+ issue.Poster = user_model.NewGhostUser()
+ if !user_model.IsErrUserNotExist(err) {
return fmt.Errorf("getUserByID.(poster) [%d]: %v", issue.PosterID, err)
}
err = nil
@@ -428,11 +429,11 @@ func (issue *Issue) HasLabel(labelID int64) bool {
return issue.hasLabel(db.GetEngine(db.DefaultContext), labelID)
}
-func (issue *Issue) addLabel(ctx context.Context, label *Label, doer *User) error {
+func (issue *Issue) addLabel(ctx context.Context, label *Label, doer *user_model.User) error {
return newIssueLabel(ctx, issue, label, doer)
}
-func (issue *Issue) addLabels(ctx context.Context, labels []*Label, doer *User) error {
+func (issue *Issue) addLabels(ctx context.Context, labels []*Label, doer *user_model.User) error {
return newIssueLabels(ctx, issue, labels, doer)
}
@@ -448,11 +449,11 @@ func (issue *Issue) getLabels(e db.Engine) (err error) {
return nil
}
-func (issue *Issue) removeLabel(ctx context.Context, doer *User, label *Label) error {
+func (issue *Issue) removeLabel(ctx context.Context, doer *user_model.User, label *Label) error {
return deleteIssueLabel(ctx, issue, label, doer)
}
-func (issue *Issue) clearLabels(ctx context.Context, doer *User) (err error) {
+func (issue *Issue) clearLabels(ctx context.Context, doer *user_model.User) (err error) {
if err = issue.getLabels(db.GetEngine(ctx)); err != nil {
return fmt.Errorf("getLabels: %v", err)
}
@@ -468,7 +469,7 @@ func (issue *Issue) clearLabels(ctx context.Context, doer *User) (err error) {
// ClearLabels removes all issue labels as the given user.
// Triggers appropriate WebHooks, if any.
-func (issue *Issue) ClearLabels(doer *User) (err error) {
+func (issue *Issue) ClearLabels(doer *user_model.User) (err error) {
ctx, committer, err := db.TxContext()
if err != nil {
return err
@@ -516,7 +517,7 @@ func (ts labelSorter) Swap(i, j int) {
// ReplaceLabels removes all current labels and add new labels to the issue.
// Triggers appropriate WebHooks, if any.
-func (issue *Issue) ReplaceLabels(labels []*Label, doer *User) (err error) {
+func (issue *Issue) ReplaceLabels(labels []*Label, doer *user_model.User) (err error) {
ctx, committer, err := db.TxContext()
if err != nil {
return err
@@ -598,7 +599,7 @@ func updateIssueCols(e db.Engine, issue *Issue, cols ...string) error {
return nil
}
-func (issue *Issue) changeStatus(ctx context.Context, doer *User, isClosed, isMergePull bool) (*Comment, error) {
+func (issue *Issue) changeStatus(ctx context.Context, doer *user_model.User, isClosed, isMergePull bool) (*Comment, error) {
// Reload the issue
currentIssue, err := getIssueByID(db.GetEngine(ctx), issue.ID)
if err != nil {
@@ -621,7 +622,7 @@ func (issue *Issue) changeStatus(ctx context.Context, doer *User, isClosed, isMe
return issue.doChangeStatus(ctx, doer, isMergePull)
}
-func (issue *Issue) doChangeStatus(ctx context.Context, doer *User, isMergePull bool) (*Comment, error) {
+func (issue *Issue) doChangeStatus(ctx context.Context, doer *user_model.User, isMergePull bool) (*Comment, error) {
e := db.GetEngine(ctx)
// Check for open dependencies
if issue.IsClosed && issue.Repo.isDependenciesEnabled(e) {
@@ -684,7 +685,7 @@ func (issue *Issue) doChangeStatus(ctx context.Context, doer *User, isMergePull
}
// ChangeStatus changes issue status to open or closed.
-func (issue *Issue) ChangeStatus(doer *User, isClosed bool) (*Comment, error) {
+func (issue *Issue) ChangeStatus(doer *user_model.User, isClosed bool) (*Comment, error) {
ctx, committer, err := db.TxContext()
if err != nil {
return nil, err
@@ -711,7 +712,7 @@ func (issue *Issue) ChangeStatus(doer *User, isClosed bool) (*Comment, error) {
}
// ChangeTitle changes the title of this issue, as the given user.
-func (issue *Issue) ChangeTitle(doer *User, oldTitle string) (err error) {
+func (issue *Issue) ChangeTitle(doer *user_model.User, oldTitle string) (err error) {
ctx, committer, err := db.TxContext()
if err != nil {
return err
@@ -745,7 +746,7 @@ func (issue *Issue) ChangeTitle(doer *User, oldTitle string) (err error) {
}
// ChangeRef changes the branch of this issue, as the given user.
-func (issue *Issue) ChangeRef(doer *User, oldRef string) (err error) {
+func (issue *Issue) ChangeRef(doer *user_model.User, oldRef string) (err error) {
ctx, committer, err := db.TxContext()
if err != nil {
return err
@@ -778,7 +779,7 @@ func (issue *Issue) ChangeRef(doer *User, oldRef string) (err error) {
}
// AddDeletePRBranchComment adds delete branch comment for pull request issue
-func AddDeletePRBranchComment(doer *User, repo *Repository, issueID int64, branchName string) error {
+func AddDeletePRBranchComment(doer *user_model.User, repo *Repository, issueID int64, branchName string) error {
issue, err := getIssueByID(db.GetEngine(db.DefaultContext), issueID)
if err != nil {
return err
@@ -823,7 +824,7 @@ func (issue *Issue) UpdateAttachments(uuids []string) (err error) {
}
// ChangeContent changes issue content, as the given user.
-func (issue *Issue) ChangeContent(doer *User, content string) (err error) {
+func (issue *Issue) ChangeContent(doer *user_model.User, content string) (err error) {
ctx, committer, err := db.TxContext()
if err != nil {
return err
@@ -922,7 +923,7 @@ type NewIssueOptions struct {
IsPull bool
}
-func newIssue(ctx context.Context, doer *User, opts NewIssueOptions) (err error) {
+func newIssue(ctx context.Context, doer *user_model.User, opts NewIssueOptions) (err error) {
e := db.GetEngine(ctx)
opts.Issue.Title = strings.TrimSpace(opts.Issue.Title)
@@ -1380,7 +1381,7 @@ func CountIssuesByRepo(opts *IssuesOptions) (map[int64]int64, error) {
}
// GetRepoIDsForIssuesOptions find all repo ids for the given options
-func GetRepoIDsForIssuesOptions(opts *IssuesOptions, user *User) ([]int64, error) {
+func GetRepoIDsForIssuesOptions(opts *IssuesOptions, user *user_model.User) ([]int64, error) {
repoIDs := make([]int64, 0, 5)
e := db.GetEngine(db.DefaultContext)
@@ -1455,7 +1456,7 @@ func GetParticipantsIDsByIssueID(issueID int64) ([]int64, error) {
}
// IsUserParticipantsOfIssue return true if user is participants of an issue
-func IsUserParticipantsOfIssue(user *User, issue *Issue) bool {
+func IsUserParticipantsOfIssue(user *user_model.User, issue *Issue) bool {
userIDs, err := issue.getParticipantIDsByIssue(db.GetEngine(db.DefaultContext))
if err != nil {
log.Error(err.Error())
@@ -1465,7 +1466,7 @@ func IsUserParticipantsOfIssue(user *User, issue *Issue) bool {
}
// UpdateIssueMentions updates issue-user relations for mentioned users.
-func UpdateIssueMentions(ctx context.Context, issueID int64, mentions []*User) error {
+func UpdateIssueMentions(ctx context.Context, issueID int64, mentions []*user_model.User) error {
if len(mentions) == 0 {
return nil
}
@@ -1843,7 +1844,7 @@ func SearchIssueIDsByKeyword(kw string, repoIDs []int64, limit, start int) (int6
// UpdateIssueByAPI updates all allowed fields of given issue.
// If the issue status is changed a statusChangeComment is returned
// similarly if the title is changed the titleChanged bool is set to true
-func UpdateIssueByAPI(issue *Issue, doer *User) (statusChangeComment *Comment, titleChanged bool, err error) {
+func UpdateIssueByAPI(issue *Issue, doer *user_model.User) (statusChangeComment *Comment, titleChanged bool, err error) {
ctx, committer, err := db.TxContext()
if err != nil {
return nil, false, err
@@ -1898,7 +1899,7 @@ func UpdateIssueByAPI(issue *Issue, doer *User) (statusChangeComment *Comment, t
}
// UpdateIssueDeadline updates an issue deadline and adds comments. Setting a deadline to 0 means deleting it.
-func UpdateIssueDeadline(issue *Issue, deadlineUnix timeutil.TimeStamp, doer *User) (err error) {
+func UpdateIssueDeadline(issue *Issue, deadlineUnix timeutil.TimeStamp, doer *user_model.User) (err error) {
// if the deadline hasn't changed do nothing
if issue.DeadlineUnix == deadlineUnix {
return nil
@@ -2017,7 +2018,7 @@ func (issue *Issue) updateClosedNum(e db.Engine) (err error) {
}
// FindAndUpdateIssueMentions finds users mentioned in the given content string, and saves them in the database.
-func (issue *Issue) FindAndUpdateIssueMentions(ctx context.Context, doer *User, content string) (mentions []*User, err error) {
+func (issue *Issue) FindAndUpdateIssueMentions(ctx context.Context, doer *user_model.User, content string) (mentions []*user_model.User, err error) {
rawMentions := references.FindAllMentionsMarkdown(content)
mentions, err = issue.ResolveMentionsByVisibility(ctx, doer, rawMentions)
if err != nil {
@@ -2031,7 +2032,7 @@ func (issue *Issue) FindAndUpdateIssueMentions(ctx context.Context, doer *User,
// ResolveMentionsByVisibility returns the users mentioned in an issue, removing those that
// don't have access to reading it. Teams are expanded into their users, but organizations are ignored.
-func (issue *Issue) ResolveMentionsByVisibility(ctx context.Context, doer *User, mentions []string) (users []*User, err error) {
+func (issue *Issue) ResolveMentionsByVisibility(ctx context.Context, doer *user_model.User, mentions []string) (users []*user_model.User, err error) {
if len(mentions) == 0 {
return
}
@@ -2100,7 +2101,7 @@ func (issue *Issue) ResolveMentionsByVisibility(ctx context.Context, doer *User,
}
}
if len(checked) != 0 {
- teamusers := make([]*User, 0, 20)
+ teamusers := make([]*user_model.User, 0, 20)
if err := db.GetEngine(ctx).
Join("INNER", "team_user", "team_user.uid = `user`.id").
In("`team_user`.team_id", checked).
@@ -2110,7 +2111,7 @@ func (issue *Issue) ResolveMentionsByVisibility(ctx context.Context, doer *User,
return nil, fmt.Errorf("get teams users: %v", err)
}
if len(teamusers) > 0 {
- users = make([]*User, 0, len(teamusers))
+ users = make([]*user_model.User, 0, len(teamusers))
for _, user := range teamusers {
if already, ok := resolved[user.LowerName]; !ok || !already {
users = append(users, user)
@@ -2134,10 +2135,10 @@ func (issue *Issue) ResolveMentionsByVisibility(ctx context.Context, doer *User,
}
if users == nil {
- users = make([]*User, 0, len(mentionUsers))
+ users = make([]*user_model.User, 0, len(mentionUsers))
}
- unchecked := make([]*User, 0, len(mentionUsers))
+ unchecked := make([]*user_model.User, 0, len(mentionUsers))
if err := db.GetEngine(ctx).
Where("`user`.is_active = ?", true).
And("`user`.prohibit_login = ?", false).
diff --git a/models/issue_assignees.go b/models/issue_assignees.go
index 996a3a8563..527549171e 100644
--- a/models/issue_assignees.go
+++ b/models/issue_assignees.go
@@ -9,6 +9,7 @@ import (
"fmt"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/util"
)
@@ -31,7 +32,7 @@ func (issue *Issue) LoadAssignees() error {
// This loads all assignees of an issue
func (issue *Issue) loadAssignees(e db.Engine) (err error) {
// Reset maybe preexisting assignees
- issue.Assignees = []*User{}
+ issue.Assignees = []*user_model.User{}
err = e.Table("`user`").
Join("INNER", "issue_assignees", "assignee_id = `user`.id").
@@ -63,11 +64,11 @@ func GetAssigneeIDsByIssue(issueID int64) ([]int64, error) {
}
// GetAssigneesByIssue returns everyone assigned to that issue
-func GetAssigneesByIssue(issue *Issue) (assignees []*User, err error) {
+func GetAssigneesByIssue(issue *Issue) (assignees []*user_model.User, err error) {
return getAssigneesByIssue(db.GetEngine(db.DefaultContext), issue)
}
-func getAssigneesByIssue(e db.Engine, issue *Issue) (assignees []*User, err error) {
+func getAssigneesByIssue(e db.Engine, issue *Issue) (assignees []*user_model.User, err error) {
err = issue.loadAssignees(e)
if err != nil {
return assignees, err
@@ -77,11 +78,11 @@ func getAssigneesByIssue(e db.Engine, issue *Issue) (assignees []*User, err erro
}
// IsUserAssignedToIssue returns true when the user is assigned to the issue
-func IsUserAssignedToIssue(issue *Issue, user *User) (isAssigned bool, err error) {
+func IsUserAssignedToIssue(issue *Issue, user *user_model.User) (isAssigned bool, err error) {
return isUserAssignedToIssue(db.GetEngine(db.DefaultContext), issue, user)
}
-func isUserAssignedToIssue(e db.Engine, issue *Issue, user *User) (isAssigned bool, err error) {
+func isUserAssignedToIssue(e db.Engine, issue *Issue, user *user_model.User) (isAssigned bool, err error) {
return e.Get(&IssueAssignees{IssueID: issue.ID, AssigneeID: user.ID})
}
@@ -92,7 +93,7 @@ func clearAssigneeByUserID(sess db.Engine, userID int64) (err error) {
}
// ToggleAssignee changes a user between assigned and not assigned for this issue, and make issue comment for it.
-func (issue *Issue) ToggleAssignee(doer *User, assigneeID int64) (removed bool, comment *Comment, err error) {
+func (issue *Issue) ToggleAssignee(doer *user_model.User, assigneeID int64) (removed bool, comment *Comment, err error) {
ctx, committer, err := db.TxContext()
if err != nil {
return false, nil, err
@@ -111,7 +112,7 @@ func (issue *Issue) ToggleAssignee(doer *User, assigneeID int64) (removed bool,
return removed, comment, nil
}
-func (issue *Issue) toggleAssignee(ctx context.Context, doer *User, assigneeID int64, isCreate bool) (removed bool, comment *Comment, err error) {
+func (issue *Issue) toggleAssignee(ctx context.Context, doer *user_model.User, assigneeID int64, isCreate bool) (removed bool, comment *Comment, err error) {
sess := db.GetEngine(ctx)
removed, err = toggleUserAssignee(sess, issue, assigneeID)
if err != nil {
@@ -148,7 +149,7 @@ func (issue *Issue) toggleAssignee(ctx context.Context, doer *User, assigneeID i
// toggles user assignee state in database
func toggleUserAssignee(e db.Engine, issue *Issue, assigneeID int64) (removed bool, err error) {
// Check if the user exists
- assignee, err := getUserByID(e, assigneeID)
+ assignee, err := user_model.GetUserByIDEngine(e, assigneeID)
if err != nil {
return false, err
}
@@ -196,7 +197,7 @@ func MakeIDsFromAPIAssigneesToAdd(oneAssignee string, multipleAssignees []string
}
// Get the IDs of all assignees
- assigneeIDs, err = GetUserIDsByNames(requestAssignees, false)
+ assigneeIDs, err = user_model.GetUserIDsByNames(requestAssignees, false)
return
}
diff --git a/models/issue_assignees_test.go b/models/issue_assignees_test.go
index b604f13bd5..dd9a42b572 100644
--- a/models/issue_assignees_test.go
+++ b/models/issue_assignees_test.go
@@ -8,6 +8,7 @@ import (
"testing"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"github.com/stretchr/testify/assert"
)
@@ -20,19 +21,19 @@ func TestUpdateAssignee(t *testing.T) {
assert.NoError(t, err)
// Assign multiple users
- user2, err := GetUserByID(2)
+ user2, err := user_model.GetUserByID(2)
assert.NoError(t, err)
- _, _, err = issue.ToggleAssignee(&User{ID: 1}, user2.ID)
+ _, _, err = issue.ToggleAssignee(&user_model.User{ID: 1}, user2.ID)
assert.NoError(t, err)
- user3, err := GetUserByID(3)
+ user3, err := user_model.GetUserByID(3)
assert.NoError(t, err)
- _, _, err = issue.ToggleAssignee(&User{ID: 1}, user3.ID)
+ _, _, err = issue.ToggleAssignee(&user_model.User{ID: 1}, user3.ID)
assert.NoError(t, err)
- user1, err := GetUserByID(1) // This user is already assigned (see the definition in fixtures), so running UpdateAssignee should unassign him
+ user1, err := user_model.GetUserByID(1) // This user is already assigned (see the definition in fixtures), so running UpdateAssignee should unassign him
assert.NoError(t, err)
- _, _, err = issue.ToggleAssignee(&User{ID: 1}, user1.ID)
+ _, _, err = issue.ToggleAssignee(&user_model.User{ID: 1}, user1.ID)
assert.NoError(t, err)
// Check if he got removed
@@ -44,7 +45,7 @@ func TestUpdateAssignee(t *testing.T) {
assignees, err := GetAssigneesByIssue(issue)
assert.NoError(t, err)
- var expectedAssignees []*User
+ var expectedAssignees []*user_model.User
expectedAssignees = append(expectedAssignees, user2, user3)
for in, assignee := range assignees {
@@ -57,7 +58,7 @@ func TestUpdateAssignee(t *testing.T) {
assert.True(t, isAssigned)
// This user should not be assigned
- isAssigned, err = IsUserAssignedToIssue(issue, &User{ID: 4})
+ isAssigned, err = IsUserAssignedToIssue(issue, &user_model.User{ID: 4})
assert.NoError(t, err)
assert.False(t, isAssigned)
}
@@ -65,8 +66,8 @@ func TestUpdateAssignee(t *testing.T) {
func TestMakeIDsFromAPIAssigneesToAdd(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- _ = unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
- _ = unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ _ = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
+ _ = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
IDs, err := MakeIDsFromAPIAssigneesToAdd("", []string{""})
assert.NoError(t, err)
diff --git a/models/issue_comment.go b/models/issue_comment.go
index 8429596c82..417caccfaf 100644
--- a/models/issue_comment.go
+++ b/models/issue_comment.go
@@ -17,6 +17,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
@@ -148,10 +149,10 @@ func (rd RoleDescriptor) HasRole(role string) bool {
// Comment represents a comment in commit and issue page.
type Comment struct {
- ID int64 `xorm:"pk autoincr"`
- Type CommentType `xorm:"INDEX"`
- PosterID int64 `xorm:"INDEX"`
- Poster *User `xorm:"-"`
+ ID int64 `xorm:"pk autoincr"`
+ Type CommentType `xorm:"INDEX"`
+ PosterID int64 `xorm:"INDEX"`
+ Poster *user_model.User `xorm:"-"`
OriginalAuthor string
OriginalAuthorID int64
IssueID int64 `xorm:"INDEX"`
@@ -172,11 +173,11 @@ type Comment struct {
Time *TrackedTime `xorm:"-"`
AssigneeID int64
RemovedAssignee bool
- Assignee *User `xorm:"-"`
- AssigneeTeamID int64 `xorm:"NOT NULL DEFAULT 0"`
- AssigneeTeam *Team `xorm:"-"`
+ Assignee *user_model.User `xorm:"-"`
+ AssigneeTeamID int64 `xorm:"NOT NULL DEFAULT 0"`
+ AssigneeTeam *Team `xorm:"-"`
ResolveDoerID int64
- ResolveDoer *User `xorm:"-"`
+ ResolveDoer *user_model.User `xorm:"-"`
OldTitle string
NewTitle string
OldRef string
@@ -284,11 +285,11 @@ func (c *Comment) loadPoster(e db.Engine) (err error) {
return nil
}
- c.Poster, err = getUserByID(e, c.PosterID)
+ c.Poster, err = user_model.GetUserByIDEngine(e, c.PosterID)
if err != nil {
- if IsErrUserNotExist(err) {
+ if user_model.IsErrUserNotExist(err) {
c.PosterID = -1
- c.Poster = NewGhostUser()
+ c.Poster = user_model.NewGhostUser()
} else {
log.Error("getUserByID[%d]: %v", c.ID, err)
}
@@ -519,12 +520,12 @@ func (c *Comment) LoadAssigneeUserAndTeam() error {
var err error
if c.AssigneeID > 0 && c.Assignee == nil {
- c.Assignee, err = GetUserByIDCtx(db.DefaultContext, c.AssigneeID)
+ c.Assignee, err = user_model.GetUserByIDCtx(db.DefaultContext, c.AssigneeID)
if err != nil {
- if !IsErrUserNotExist(err) {
+ if !user_model.IsErrUserNotExist(err) {
return err
}
- c.Assignee = NewGhostUser()
+ c.Assignee = user_model.NewGhostUser()
}
} else if c.AssigneeTeamID > 0 && c.AssigneeTeam == nil {
if err = c.LoadIssue(); err != nil {
@@ -554,10 +555,10 @@ func (c *Comment) LoadResolveDoer() (err error) {
if c.ResolveDoerID == 0 || c.Type != CommentTypeCode {
return nil
}
- c.ResolveDoer, err = GetUserByIDCtx(db.DefaultContext, c.ResolveDoerID)
+ c.ResolveDoer, err = user_model.GetUserByIDCtx(db.DefaultContext, c.ResolveDoerID)
if err != nil {
- if IsErrUserNotExist(err) {
- c.ResolveDoer = NewGhostUser()
+ if user_model.IsErrUserNotExist(err) {
+ c.ResolveDoer = user_model.NewGhostUser()
err = nil
}
}
@@ -628,7 +629,7 @@ func (c *Comment) LoadReview() error {
var notEnoughLines = regexp.MustCompile(`fatal: file .* has only \d+ lines?`)
-func (c *Comment) checkInvalidation(doer *User, repo *git.Repository, branch string) error {
+func (c *Comment) checkInvalidation(doer *user_model.User, repo *git.Repository, branch string) error {
// FIXME differentiate between previous and proposed line
commit, err := repo.LineBlame(branch, repo.Path, c.TreePath, uint(c.UnsignedLine()))
if err != nil && (strings.Contains(err.Error(), "fatal: no such path") || notEnoughLines.MatchString(err.Error())) {
@@ -647,7 +648,7 @@ func (c *Comment) checkInvalidation(doer *User, repo *git.Repository, branch str
// CheckInvalidation checks if the line of code comment got changed by another commit.
// If the line got changed the comment is going to be invalidated.
-func (c *Comment) CheckInvalidation(repo *git.Repository, doer *User, branch string) error {
+func (c *Comment) CheckInvalidation(repo *git.Repository, doer *user_model.User, branch string) error {
return c.checkInvalidation(doer, repo, branch)
}
@@ -824,7 +825,7 @@ func updateCommentInfos(ctx context.Context, opts *CreateCommentOptions, comment
return updateIssueCols(e, opts.Issue, "updated_unix")
}
-func createDeadlineComment(ctx context.Context, doer *User, issue *Issue, newDeadlineUnix timeutil.TimeStamp) (*Comment, error) {
+func createDeadlineComment(ctx context.Context, doer *user_model.User, issue *Issue, newDeadlineUnix timeutil.TimeStamp) (*Comment, error) {
var content string
var commentType CommentType
@@ -861,7 +862,7 @@ func createDeadlineComment(ctx context.Context, doer *User, issue *Issue, newDea
}
// Creates issue dependency comment
-func createIssueDependencyComment(ctx context.Context, doer *User, issue, dependentIssue *Issue, add bool) (err error) {
+func createIssueDependencyComment(ctx context.Context, doer *user_model.User, issue, dependentIssue *Issue, add bool) (err error) {
cType := CommentTypeAddDependency
if !add {
cType = CommentTypeRemoveDependency
@@ -896,7 +897,7 @@ func createIssueDependencyComment(ctx context.Context, doer *User, issue, depend
// CreateCommentOptions defines options for creating comment
type CreateCommentOptions struct {
Type CommentType
- Doer *User
+ Doer *user_model.User
Repo *Repository
Issue *Issue
Label *Label
@@ -952,7 +953,7 @@ func CreateComment(opts *CreateCommentOptions) (comment *Comment, err error) {
}
// CreateRefComment creates a commit reference comment to issue.
-func CreateRefComment(doer *User, repo *Repository, issue *Issue, content, commitSHA string) error {
+func CreateRefComment(doer *user_model.User, repo *Repository, issue *Issue, content, commitSHA string) error {
if len(commitSHA) == 0 {
return fmt.Errorf("cannot create reference with empty commit SHA")
}
@@ -1072,7 +1073,7 @@ func CountComments(opts *FindCommentsOptions) (int64, error) {
}
// UpdateComment updates information of comment.
-func UpdateComment(c *Comment, doer *User) error {
+func UpdateComment(c *Comment, doer *user_model.User) error {
ctx, committer, err := db.TxContext()
if err != nil {
return err
@@ -1143,11 +1144,11 @@ func deleteComment(e db.Engine, comment *Comment) error {
// CodeComments represents comments on code by using this structure: FILENAME -> LINE (+ == proposed; - == previous) -> COMMENTS
type CodeComments map[string]map[int64][]*Comment
-func fetchCodeComments(e db.Engine, issue *Issue, currentUser *User) (CodeComments, error) {
+func fetchCodeComments(e db.Engine, issue *Issue, currentUser *user_model.User) (CodeComments, error) {
return fetchCodeCommentsByReview(e, issue, currentUser, nil)
}
-func fetchCodeCommentsByReview(e db.Engine, issue *Issue, currentUser *User, review *Review) (CodeComments, error) {
+func fetchCodeCommentsByReview(e db.Engine, issue *Issue, currentUser *user_model.User, review *Review) (CodeComments, error) {
pathToLineToComment := make(CodeComments)
if review == nil {
review = &Review{ID: 0}
@@ -1172,7 +1173,7 @@ func fetchCodeCommentsByReview(e db.Engine, issue *Issue, currentUser *User, rev
return pathToLineToComment, nil
}
-func findCodeComments(e db.Engine, opts FindCommentsOptions, issue *Issue, currentUser *User, review *Review) ([]*Comment, error) {
+func findCodeComments(e db.Engine, opts FindCommentsOptions, issue *Issue, currentUser *user_model.User, review *Review) ([]*Comment, error) {
var comments []*Comment
if review == nil {
review = &Review{ID: 0}
@@ -1241,7 +1242,7 @@ func findCodeComments(e db.Engine, opts FindCommentsOptions, issue *Issue, curre
}
// FetchCodeCommentsByLine fetches the code comments for a given treePath and line number
-func FetchCodeCommentsByLine(issue *Issue, currentUser *User, treePath string, line int64) ([]*Comment, error) {
+func FetchCodeCommentsByLine(issue *Issue, currentUser *user_model.User, treePath string, line int64) ([]*Comment, error) {
opts := FindCommentsOptions{
Type: CommentTypeCode,
IssueID: issue.ID,
@@ -1252,7 +1253,7 @@ func FetchCodeCommentsByLine(issue *Issue, currentUser *User, treePath string, l
}
// FetchCodeComments will return a 2d-map: ["Path"]["Line"] = Comments at line
-func FetchCodeComments(issue *Issue, currentUser *User) (CodeComments, error) {
+func FetchCodeComments(issue *Issue, currentUser *user_model.User) (CodeComments, error) {
return fetchCodeComments(db.GetEngine(db.DefaultContext), issue, currentUser)
}
@@ -1277,7 +1278,7 @@ func UpdateCommentsMigrationsByType(tp structs.GitServiceType, originalAuthorID
}
// CreatePushPullComment create push code to pull base comment
-func CreatePushPullComment(pusher *User, pr *PullRequest, oldCommitID, newCommitID string) (comment *Comment, err error) {
+func CreatePushPullComment(pusher *user_model.User, pr *PullRequest, oldCommitID, newCommitID string) (comment *Comment, err error) {
if pr.HasMerged || oldCommitID == "" || newCommitID == "" {
return nil, nil
}
diff --git a/models/issue_comment_list.go b/models/issue_comment_list.go
index 3c587fc8f7..ef6aff9cbe 100644
--- a/models/issue_comment_list.go
+++ b/models/issue_comment_list.go
@@ -7,6 +7,7 @@ package models
import (
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
+ user_model "code.gitea.io/gitea/models/user"
)
// CommentList defines a list of comments
@@ -28,7 +29,7 @@ func (comments CommentList) loadPosters(e db.Engine) error {
}
posterIDs := comments.getPosterIDs()
- posterMaps := make(map[int64]*User, len(posterIDs))
+ posterMaps := make(map[int64]*user_model.User, len(posterIDs))
left := len(posterIDs)
for left > 0 {
limit := defaultMaxInSize
@@ -51,7 +52,7 @@ func (comments CommentList) loadPosters(e db.Engine) error {
}
var ok bool
if comment.Poster, ok = posterMaps[comment.PosterID]; !ok {
- comment.Poster = NewGhostUser()
+ comment.Poster = user_model.NewGhostUser()
}
}
return nil
@@ -217,7 +218,7 @@ func (comments CommentList) loadAssignees(e db.Engine) error {
}
assigneeIDs := comments.getAssigneeIDs()
- assignees := make(map[int64]*User, len(assigneeIDs))
+ assignees := make(map[int64]*user_model.User, len(assigneeIDs))
left := len(assigneeIDs)
for left > 0 {
limit := defaultMaxInSize
@@ -226,13 +227,13 @@ func (comments CommentList) loadAssignees(e db.Engine) error {
}
rows, err := e.
In("id", assigneeIDs[:limit]).
- Rows(new(User))
+ Rows(new(user_model.User))
if err != nil {
return err
}
for rows.Next() {
- var user User
+ var user user_model.User
err = rows.Scan(&user)
if err != nil {
rows.Close()
diff --git a/models/issue_comment_test.go b/models/issue_comment_test.go
index 4d3607b3e1..5ab4892bc7 100644
--- a/models/issue_comment_test.go
+++ b/models/issue_comment_test.go
@@ -9,6 +9,7 @@ import (
"time"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"github.com/stretchr/testify/assert"
)
@@ -18,7 +19,7 @@ func TestCreateComment(t *testing.T) {
issue := unittest.AssertExistsAndLoadBean(t, &Issue{}).(*Issue)
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: issue.RepoID}).(*Repository)
- doer := unittest.AssertExistsAndLoadBean(t, &User{ID: repo.OwnerID}).(*User)
+ doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
now := time.Now().Unix()
comment, err := CreateComment(&CreateCommentOptions{
@@ -46,7 +47,7 @@ func TestFetchCodeComments(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 2}).(*Issue)
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
res, err := FetchCodeComments(issue, user)
assert.NoError(t, err)
assert.Contains(t, res, "README.md")
@@ -54,7 +55,7 @@ func TestFetchCodeComments(t *testing.T) {
assert.Len(t, res["README.md"][4], 1)
assert.Equal(t, int64(4), res["README.md"][4][0].ID)
- user2 := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
res, err = FetchCodeComments(issue, user2)
assert.NoError(t, err)
assert.Len(t, res, 1)
diff --git a/models/issue_dependency.go b/models/issue_dependency.go
index ab81ef0c68..9fef652b4e 100644
--- a/models/issue_dependency.go
+++ b/models/issue_dependency.go
@@ -7,6 +7,7 @@ package models
import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unit"
+ 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"
@@ -36,7 +37,7 @@ const (
)
// CreateIssueDependency creates a new dependency for an issue
-func CreateIssueDependency(user *User, issue, dep *Issue) error {
+func CreateIssueDependency(user *user_model.User, issue, dep *Issue) error {
ctx, committer, err := db.TxContext()
if err != nil {
return err
@@ -78,7 +79,7 @@ func CreateIssueDependency(user *User, issue, dep *Issue) error {
}
// RemoveIssueDependency removes a dependency from an issue
-func RemoveIssueDependency(user *User, issue, dep *Issue, depType DependencyType) (err error) {
+func RemoveIssueDependency(user *user_model.User, issue, dep *Issue, depType DependencyType) (err error) {
ctx, committer, err := db.TxContext()
if err != nil {
return err
diff --git a/models/issue_dependency_test.go b/models/issue_dependency_test.go
index 86ac98b733..61215dedef 100644
--- a/models/issue_dependency_test.go
+++ b/models/issue_dependency_test.go
@@ -8,6 +8,7 @@ import (
"testing"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"github.com/stretchr/testify/assert"
)
@@ -16,7 +17,7 @@ func TestCreateIssueDependency(t *testing.T) {
// Prepare
assert.NoError(t, unittest.PrepareTestDatabase())
- user1, err := GetUserByID(1)
+ user1, err := user_model.GetUserByID(1)
assert.NoError(t, err)
issue1, err := GetIssueByID(1)
diff --git a/models/issue_label.go b/models/issue_label.go
index 2858b12dde..9b36d8dfdf 100644
--- a/models/issue_label.go
+++ b/models/issue_label.go
@@ -15,6 +15,7 @@ import (
"strings"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/timeutil"
"xorm.io/builder"
@@ -665,7 +666,7 @@ func HasIssueLabel(issueID, labelID int64) bool {
// newIssueLabel this function creates a new label it does not check if the label is valid for the issue
// YOU MUST CHECK THIS BEFORE THIS FUNCTION
-func newIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *User) (err error) {
+func newIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *user_model.User) (err error) {
e := db.GetEngine(ctx)
if _, err = e.Insert(&IssueLabel{
IssueID: issue.ID,
@@ -694,7 +695,7 @@ func newIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *User)
}
// NewIssueLabel creates a new issue-label relation.
-func NewIssueLabel(issue *Issue, label *Label, doer *User) (err error) {
+func NewIssueLabel(issue *Issue, label *Label, doer *user_model.User) (err error) {
if HasIssueLabel(issue.ID, label.ID) {
return nil
}
@@ -728,7 +729,7 @@ func NewIssueLabel(issue *Issue, label *Label, doer *User) (err error) {
}
// newIssueLabels add labels to an issue. It will check if the labels are valid for the issue
-func newIssueLabels(ctx context.Context, issue *Issue, labels []*Label, doer *User) (err error) {
+func newIssueLabels(ctx context.Context, issue *Issue, labels []*Label, doer *user_model.User) (err error) {
e := db.GetEngine(ctx)
if err = issue.loadRepo(e); err != nil {
return err
@@ -749,7 +750,7 @@ func newIssueLabels(ctx context.Context, issue *Issue, labels []*Label, doer *Us
}
// NewIssueLabels creates a list of issue-label relations.
-func NewIssueLabels(issue *Issue, labels []*Label, doer *User) (err error) {
+func NewIssueLabels(issue *Issue, labels []*Label, doer *user_model.User) (err error) {
ctx, committer, err := db.TxContext()
if err != nil {
return err
@@ -768,7 +769,7 @@ func NewIssueLabels(issue *Issue, labels []*Label, doer *User) (err error) {
return committer.Commit()
}
-func deleteIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *User) (err error) {
+func deleteIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *user_model.User) (err error) {
e := db.GetEngine(ctx)
if count, err := e.Delete(&IssueLabel{
IssueID: issue.ID,
@@ -798,7 +799,7 @@ func deleteIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *Use
}
// DeleteIssueLabel deletes issue-label relation.
-func DeleteIssueLabel(issue *Issue, label *Label, doer *User) (err error) {
+func DeleteIssueLabel(issue *Issue, label *Label, doer *user_model.User) (err error) {
ctx, committer, err := db.TxContext()
if err != nil {
return err
diff --git a/models/issue_label_test.go b/models/issue_label_test.go
index d0f807a56e..aa3c92b282 100644
--- a/models/issue_label_test.go
+++ b/models/issue_label_test.go
@@ -10,6 +10,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"github.com/stretchr/testify/assert"
)
@@ -296,7 +297,7 @@ func TestNewIssueLabel(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
label := unittest.AssertExistsAndLoadBean(t, &Label{ID: 2}).(*Label)
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue)
- doer := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
// add new IssueLabel
prevNumIssues := label.NumIssues
@@ -322,7 +323,7 @@ func TestNewIssueLabels(t *testing.T) {
label1 := unittest.AssertExistsAndLoadBean(t, &Label{ID: 1}).(*Label)
label2 := unittest.AssertExistsAndLoadBean(t, &Label{ID: 2}).(*Label)
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 5}).(*Issue)
- doer := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
assert.NoError(t, NewIssueLabels(issue, []*Label{label1, label2}, doer))
unittest.AssertExistsAndLoadBean(t, &IssueLabel{IssueID: issue.ID, LabelID: label1.ID})
@@ -352,7 +353,7 @@ func TestDeleteIssueLabel(t *testing.T) {
testSuccess := func(labelID, issueID, doerID int64) {
label := unittest.AssertExistsAndLoadBean(t, &Label{ID: labelID}).(*Label)
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: issueID}).(*Issue)
- doer := unittest.AssertExistsAndLoadBean(t, &User{ID: doerID}).(*User)
+ doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doerID}).(*user_model.User)
expectedNumIssues := label.NumIssues
expectedNumClosedIssues := label.NumClosedIssues
diff --git a/models/issue_list.go b/models/issue_list.go
index 6eeb2a961a..7c98f60b3a 100644
--- a/models/issue_list.go
+++ b/models/issue_list.go
@@ -9,6 +9,7 @@ import (
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
+ user_model "code.gitea.io/gitea/models/user"
"xorm.io/builder"
)
@@ -84,7 +85,7 @@ func (issues IssueList) loadPosters(e db.Engine) error {
}
posterIDs := issues.getPosterIDs()
- posterMaps := make(map[int64]*User, len(posterIDs))
+ posterMaps := make(map[int64]*user_model.User, len(posterIDs))
left := len(posterIDs)
for left > 0 {
limit := defaultMaxInSize
@@ -107,7 +108,7 @@ func (issues IssueList) loadPosters(e db.Engine) error {
}
var ok bool
if issue.Poster, ok = posterMaps[issue.PosterID]; !ok {
- issue.Poster = NewGhostUser()
+ issue.Poster = user_model.NewGhostUser()
}
}
return nil
@@ -219,11 +220,11 @@ func (issues IssueList) loadAssignees(e db.Engine) error {
}
type AssigneeIssue struct {
- IssueAssignee *IssueAssignees `xorm:"extends"`
- Assignee *User `xorm:"extends"`
+ IssueAssignee *IssueAssignees `xorm:"extends"`
+ Assignee *user_model.User `xorm:"extends"`
}
- assignees := make(map[int64][]*User, len(issues))
+ assignees := make(map[int64][]*user_model.User, len(issues))
issueIDs := issues.getIssueIDs()
left := len(issueIDs)
for left > 0 {
diff --git a/models/issue_lock.go b/models/issue_lock.go
index d0b9c660c2..66a932225a 100644
--- a/models/issue_lock.go
+++ b/models/issue_lock.go
@@ -4,11 +4,14 @@
package models
-import "code.gitea.io/gitea/models/db"
+import (
+ "code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
+)
// IssueLockOptions defines options for locking and/or unlocking an issue/PR
type IssueLockOptions struct {
- Doer *User
+ Doer *user_model.User
Issue *Issue
Reason string
}
diff --git a/models/issue_milestone.go b/models/issue_milestone.go
index de4e13b4bb..a85c865464 100644
--- a/models/issue_milestone.go
+++ b/models/issue_milestone.go
@@ -11,6 +11,7 @@ import (
"time"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
@@ -267,7 +268,7 @@ func changeMilestoneStatus(e db.Engine, m *Milestone, isClosed bool) error {
return updateRepoMilestoneNum(e, m.RepoID)
}
-func changeMilestoneAssign(ctx context.Context, doer *User, issue *Issue, oldMilestoneID int64) error {
+func changeMilestoneAssign(ctx context.Context, doer *user_model.User, issue *Issue, oldMilestoneID int64) error {
e := db.GetEngine(ctx)
if err := updateIssueCols(e, issue, "milestone_id"); err != nil {
return err
@@ -307,7 +308,7 @@ func changeMilestoneAssign(ctx context.Context, doer *User, issue *Issue, oldMil
}
// ChangeMilestoneAssign changes assignment of milestone for issue.
-func ChangeMilestoneAssign(issue *Issue, doer *User, oldMilestoneID int64) (err error) {
+func ChangeMilestoneAssign(issue *Issue, doer *user_model.User, oldMilestoneID int64) (err error) {
ctx, committer, err := db.TxContext()
if err != nil {
return err
diff --git a/models/issue_milestone_test.go b/models/issue_milestone_test.go
index 2956e40f06..21d90a6118 100644
--- a/models/issue_milestone_test.go
+++ b/models/issue_milestone_test.go
@@ -10,6 +10,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
@@ -240,7 +241,7 @@ func TestUpdateMilestoneCounters(t *testing.T) {
func TestChangeMilestoneAssign(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
issue := unittest.AssertExistsAndLoadBean(t, &Issue{RepoID: 1}).(*Issue)
- doer := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
assert.NotNil(t, issue)
assert.NotNil(t, doer)
diff --git a/models/issue_reaction.go b/models/issue_reaction.go
index 933246544b..fb34db4ed5 100644
--- a/models/issue_reaction.go
+++ b/models/issue_reaction.go
@@ -9,6 +9,7 @@ import (
"fmt"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
@@ -24,7 +25,7 @@ type Reaction struct {
UserID int64 `xorm:"INDEX UNIQUE(s) NOT NULL"`
OriginalAuthorID int64 `xorm:"INDEX UNIQUE(s) NOT NULL DEFAULT(0)"`
OriginalAuthor string `xorm:"INDEX UNIQUE(s)"`
- User *User `xorm:"-"`
+ User *user_model.User `xorm:"-"`
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
}
@@ -136,7 +137,7 @@ func createReaction(e db.Engine, opts *ReactionOptions) (*Reaction, error) {
// ReactionOptions defines options for creating or deleting reactions
type ReactionOptions struct {
Type string
- Doer *User
+ Doer *user_model.User
Issue *Issue
Comment *Comment
}
@@ -165,7 +166,7 @@ func CreateReaction(opts *ReactionOptions) (*Reaction, error) {
}
// CreateIssueReaction creates a reaction on issue.
-func CreateIssueReaction(doer *User, issue *Issue, content string) (*Reaction, error) {
+func CreateIssueReaction(doer *user_model.User, issue *Issue, content string) (*Reaction, error) {
return CreateReaction(&ReactionOptions{
Type: content,
Doer: doer,
@@ -174,7 +175,7 @@ func CreateIssueReaction(doer *User, issue *Issue, content string) (*Reaction, e
}
// CreateCommentReaction creates a reaction on comment.
-func CreateCommentReaction(doer *User, issue *Issue, comment *Comment, content string) (*Reaction, error) {
+func CreateCommentReaction(doer *user_model.User, issue *Issue, comment *Comment, content string) (*Reaction, error) {
return CreateReaction(&ReactionOptions{
Type: content,
Doer: doer,
@@ -216,7 +217,7 @@ func DeleteReaction(opts *ReactionOptions) error {
}
// DeleteIssueReaction deletes a reaction on issue.
-func DeleteIssueReaction(doer *User, issue *Issue, content string) error {
+func DeleteIssueReaction(doer *user_model.User, issue *Issue, content string) error {
return DeleteReaction(&ReactionOptions{
Type: content,
Doer: doer,
@@ -225,7 +226,7 @@ func DeleteIssueReaction(doer *User, issue *Issue, content string) error {
}
// DeleteCommentReaction deletes a reaction on comment.
-func DeleteCommentReaction(doer *User, issue *Issue, comment *Comment, content string) error {
+func DeleteCommentReaction(doer *user_model.User, issue *Issue, comment *Comment, content string) error {
return DeleteReaction(&ReactionOptions{
Type: content,
Doer: doer,
@@ -235,11 +236,11 @@ func DeleteCommentReaction(doer *User, issue *Issue, comment *Comment, content s
}
// LoadUser load user of reaction
-func (r *Reaction) LoadUser() (*User, error) {
+func (r *Reaction) LoadUser() (*user_model.User, error) {
if r.User != nil {
return r.User, nil
}
- user, err := GetUserByIDCtx(db.DefaultContext, r.UserID)
+ user, err := user_model.GetUserByIDCtx(db.DefaultContext, r.UserID)
if err != nil {
return nil, err
}
@@ -285,13 +286,13 @@ func (list ReactionList) getUserIDs() []int64 {
return keysInt64(userIDs)
}
-func (list ReactionList) loadUsers(e db.Engine, repo *Repository) ([]*User, error) {
+func (list ReactionList) loadUsers(e db.Engine, repo *Repository) ([]*user_model.User, error) {
if len(list) == 0 {
return nil, nil
}
userIDs := list.getUserIDs()
- userMaps := make(map[int64]*User, len(userIDs))
+ userMaps := make(map[int64]*user_model.User, len(userIDs))
err := e.
In("id", userIDs).
Find(&userMaps)
@@ -301,18 +302,18 @@ func (list ReactionList) loadUsers(e db.Engine, repo *Repository) ([]*User, erro
for _, reaction := range list {
if reaction.OriginalAuthor != "" {
- reaction.User = NewReplaceUser(fmt.Sprintf("%s(%s)", reaction.OriginalAuthor, repo.OriginalServiceType.Name()))
+ reaction.User = user_model.NewReplaceUser(fmt.Sprintf("%s(%s)", reaction.OriginalAuthor, repo.OriginalServiceType.Name()))
} else if user, ok := userMaps[reaction.UserID]; ok {
reaction.User = user
} else {
- reaction.User = NewGhostUser()
+ reaction.User = user_model.NewGhostUser()
}
}
return valuesUser(userMaps), nil
}
// LoadUsers loads reactions' all users
-func (list ReactionList) LoadUsers(repo *Repository) ([]*User, error) {
+func (list ReactionList) LoadUsers(repo *Repository) ([]*user_model.User, error) {
return list.loadUsers(db.GetEngine(db.DefaultContext), repo)
}
diff --git a/models/issue_reaction_test.go b/models/issue_reaction_test.go
index c01e4add7a..458250ac58 100644
--- a/models/issue_reaction_test.go
+++ b/models/issue_reaction_test.go
@@ -8,12 +8,13 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"github.com/stretchr/testify/assert"
)
-func addReaction(t *testing.T, doer *User, issue *Issue, comment *Comment, content string) {
+func addReaction(t *testing.T, doer *user_model.User, issue *Issue, comment *Comment, content string) {
var reaction *Reaction
var err error
if comment == nil {
@@ -28,7 +29,7 @@ func addReaction(t *testing.T, doer *User, issue *Issue, comment *Comment, conte
func TestIssueAddReaction(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- user1 := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
+ user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
issue1 := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue)
@@ -40,7 +41,7 @@ func TestIssueAddReaction(t *testing.T) {
func TestIssueAddDuplicateReaction(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- user1 := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
+ user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
issue1 := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue)
@@ -61,7 +62,7 @@ func TestIssueAddDuplicateReaction(t *testing.T) {
func TestIssueDeleteReaction(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- user1 := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
+ user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
issue1 := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue)
@@ -78,11 +79,11 @@ func TestIssueReactionCount(t *testing.T) {
setting.UI.ReactionMaxUserNum = 2
- user1 := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
- user2 := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
- user3 := unittest.AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
- user4 := unittest.AssertExistsAndLoadBean(t, &User{ID: 4}).(*User)
- ghost := NewGhostUser()
+ user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
+ user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
+ user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User)
+ ghost := user_model.NewGhostUser()
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 2}).(*Issue)
@@ -114,7 +115,7 @@ func TestIssueReactionCount(t *testing.T) {
func TestIssueCommentAddReaction(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- user1 := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
+ user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
issue1 := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue)
@@ -128,10 +129,10 @@ func TestIssueCommentAddReaction(t *testing.T) {
func TestIssueCommentDeleteReaction(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- user1 := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
- user2 := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
- user3 := unittest.AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
- user4 := unittest.AssertExistsAndLoadBean(t, &User{ID: 4}).(*User)
+ user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
+ user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
+ user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User)
issue1 := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue)
repo1 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: issue1.RepoID}).(*Repository)
@@ -155,7 +156,7 @@ func TestIssueCommentDeleteReaction(t *testing.T) {
func TestIssueCommentReactionCount(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- user1 := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
+ user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
issue1 := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue)
diff --git a/models/issue_stopwatch.go b/models/issue_stopwatch.go
index eaec5d924e..7754e90a86 100644
--- a/models/issue_stopwatch.go
+++ b/models/issue_stopwatch.go
@@ -10,6 +10,7 @@ import (
"time"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/timeutil"
)
@@ -104,7 +105,7 @@ func hasUserStopwatch(e db.Engine, userID int64) (exists bool, sw *Stopwatch, er
}
// FinishIssueStopwatchIfPossible if stopwatch exist then finish it otherwise ignore
-func FinishIssueStopwatchIfPossible(ctx context.Context, user *User, issue *Issue) error {
+func FinishIssueStopwatchIfPossible(ctx context.Context, user *user_model.User, issue *Issue) error {
_, exists, err := getStopwatch(ctx, user.ID, issue.ID)
if err != nil {
return err
@@ -116,7 +117,7 @@ func FinishIssueStopwatchIfPossible(ctx context.Context, user *User, issue *Issu
}
// CreateOrStopIssueStopwatch create an issue stopwatch if it's not exist, otherwise finish it
-func CreateOrStopIssueStopwatch(user *User, issue *Issue) error {
+func CreateOrStopIssueStopwatch(user *user_model.User, issue *Issue) error {
_, exists, err := getStopwatch(db.DefaultContext, user.ID, issue.ID)
if err != nil {
return err
@@ -128,7 +129,7 @@ func CreateOrStopIssueStopwatch(user *User, issue *Issue) error {
}
// FinishIssueStopwatch if stopwatch exist then finish it otherwise return an error
-func FinishIssueStopwatch(ctx context.Context, user *User, issue *Issue) error {
+func FinishIssueStopwatch(ctx context.Context, user *user_model.User, issue *Issue) error {
sw, exists, err := getStopwatch(ctx, user.ID, issue.ID)
if err != nil {
return err
@@ -174,7 +175,7 @@ func FinishIssueStopwatch(ctx context.Context, user *User, issue *Issue) error {
}
// CreateIssueStopwatch creates a stopwatch if not exist, otherwise return an error
-func CreateIssueStopwatch(ctx context.Context, user *User, issue *Issue) error {
+func CreateIssueStopwatch(ctx context.Context, user *user_model.User, issue *Issue) error {
e := db.GetEngine(ctx)
if err := issue.loadRepo(e); err != nil {
return err
@@ -223,7 +224,7 @@ func CreateIssueStopwatch(ctx context.Context, user *User, issue *Issue) error {
}
// CancelStopwatch removes the given stopwatch and logs it into issue's timeline.
-func CancelStopwatch(user *User, issue *Issue) error {
+func CancelStopwatch(user *user_model.User, issue *Issue) error {
ctx, committer, err := db.TxContext()
if err != nil {
return err
@@ -235,7 +236,7 @@ func CancelStopwatch(user *User, issue *Issue) error {
return committer.Commit()
}
-func cancelStopwatch(ctx context.Context, user *User, issue *Issue) error {
+func cancelStopwatch(ctx context.Context, user *user_model.User, issue *Issue) error {
e := db.GetEngine(ctx)
sw, exists, err := getStopwatch(ctx, user.ID, issue.ID)
if err != nil {
diff --git a/models/issue_stopwatch_test.go b/models/issue_stopwatch_test.go
index ceb579d095..0f578f101f 100644
--- a/models/issue_stopwatch_test.go
+++ b/models/issue_stopwatch_test.go
@@ -8,6 +8,7 @@ import (
"testing"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/timeutil"
"github.com/stretchr/testify/assert"
@@ -16,7 +17,7 @@ import (
func TestCancelStopwatch(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- user1, err := GetUserByID(1)
+ user1, err := user_model.GetUserByID(1)
assert.NoError(t, err)
issue1, err := GetIssueByID(1)
@@ -56,9 +57,9 @@ func TestHasUserStopwatch(t *testing.T) {
func TestCreateOrStopIssueStopwatch(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- user2, err := GetUserByID(2)
+ user2, err := user_model.GetUserByID(2)
assert.NoError(t, err)
- user3, err := GetUserByID(3)
+ user3, err := user_model.GetUserByID(3)
assert.NoError(t, err)
issue1, err := GetIssueByID(1)
diff --git a/models/issue_test.go b/models/issue_test.go
index 7942b7e785..a9e19438d6 100644
--- a/models/issue_test.go
+++ b/models/issue_test.go
@@ -13,6 +13,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"github.com/stretchr/testify/assert"
)
@@ -23,7 +24,7 @@ func TestIssue_ReplaceLabels(t *testing.T) {
testSuccess := func(issueID int64, labelIDs []int64) {
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: issueID}).(*Issue)
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: issue.RepoID}).(*Repository)
- doer := unittest.AssertExistsAndLoadBean(t, &User{ID: repo.OwnerID}).(*User)
+ doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
labels := make([]*Label, len(labelIDs))
for i, labelID := range labelIDs {
@@ -110,7 +111,7 @@ func TestIssue_ClearLabels(t *testing.T) {
for _, test := range tests {
assert.NoError(t, unittest.PrepareTestDatabase())
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: test.issueID}).(*Issue)
- doer := unittest.AssertExistsAndLoadBean(t, &User{ID: test.doerID}).(*User)
+ doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: test.doerID}).(*user_model.User)
assert.NoError(t, issue.ClearLabels(doer))
unittest.AssertNotExistsBean(t, &IssueLabel{IssueID: test.issueID})
}
@@ -322,7 +323,7 @@ func TestIssue_SearchIssueIDsByKeyword(t *testing.T) {
func TestGetRepoIDsForIssuesOptions(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
for _, test := range []struct {
Opts IssuesOptions
ExpectedRepoIDs []int64
@@ -354,7 +355,7 @@ func testInsertIssue(t *testing.T, title, content string, expectIndex int64) *Is
var newIssue Issue
t.Run(title, func(t *testing.T) {
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
issue := Issue{
RepoID: repo.ID,
@@ -396,10 +397,10 @@ func TestIssue_ResolveMentions(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
testSuccess := func(owner, repo, doer string, mentions []string, expected []int64) {
- o := unittest.AssertExistsAndLoadBean(t, &User{LowerName: owner}).(*User)
+ o := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: owner}).(*user_model.User)
r := unittest.AssertExistsAndLoadBean(t, &Repository{OwnerID: o.ID, LowerName: repo}).(*Repository)
issue := &Issue{RepoID: r.ID}
- d := unittest.AssertExistsAndLoadBean(t, &User{LowerName: doer}).(*User)
+ d := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: doer}).(*user_model.User)
resolved, err := issue.ResolveMentionsByVisibility(db.DefaultContext, d, mentions)
assert.NoError(t, err)
ids := make([]int64, len(resolved))
diff --git a/models/issue_tracked_time.go b/models/issue_tracked_time.go
index 55d585a55c..392bf91e19 100644
--- a/models/issue_tracked_time.go
+++ b/models/issue_tracked_time.go
@@ -8,6 +8,7 @@ import (
"time"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"xorm.io/builder"
@@ -15,15 +16,15 @@ import (
// TrackedTime represents a time that was spent for a specific issue.
type TrackedTime struct {
- ID int64 `xorm:"pk autoincr"`
- IssueID int64 `xorm:"INDEX"`
- Issue *Issue `xorm:"-"`
- UserID int64 `xorm:"INDEX"`
- User *User `xorm:"-"`
- Created time.Time `xorm:"-"`
- CreatedUnix int64 `xorm:"created"`
- Time int64 `xorm:"NOT NULL"`
- Deleted bool `xorm:"NOT NULL DEFAULT false"`
+ ID int64 `xorm:"pk autoincr"`
+ IssueID int64 `xorm:"INDEX"`
+ Issue *Issue `xorm:"-"`
+ UserID int64 `xorm:"INDEX"`
+ User *user_model.User `xorm:"-"`
+ Created time.Time `xorm:"-"`
+ CreatedUnix int64 `xorm:"created"`
+ Time int64 `xorm:"NOT NULL"`
+ Deleted bool `xorm:"NOT NULL DEFAULT false"`
}
func init() {
@@ -55,7 +56,7 @@ func (t *TrackedTime) loadAttributes(e db.Engine) (err error) {
}
}
if t.User == nil {
- t.User, err = getUserByID(e, t.UserID)
+ t.User, err = user_model.GetUserByIDEngine(e, t.UserID)
if err != nil {
return
}
@@ -153,7 +154,7 @@ func GetTrackedSeconds(opts FindTrackedTimesOptions) (int64, error) {
}
// AddTime will add the given time (in seconds) to the issue
-func AddTime(user *User, issue *Issue, amount int64, created time.Time) (*TrackedTime, error) {
+func AddTime(user *user_model.User, issue *Issue, amount int64, created time.Time) (*TrackedTime, error) {
ctx, committer, err := db.TxContext()
if err != nil {
return nil, err
@@ -184,7 +185,7 @@ func AddTime(user *User, issue *Issue, amount int64, created time.Time) (*Tracke
return t, committer.Commit()
}
-func addTime(e db.Engine, user *User, issue *Issue, amount int64, created time.Time) (*TrackedTime, error) {
+func addTime(e db.Engine, user *user_model.User, issue *Issue, amount int64, created time.Time) (*TrackedTime, error) {
if created.IsZero() {
created = time.Now()
}
@@ -202,7 +203,7 @@ func addTime(e db.Engine, user *User, issue *Issue, amount int64, created time.T
}
// TotalTimes returns the spent time for each user by an issue
-func TotalTimes(options *FindTrackedTimesOptions) (map[*User]string, error) {
+func TotalTimes(options *FindTrackedTimesOptions) (map[*user_model.User]string, error) {
trackedTimes, err := GetTrackedTimes(options)
if err != nil {
return nil, err
@@ -213,12 +214,12 @@ func TotalTimes(options *FindTrackedTimesOptions) (map[*User]string, error) {
totalTimesByUser[t.UserID] += t.Time
}
- totalTimes := make(map[*User]string)
+ totalTimes := make(map[*user_model.User]string)
// Fetching User and making time human readable
for userID, total := range totalTimesByUser {
- user, err := GetUserByID(userID)
+ user, err := user_model.GetUserByID(userID)
if err != nil {
- if IsErrUserNotExist(err) {
+ if user_model.IsErrUserNotExist(err) {
continue
}
return nil, err
@@ -229,7 +230,7 @@ func TotalTimes(options *FindTrackedTimesOptions) (map[*User]string, error) {
}
// DeleteIssueUserTimes deletes times for issue
-func DeleteIssueUserTimes(issue *Issue, user *User) error {
+func DeleteIssueUserTimes(issue *Issue, user *user_model.User) error {
ctx, committer, err := db.TxContext()
if err != nil {
return err
diff --git a/models/issue_tracked_time_test.go b/models/issue_tracked_time_test.go
index 83420f5a15..97efd8bb72 100644
--- a/models/issue_tracked_time_test.go
+++ b/models/issue_tracked_time_test.go
@@ -9,6 +9,7 @@ import (
"time"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"github.com/stretchr/testify/assert"
)
@@ -16,7 +17,7 @@ import (
func TestAddTime(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- user3, err := GetUserByID(3)
+ user3, err := user_model.GetUserByID(3)
assert.NoError(t, err)
issue1, err := GetIssueByID(1)
diff --git a/models/issue_watch.go b/models/issue_watch.go
index 5bac406ad0..bf5c2593a3 100644
--- a/models/issue_watch.go
+++ b/models/issue_watch.go
@@ -6,6 +6,7 @@ package models
import (
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/timeutil"
)
@@ -71,7 +72,7 @@ func getIssueWatch(e db.Engine, userID, issueID int64) (iw *IssueWatch, exists b
// CheckIssueWatch check if an user is watching an issue
// it takes participants and repo watch into account
-func CheckIssueWatch(user *User, issue *Issue) (bool, error) {
+func CheckIssueWatch(user *user_model.User, issue *Issue) (bool, error) {
iw, exist, err := getIssueWatch(db.GetEngine(db.DefaultContext), user.ID, issue.ID)
if err != nil {
return false, err
diff --git a/models/issue_xref.go b/models/issue_xref.go
index 55483ce57b..ceaff62be1 100644
--- a/models/issue_xref.go
+++ b/models/issue_xref.go
@@ -9,6 +9,7 @@ import (
"fmt"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/references"
)
@@ -21,7 +22,7 @@ type crossReference struct {
// crossReferencesContext is context to pass along findCrossReference functions
type crossReferencesContext struct {
Type CommentType
- Doer *User
+ Doer *user_model.User
OrigIssue *Issue
OrigComment *Comment
RemoveOld bool
@@ -60,7 +61,7 @@ func neuterCrossReferencesIds(e db.Engine, ids []int64) error {
// \/ \/ \/
//
-func (issue *Issue) addCrossReferences(stdCtx context.Context, doer *User, removeOld bool) error {
+func (issue *Issue) addCrossReferences(stdCtx context.Context, doer *user_model.User, removeOld bool) error {
var commentType CommentType
if issue.IsPull {
commentType = CommentTypePullRef
@@ -242,7 +243,7 @@ func (issue *Issue) verifyReferencedIssue(e db.Engine, ctx *crossReferencesConte
// \/ \/ \/ \/ \/
//
-func (comment *Comment) addCrossReferences(stdCtx context.Context, doer *User, removeOld bool) error {
+func (comment *Comment) addCrossReferences(stdCtx context.Context, doer *user_model.User, removeOld bool) error {
if comment.Type != CommentTypeCode && comment.Type != CommentTypeComment {
return nil
}
diff --git a/models/issue_xref_test.go b/models/issue_xref_test.go
index c40e545fa8..06f937c80d 100644
--- a/models/issue_xref_test.go
+++ b/models/issue_xref_test.go
@@ -10,6 +10,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/references"
"github.com/stretchr/testify/assert"
@@ -79,7 +80,7 @@ func TestXRef_NeuterCrossReferences(t *testing.T) {
assert.Equal(t, CommentTypeIssueRef, ref.Type)
assert.Equal(t, references.XRefActionNone, ref.RefAction)
- d := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
i.Title = "title2, no mentions"
assert.NoError(t, i.ChangeTitle(d, title))
@@ -91,7 +92,7 @@ func TestXRef_NeuterCrossReferences(t *testing.T) {
func TestXRef_ResolveCrossReferences(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- d := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
i1 := testCreateIssue(t, 1, 2, "title1", "content1", false)
i2 := testCreateIssue(t, 1, 2, "title2", "content2", false)
@@ -126,7 +127,7 @@ func TestXRef_ResolveCrossReferences(t *testing.T) {
func testCreateIssue(t *testing.T, repo, doer int64, title, content string, ispull bool) *Issue {
r := unittest.AssertExistsAndLoadBean(t, &Repository{ID: repo}).(*Repository)
- d := unittest.AssertExistsAndLoadBean(t, &User{ID: doer}).(*User)
+ d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer}).(*user_model.User)
idx, err := db.GetNextResourceIndex("issue_index", r.ID)
assert.NoError(t, err)
@@ -157,7 +158,7 @@ func testCreateIssue(t *testing.T, repo, doer int64, title, content string, ispu
func testCreatePR(t *testing.T, repo, doer int64, title, content string) *PullRequest {
r := unittest.AssertExistsAndLoadBean(t, &Repository{ID: repo}).(*Repository)
- d := unittest.AssertExistsAndLoadBean(t, &User{ID: doer}).(*User)
+ d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer}).(*user_model.User)
i := &Issue{RepoID: r.ID, PosterID: d.ID, Poster: d, Title: title, Content: content, IsPull: true}
pr := &PullRequest{HeadRepoID: repo, BaseRepoID: repo, HeadBranch: "head", BaseBranch: "base", Status: PullRequestStatusMergeable}
assert.NoError(t, NewPullRequest(r, i, nil, nil, pr))
@@ -166,7 +167,7 @@ func testCreatePR(t *testing.T, repo, doer int64, title, content string) *PullRe
}
func testCreateComment(t *testing.T, repo, doer, issue int64, content string) *Comment {
- d := unittest.AssertExistsAndLoadBean(t, &User{ID: doer}).(*User)
+ d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer}).(*user_model.User)
i := unittest.AssertExistsAndLoadBean(t, &Issue{ID: issue}).(*Issue)
c := &Comment{Type: CommentTypeComment, PosterID: doer, Poster: d, IssueID: issue, Issue: i, Content: content}
diff --git a/models/lfs.go b/models/lfs.go
index 40539d2b78..da5e61ed0b 100644
--- a/models/lfs.go
+++ b/models/lfs.go
@@ -8,6 +8,7 @@ import (
"errors"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/timeutil"
@@ -132,7 +133,7 @@ func (repo *Repository) CountLFSMetaObjects() (int64, error) {
}
// LFSObjectAccessible checks if a provided Oid is accessible to the user
-func LFSObjectAccessible(user *User, oid string) (bool, error) {
+func LFSObjectAccessible(user *user_model.User, oid string) (bool, error) {
if user.IsAdmin {
count, err := db.GetEngine(db.DefaultContext).Count(&LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}})
return count > 0, err
@@ -143,7 +144,7 @@ func LFSObjectAccessible(user *User, oid string) (bool, error) {
}
// LFSAutoAssociate auto associates accessible LFSMetaObjects
-func LFSAutoAssociate(metas []*LFSMetaObject, user *User, repoID int64) error {
+func LFSAutoAssociate(metas []*LFSMetaObject, user *user_model.User, repoID int64) error {
ctx, committer, err := db.TxContext()
if err != nil {
return err
diff --git a/models/lfs_lock.go b/models/lfs_lock.go
index 943699290f..15513ea1dd 100644
--- a/models/lfs_lock.go
+++ b/models/lfs_lock.go
@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unit"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"xorm.io/xorm"
@@ -22,7 +23,6 @@ type LFSLock struct {
ID int64 `xorm:"pk autoincr"`
Repo *Repository `xorm:"-"`
RepoID int64 `xorm:"INDEX NOT NULL"`
- Owner *User `xorm:"-"`
OwnerID int64 `xorm:"INDEX NOT NULL"`
Path string `xorm:"TEXT"`
Created time.Time `xorm:"created"`
@@ -34,7 +34,6 @@ func init() {
// BeforeInsert is invoked from XORM before inserting an object of this type.
func (l *LFSLock) BeforeInsert() {
- l.OwnerID = l.Owner.ID
l.RepoID = l.Repo.ID
l.Path = cleanPath(l.Path)
}
@@ -42,10 +41,6 @@ func (l *LFSLock) BeforeInsert() {
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
func (l *LFSLock) AfterLoad(session *xorm.Session) {
var err error
- l.Owner, err = getUserByID(session, l.OwnerID)
- if err != nil {
- log.Error("LFS lock AfterLoad failed OwnerId[%d] not found: %v", l.OwnerID, err)
- }
l.Repo, err = getRepositoryByID(session, l.RepoID)
if err != nil {
log.Error("LFS lock AfterLoad failed RepoId[%d] not found: %v", l.RepoID, err)
@@ -58,7 +53,7 @@ func cleanPath(p string) string {
// CreateLFSLock creates a new lock.
func CreateLFSLock(lock *LFSLock) (*LFSLock, error) {
- err := CheckLFSAccessForRepo(lock.Owner, lock.Repo, AccessModeWrite)
+ err := CheckLFSAccessForRepo(lock.OwnerID, lock.Repo, AccessModeWrite)
if err != nil {
return nil, err
}
@@ -123,13 +118,13 @@ func CountLFSLockByRepoID(repoID int64) (int64, error) {
}
// DeleteLFSLockByID deletes a lock by given ID.
-func DeleteLFSLockByID(id int64, u *User, force bool) (*LFSLock, error) {
+func DeleteLFSLockByID(id int64, u *user_model.User, force bool) (*LFSLock, error) {
lock, err := GetLFSLockByID(id)
if err != nil {
return nil, err
}
- err = CheckLFSAccessForRepo(u, lock.Repo, AccessModeWrite)
+ err = CheckLFSAccessForRepo(u.ID, lock.Repo, AccessModeWrite)
if err != nil {
return nil, err
}
@@ -143,10 +138,14 @@ func DeleteLFSLockByID(id int64, u *User, force bool) (*LFSLock, error) {
}
// CheckLFSAccessForRepo check needed access mode base on action
-func CheckLFSAccessForRepo(u *User, repo *Repository, mode AccessMode) error {
- if u == nil {
+func CheckLFSAccessForRepo(ownerID int64, repo *Repository, mode AccessMode) error {
+ if ownerID == 0 {
return ErrLFSUnauthorizedAction{repo.ID, "undefined", mode}
}
+ u, err := user_model.GetUserByID(ownerID)
+ if err != nil {
+ return err
+ }
perm, err := GetUserRepoPermission(repo, u)
if err != nil {
return err
diff --git a/models/main_test.go b/models/main_test.go
index 5c99a2b2f7..87e59f5b11 100644
--- a/models/main_test.go
+++ b/models/main_test.go
@@ -8,6 +8,7 @@ import (
"testing"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"github.com/stretchr/testify/assert"
)
@@ -16,7 +17,7 @@ import (
func TestFixturesAreConsistent(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
unittest.CheckConsistencyFor(t,
- &User{},
+ &user_model.User{},
&Repository{},
&Issue{},
&PullRequest{},
diff --git a/models/notification.go b/models/notification.go
index db78558647..ef8a1e83b8 100644
--- a/models/notification.go
+++ b/models/notification.go
@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unit"
+ 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"
@@ -62,10 +63,10 @@ type Notification struct {
UpdatedBy int64 `xorm:"INDEX NOT NULL"`
- Issue *Issue `xorm:"-"`
- Repository *Repository `xorm:"-"`
- Comment *Comment `xorm:"-"`
- User *User `xorm:"-"`
+ Issue *Issue `xorm:"-"`
+ Repository *Repository `xorm:"-"`
+ Comment *Comment `xorm:"-"`
+ User *user_model.User `xorm:"-"`
CreatedUnix timeutil.TimeStamp `xorm:"created INDEX NOT NULL"`
UpdatedUnix timeutil.TimeStamp `xorm:"updated INDEX NOT NULL"`
@@ -139,7 +140,7 @@ func CountNotifications(opts *FindNotificationOptions) (int64, error) {
}
// CreateRepoTransferNotification creates notification for the user a repository was transferred to
-func CreateRepoTransferNotification(doer, newOwner *User, repo *Repository) error {
+func CreateRepoTransferNotification(doer, newOwner *user_model.User, repo *Repository) error {
ctx, committer, err := db.TxContext()
if err != nil {
return err
@@ -258,9 +259,9 @@ func createOrUpdateIssueNotifications(e db.Engine, issueID, commentID, notificat
// notify
for userID := range toNotify {
issue.Repo.Units = nil
- user, err := getUserByID(e, userID)
+ user, err := user_model.GetUserByIDEngine(e, userID)
if err != nil {
- if IsErrUserNotExist(err) {
+ if user_model.IsErrUserNotExist(err) {
continue
}
@@ -355,11 +356,11 @@ func getIssueNotification(e db.Engine, userID, issueID int64) (*Notification, er
}
// NotificationsForUser returns notifications for a given user and status
-func NotificationsForUser(user *User, statuses []NotificationStatus, page, perPage int) (NotificationList, error) {
+func NotificationsForUser(user *user_model.User, statuses []NotificationStatus, page, perPage int) (NotificationList, error) {
return notificationsForUser(db.GetEngine(db.DefaultContext), user, statuses, page, perPage)
}
-func notificationsForUser(e db.Engine, user *User, statuses []NotificationStatus, page, perPage int) (notifications []*Notification, err error) {
+func notificationsForUser(e db.Engine, user *user_model.User, statuses []NotificationStatus, page, perPage int) (notifications []*Notification, err error) {
if len(statuses) == 0 {
return
}
@@ -378,7 +379,7 @@ func notificationsForUser(e db.Engine, user *User, statuses []NotificationStatus
}
// CountUnread count unread notifications for a user
-func CountUnread(user *User) int64 {
+func CountUnread(user *user_model.User) int64 {
return countUnread(db.GetEngine(db.DefaultContext), user.ID)
}
@@ -452,7 +453,7 @@ func (n *Notification) loadComment(e db.Engine) (err error) {
func (n *Notification) loadUser(e db.Engine) (err error) {
if n.User == nil {
- n.User, err = getUserByID(e, n.UserID)
+ n.User, err = user_model.GetUserByIDEngine(e, n.UserID)
if err != nil {
return fmt.Errorf("getUserByID [%d]: %v", n.UserID, err)
}
@@ -733,11 +734,11 @@ func (nl NotificationList) LoadComments() ([]int, error) {
}
// GetNotificationCount returns the notification count for user
-func GetNotificationCount(user *User, status NotificationStatus) (int64, error) {
+func GetNotificationCount(user *user_model.User, status NotificationStatus) (int64, error) {
return getNotificationCount(db.GetEngine(db.DefaultContext), user, status)
}
-func getNotificationCount(e db.Engine, user *User, status NotificationStatus) (count int64, err error) {
+func getNotificationCount(e db.Engine, user *user_model.User, status NotificationStatus) (count int64, err error) {
count, err = e.
Where("user_id = ?", user.ID).
And("status = ?", status).
@@ -788,7 +789,7 @@ func setRepoNotificationStatusReadIfUnread(e db.Engine, userID, repoID int64) er
}
// SetNotificationStatus change the notification status
-func SetNotificationStatus(notificationID int64, user *User, status NotificationStatus) (*Notification, error) {
+func SetNotificationStatus(notificationID int64, user *user_model.User, status NotificationStatus) (*Notification, error) {
notification, err := getNotificationByID(db.GetEngine(db.DefaultContext), notificationID)
if err != nil {
return notification, err
@@ -826,7 +827,7 @@ func getNotificationByID(e db.Engine, notificationID int64) (*Notification, erro
}
// UpdateNotificationStatuses updates the statuses of all of a user's notifications that are of the currentStatus type to the desiredStatus
-func UpdateNotificationStatuses(user *User, currentStatus, desiredStatus NotificationStatus) error {
+func UpdateNotificationStatuses(user *user_model.User, currentStatus, desiredStatus NotificationStatus) error {
n := &Notification{Status: desiredStatus, UpdatedBy: user.ID}
_, err := db.GetEngine(db.DefaultContext).
Where("user_id = ? AND status = ?", user.ID, currentStatus).
diff --git a/models/notification_test.go b/models/notification_test.go
index 19fad25f99..3b05f34c55 100644
--- a/models/notification_test.go
+++ b/models/notification_test.go
@@ -8,6 +8,7 @@ import (
"testing"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"github.com/stretchr/testify/assert"
)
@@ -29,7 +30,7 @@ func TestCreateOrUpdateIssueNotifications(t *testing.T) {
func TestNotificationsForUser(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
statuses := []NotificationStatus{NotificationStatusRead, NotificationStatusUnread}
notfs, err := NotificationsForUser(user, statuses, 1, 10)
assert.NoError(t, err)
@@ -63,7 +64,7 @@ func TestNotification_GetIssue(t *testing.T) {
func TestGetNotificationCount(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
cnt, err := GetNotificationCount(user, NotificationStatusRead)
assert.NoError(t, err)
assert.EqualValues(t, 0, cnt)
@@ -75,7 +76,7 @@ func TestGetNotificationCount(t *testing.T) {
func TestSetNotificationStatus(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
notf := unittest.AssertExistsAndLoadBean(t,
&Notification{UserID: user.ID, Status: NotificationStatusRead}).(*Notification)
_, err := SetNotificationStatus(notf.ID, user, NotificationStatusPinned)
@@ -91,7 +92,7 @@ func TestSetNotificationStatus(t *testing.T) {
func TestUpdateNotificationStatuses(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
notfUnread := unittest.AssertExistsAndLoadBean(t,
&Notification{UserID: user.ID, Status: NotificationStatusUnread}).(*Notification)
notfRead := unittest.AssertExistsAndLoadBean(t,
diff --git a/models/org.go b/models/org.go
index ea73d03d42..63e1b99af5 100644
--- a/models/org.go
+++ b/models/org.go
@@ -21,10 +21,10 @@ import (
)
// Organization represents an organization
-type Organization User
+type Organization user_model.User
// OrgFromUser converts user to organization
-func OrgFromUser(user *User) *Organization {
+func OrgFromUser(user *user_model.User) *Organization {
return (*Organization)(user)
}
@@ -188,8 +188,8 @@ func (org *Organization) RemoveOrgRepo(repoID int64) error {
}
// AsUser returns the org as user object
-func (org *Organization) AsUser() *User {
- return (*User)(org)
+func (org *Organization) AsUser() *user_model.User {
+ return (*user_model.User)(org)
}
// DisplayName returns full name if it's not empty,
@@ -204,34 +204,34 @@ func (org *Organization) CustomAvatarRelativePath() string {
}
// CreateOrganization creates record of a new organization.
-func CreateOrganization(org *Organization, owner *User) (err error) {
+func CreateOrganization(org *Organization, owner *user_model.User) (err error) {
if !owner.CanCreateOrganization() {
return ErrUserNotAllowedCreateOrg{}
}
- if err = IsUsableUsername(org.Name); err != nil {
+ if err = user_model.IsUsableUsername(org.Name); err != nil {
return err
}
- isExist, err := IsUserExist(0, org.Name)
+ isExist, err := user_model.IsUserExist(0, org.Name)
if err != nil {
return err
} else if isExist {
- return ErrUserAlreadyExist{org.Name}
+ return user_model.ErrUserAlreadyExist{Name: org.Name}
}
org.LowerName = strings.ToLower(org.Name)
- if org.Rands, err = GetUserSalt(); err != nil {
+ if org.Rands, err = user_model.GetUserSalt(); err != nil {
return err
}
- if org.Salt, err = GetUserSalt(); err != nil {
+ if org.Salt, err = user_model.GetUserSalt(); err != nil {
return err
}
org.UseCustomAvatar = true
org.MaxRepoCreation = -1
org.NumTeams = 1
org.NumMembers = 1
- org.Type = UserTypeOrganization
+ org.Type = user_model.UserTypeOrganization
ctx, committer, err := db.TxContext()
if err != nil {
@@ -246,7 +246,7 @@ func CreateOrganization(org *Organization, owner *User) (err error) {
if err = db.Insert(ctx, org); err != nil {
return fmt.Errorf("insert organization: %v", err)
}
- if err = generateRandomAvatar(db.GetEngine(ctx), org.AsUser()); err != nil {
+ if err = user_model.GenerateRandomAvatarCtx(ctx, org.AsUser()); err != nil {
return fmt.Errorf("generate random avatar: %v", err)
}
@@ -304,7 +304,7 @@ func GetOrgByName(name string) (*Organization, error) {
}
u := &Organization{
LowerName: strings.ToLower(name),
- Type: UserTypeOrganization,
+ Type: user_model.UserTypeOrganization,
}
has, err := db.GetEngine(db.DefaultContext).Get(u)
if err != nil {
@@ -325,7 +325,7 @@ func CountOrganizations() int64 {
// DeleteOrganization deletes models associated to an organization.
func DeleteOrganization(ctx context.Context, org *Organization) error {
- if org.Type != UserTypeOrganization {
+ if org.Type != user_model.UserTypeOrganization {
return fmt.Errorf("%s is a user not an organization", org.Name)
}
@@ -340,7 +340,7 @@ func DeleteOrganization(ctx context.Context, org *Organization) error {
return fmt.Errorf("deleteBeans: %v", err)
}
- if _, err := e.ID(org.ID).Delete(new(User)); err != nil {
+ if _, err := e.ID(org.ID).Delete(new(user_model.User)); err != nil {
return fmt.Errorf("Delete: %v", err)
}
@@ -433,12 +433,12 @@ func (org *Organization) GetOrgUserMaxAuthorizeLevel(uid int64) (AccessMode, err
}
// GetUsersWhoCanCreateOrgRepo returns users which are able to create repo in organization
-func GetUsersWhoCanCreateOrgRepo(orgID int64) ([]*User, error) {
+func GetUsersWhoCanCreateOrgRepo(orgID int64) ([]*user_model.User, error) {
return getUsersWhoCanCreateOrgRepo(db.GetEngine(db.DefaultContext), orgID)
}
-func getUsersWhoCanCreateOrgRepo(e db.Engine, orgID int64) ([]*User, error) {
- users := make([]*User, 0, 10)
+func getUsersWhoCanCreateOrgRepo(e db.Engine, orgID int64) ([]*user_model.User, error) {
+ users := make([]*user_model.User, 0, 10)
return users, e.
Join("INNER", "`team_user`", "`team_user`.uid=`user`.id").
Join("INNER", "`team`", "`team`.id=`team_user`.team_id").
@@ -450,8 +450,8 @@ func getUsersWhoCanCreateOrgRepo(e db.Engine, orgID int64) ([]*User, error) {
type MinimalOrg = Organization
// GetUserOrgsList returns one user's all orgs list
-func GetUserOrgsList(user *User) ([]*MinimalOrg, error) {
- schema, err := db.TableInfo(new(User))
+func GetUserOrgsList(user *user_model.User) ([]*MinimalOrg, error) {
+ schema, err := db.TableInfo(new(user_model.User))
if err != nil {
return nil, err
}
@@ -507,6 +507,12 @@ func GetUserOrgsList(user *User) ([]*MinimalOrg, error) {
return orgs, nil
}
+// SearchOrganizationsOptions options to filter organizations
+type SearchOrganizationsOptions struct {
+ db.ListOptions
+ All bool
+}
+
// FindOrgOptions finds orgs options
type FindOrgOptions struct {
db.ListOptions
@@ -549,7 +555,7 @@ func FindOrgs(opts FindOrgOptions) ([]*Organization, error) {
func CountOrgs(opts FindOrgOptions) (int64, error) {
return db.GetEngine(db.DefaultContext).
Where(opts.toConds()).
- Count(new(User))
+ Count(new(user_model.User))
}
func getOwnedOrgsByUserID(sess db.Engine, userID int64) ([]*Organization, error) {
@@ -564,11 +570,11 @@ func getOwnedOrgsByUserID(sess db.Engine, userID int64) ([]*Organization, error)
}
// HasOrgOrUserVisible tells if the given user can see the given org or user
-func HasOrgOrUserVisible(org, user *User) bool {
+func HasOrgOrUserVisible(org, user *user_model.User) bool {
return hasOrgOrUserVisible(db.GetEngine(db.DefaultContext), org, user)
}
-func hasOrgOrUserVisible(e db.Engine, orgOrUser, user *User) bool {
+func hasOrgOrUserVisible(e db.Engine, orgOrUser, user *user_model.User) bool {
// Not SignedUser
if user == nil {
return orgOrUser.Visibility == structs.VisibleTypePublic
@@ -585,7 +591,7 @@ func hasOrgOrUserVisible(e db.Engine, orgOrUser, user *User) bool {
}
// HasOrgsVisible tells if the given user can see at least one of the orgs provided
-func HasOrgsVisible(orgs []*Organization, user *User) bool {
+func HasOrgsVisible(orgs []*Organization, user *user_model.User) bool {
if len(orgs) == 0 {
return false
}
@@ -718,7 +724,11 @@ func GetOrgByIDCtx(ctx context.Context, id int64) (*Organization, error) {
if err != nil {
return nil, err
} else if !has {
- return nil, ErrUserNotExist{id, "", 0}
+ return nil, user_model.ErrUserNotExist{
+ UID: id,
+ Name: "",
+ KeyID: 0,
+ }
}
return u, nil
}
@@ -896,17 +906,17 @@ type AccessibleReposEnvironment interface {
Repos(page, pageSize int) ([]*Repository, error)
MirrorRepos() ([]*Repository, error)
AddKeyword(keyword string)
- SetSort(SearchOrderBy)
+ SetSort(db.SearchOrderBy)
}
type accessibleReposEnv struct {
org *Organization
- user *User
+ user *user_model.User
team *Team
teamIDs []int64
e db.Engine
keyword string
- orderBy SearchOrderBy
+ orderBy db.SearchOrderBy
}
// AccessibleReposEnv builds an AccessibleReposEnvironment for the repositories in `org`
@@ -916,10 +926,10 @@ func (org *Organization) AccessibleReposEnv(userID int64) (AccessibleReposEnviro
}
func (org *Organization) accessibleReposEnv(e db.Engine, userID int64) (AccessibleReposEnvironment, error) {
- var user *User
+ var user *user_model.User
if userID > 0 {
- u, err := getUserByID(e, userID)
+ u, err := user_model.GetUserByIDEngine(e, userID)
if err != nil {
return nil, err
}
@@ -935,7 +945,7 @@ func (org *Organization) accessibleReposEnv(e db.Engine, userID int64) (Accessib
user: user,
teamIDs: teamIDs,
e: e,
- orderBy: SearchOrderByRecentUpdated,
+ orderBy: db.SearchOrderByRecentUpdated,
}, nil
}
@@ -946,7 +956,7 @@ func (org *Organization) AccessibleTeamReposEnv(team *Team) AccessibleReposEnvir
org: org,
team: team,
e: db.GetEngine(db.DefaultContext),
- orderBy: SearchOrderByRecentUpdated,
+ orderBy: db.SearchOrderByRecentUpdated,
}
}
@@ -1049,6 +1059,6 @@ func (env *accessibleReposEnv) AddKeyword(keyword string) {
env.keyword = keyword
}
-func (env *accessibleReposEnv) SetSort(orderBy SearchOrderBy) {
+func (env *accessibleReposEnv) SetSort(orderBy db.SearchOrderBy) {
env.orderBy = orderBy
}
diff --git a/models/org_team.go b/models/org_team.go
index 1bdffe2cb1..510a0dcfaa 100644
--- a/models/org_team.go
+++ b/models/org_team.go
@@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unit"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@@ -30,8 +31,8 @@ type Team struct {
Name string
Description string
Authorize AccessMode
- Repos []*Repository `xorm:"-"`
- Members []*User `xorm:"-"`
+ Repos []*Repository `xorm:"-"`
+ Members []*user_model.User `xorm:"-"`
NumRepos int
NumMembers int
Units []*TeamUnit `xorm:"-"`
@@ -456,7 +457,7 @@ func (t *Team) unitEnabled(e db.Engine, tp unit.Type) bool {
func IsUsableTeamName(name string) error {
switch name {
case "new":
- return ErrNameReserved{name}
+ return db.ErrNameReserved{Name: name}
default:
return nil
}
@@ -473,7 +474,7 @@ func NewTeam(t *Team) (err error) {
return err
}
- has, err := db.GetEngine(db.DefaultContext).ID(t.OrgID).Get(new(User))
+ has, err := db.GetEngine(db.DefaultContext).ID(t.OrgID).Get(new(user_model.User))
if err != nil {
return err
}
@@ -760,14 +761,14 @@ func getTeamUsersByTeamID(e db.Engine, teamID int64) ([]*TeamUser, error) {
Find(&teamUsers)
}
-func getTeamMembers(e db.Engine, teamID int64) (_ []*User, err error) {
+func getTeamMembers(e db.Engine, teamID int64) (_ []*user_model.User, err error) {
teamUsers, err := getTeamUsersByTeamID(e, teamID)
if err != nil {
return nil, fmt.Errorf("get team-users: %v", err)
}
- members := make([]*User, len(teamUsers))
+ members := make([]*user_model.User, len(teamUsers))
for i, teamUser := range teamUsers {
- member, err := getUserByID(e, teamUser.UID)
+ member, err := user_model.GetUserByIDEngine(e, teamUser.UID)
if err != nil {
return nil, fmt.Errorf("get user '%d': %v", teamUser.UID, err)
}
@@ -780,7 +781,7 @@ func getTeamMembers(e db.Engine, teamID int64) (_ []*User, err error) {
}
// GetTeamMembers returns all members in given team of organization.
-func GetTeamMembers(teamID int64) ([]*User, error) {
+func GetTeamMembers(teamID int64) ([]*user_model.User, error) {
return getTeamMembers(db.GetEngine(db.DefaultContext), teamID)
}
diff --git a/models/org_team_test.go b/models/org_team_test.go
index b912dd83f2..450cf7dd55 100644
--- a/models/org_team_test.go
+++ b/models/org_team_test.go
@@ -8,7 +8,9 @@ import (
"strings"
"testing"
+ "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"github.com/stretchr/testify/assert"
)
@@ -74,7 +76,7 @@ func TestTeam_AddMember(t *testing.T) {
team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team)
assert.NoError(t, team.AddMember(userID))
unittest.AssertExistsAndLoadBean(t, &TeamUser{UID: userID, TeamID: teamID})
- unittest.CheckConsistencyFor(t, &Team{ID: teamID}, &User{ID: team.OrgID})
+ unittest.CheckConsistencyFor(t, &Team{ID: teamID}, &user_model.User{ID: team.OrgID})
}
test(1, 2)
test(1, 4)
@@ -151,7 +153,7 @@ func TestTeam_RemoveRepository(t *testing.T) {
func TestIsUsableTeamName(t *testing.T) {
assert.NoError(t, IsUsableTeamName("usable"))
- assert.True(t, IsErrNameReserved(IsUsableTeamName("new")))
+ assert.True(t, db.IsErrNameReserved(IsUsableTeamName("new")))
}
func TestNewTeam(t *testing.T) {
@@ -161,7 +163,7 @@ func TestNewTeam(t *testing.T) {
team := &Team{Name: teamName, OrgID: 3}
assert.NoError(t, NewTeam(team))
unittest.AssertExistsAndLoadBean(t, &Team{Name: teamName})
- unittest.CheckConsistencyFor(t, &Team{}, &User{ID: team.OrgID})
+ unittest.CheckConsistencyFor(t, &Team{}, &user_model.User{ID: team.OrgID})
}
func TestGetTeam(t *testing.T) {
@@ -243,7 +245,7 @@ func TestDeleteTeam(t *testing.T) {
unittest.AssertNotExistsBean(t, &TeamUser{TeamID: team.ID})
// check that team members don't have "leftover" access to repos
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: 4}).(*User)
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User)
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository)
accessMode, err := AccessLevel(user, repo)
assert.NoError(t, err)
@@ -321,7 +323,7 @@ func TestAddTeamMember(t *testing.T) {
team := unittest.AssertExistsAndLoadBean(t, &Team{ID: teamID}).(*Team)
assert.NoError(t, AddTeamMember(team, userID))
unittest.AssertExistsAndLoadBean(t, &TeamUser{UID: userID, TeamID: teamID})
- unittest.CheckConsistencyFor(t, &Team{ID: teamID}, &User{ID: team.OrgID})
+ unittest.CheckConsistencyFor(t, &Team{ID: teamID}, &user_model.User{ID: team.OrgID})
}
test(1, 2)
test(1, 4)
diff --git a/models/org_test.go b/models/org_test.go
index 805c63300b..c24064c5b8 100644
--- a/models/org_test.go
+++ b/models/org_test.go
@@ -9,6 +9,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
@@ -130,7 +131,7 @@ func TestUser_AddMember(t *testing.T) {
org = unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
assert.Equal(t, prevNumMembers, org.NumMembers)
- unittest.CheckConsistencyFor(t, &User{})
+ unittest.CheckConsistencyFor(t, &user_model.User{})
}
func TestUser_RemoveMember(t *testing.T) {
@@ -153,7 +154,7 @@ func TestUser_RemoveMember(t *testing.T) {
org = unittest.AssertExistsAndLoadBean(t, &Organization{ID: 3}).(*Organization)
assert.Equal(t, prevNumMembers, org.NumMembers)
- unittest.CheckConsistencyFor(t, &User{}, &Team{})
+ unittest.CheckConsistencyFor(t, &user_model.User{}, &Team{})
}
func TestUser_RemoveOrgRepo(t *testing.T) {
@@ -174,7 +175,7 @@ func TestUser_RemoveOrgRepo(t *testing.T) {
assert.NoError(t, org.RemoveOrgRepo(unittest.NonexistentID))
unittest.CheckConsistencyFor(t,
- &User{ID: org.ID},
+ &user_model.User{ID: org.ID},
&Team{OrgID: org.ID},
&Repository{ID: repo.ID})
}
@@ -183,37 +184,37 @@ func TestCreateOrganization(t *testing.T) {
// successful creation of org
assert.NoError(t, unittest.PrepareTestDatabase())
- owner := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
const newOrgName = "neworg"
org := &Organization{
Name: newOrgName,
}
- unittest.AssertNotExistsBean(t, &User{Name: newOrgName, Type: UserTypeOrganization})
+ unittest.AssertNotExistsBean(t, &user_model.User{Name: newOrgName, Type: user_model.UserTypeOrganization})
assert.NoError(t, CreateOrganization(org, owner))
org = unittest.AssertExistsAndLoadBean(t,
- &Organization{Name: newOrgName, Type: UserTypeOrganization}).(*Organization)
+ &Organization{Name: newOrgName, Type: user_model.UserTypeOrganization}).(*Organization)
ownerTeam := unittest.AssertExistsAndLoadBean(t,
&Team{Name: ownerTeamName, OrgID: org.ID}).(*Team)
unittest.AssertExistsAndLoadBean(t, &TeamUser{UID: owner.ID, TeamID: ownerTeam.ID})
- unittest.CheckConsistencyFor(t, &User{}, &Team{})
+ unittest.CheckConsistencyFor(t, &user_model.User{}, &Team{})
}
func TestCreateOrganization2(t *testing.T) {
// unauthorized creation of org
assert.NoError(t, unittest.PrepareTestDatabase())
- owner := unittest.AssertExistsAndLoadBean(t, &User{ID: 5}).(*User)
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User)
const newOrgName = "neworg"
org := &Organization{
Name: newOrgName,
}
- unittest.AssertNotExistsBean(t, &Organization{Name: newOrgName, Type: UserTypeOrganization})
+ unittest.AssertNotExistsBean(t, &Organization{Name: newOrgName, Type: user_model.UserTypeOrganization})
err := CreateOrganization(org, owner)
assert.Error(t, err)
assert.True(t, IsErrUserNotAllowedCreateOrg(err))
- unittest.AssertNotExistsBean(t, &Organization{Name: newOrgName, Type: UserTypeOrganization})
+ unittest.AssertNotExistsBean(t, &Organization{Name: newOrgName, Type: user_model.UserTypeOrganization})
unittest.CheckConsistencyFor(t, &Organization{}, &Team{})
}
@@ -221,23 +222,23 @@ func TestCreateOrganization3(t *testing.T) {
// create org with same name as existent org
assert.NoError(t, unittest.PrepareTestDatabase())
- owner := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
- org := &Organization{Name: "user3"} // should already exist
- unittest.AssertExistsAndLoadBean(t, &User{Name: org.Name}) // sanity check
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
+ org := &Organization{Name: "user3"} // should already exist
+ unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: org.Name}) // sanity check
err := CreateOrganization(org, owner)
assert.Error(t, err)
- assert.True(t, IsErrUserAlreadyExist(err))
- unittest.CheckConsistencyFor(t, &User{}, &Team{})
+ assert.True(t, user_model.IsErrUserAlreadyExist(err))
+ unittest.CheckConsistencyFor(t, &user_model.User{}, &Team{})
}
func TestCreateOrganization4(t *testing.T) {
// create org with unusable name
assert.NoError(t, unittest.PrepareTestDatabase())
- owner := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
err := CreateOrganization(&Organization{Name: "assets"}, owner)
assert.Error(t, err)
- assert.True(t, IsErrNameReserved(err))
+ assert.True(t, db.IsErrNameReserved(err))
unittest.CheckConsistencyFor(t, &Organization{}, &Team{})
}
@@ -258,7 +259,7 @@ func TestGetOrgByName(t *testing.T) {
func TestCountOrganizations(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- expected, err := db.GetEngine(db.DefaultContext).Where("type=?", UserTypeOrganization).Count(&User{})
+ expected, err := db.GetEngine(db.DefaultContext).Where("type=?", user_model.UserTypeOrganization).Count(&user_model.User{})
assert.NoError(t, err)
assert.Equal(t, expected, CountOrganizations())
}
@@ -444,7 +445,7 @@ func TestChangeOrgUserStatus(t *testing.T) {
func TestAddOrgUser(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
testSuccess := func(orgID, userID int64, isPublic bool) {
- org := unittest.AssertExistsAndLoadBean(t, &User{ID: orgID}).(*User)
+ org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: orgID}).(*user_model.User)
expectedNumMembers := org.NumMembers
if !unittest.BeanExists(t, &OrgUser{OrgID: orgID, UID: userID}) {
expectedNumMembers++
@@ -453,7 +454,7 @@ func TestAddOrgUser(t *testing.T) {
ou := &OrgUser{OrgID: orgID, UID: userID}
unittest.AssertExistsAndLoadBean(t, ou)
assert.Equal(t, isPublic, ou.IsPublic)
- org = unittest.AssertExistsAndLoadBean(t, &User{ID: orgID}).(*User)
+ org = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: orgID}).(*user_model.User)
assert.EqualValues(t, expectedNumMembers, org.NumMembers)
}
@@ -465,20 +466,20 @@ func TestAddOrgUser(t *testing.T) {
setting.Service.DefaultOrgMemberVisible = true
testSuccess(6, 3, true)
- unittest.CheckConsistencyFor(t, &User{}, &Team{})
+ unittest.CheckConsistencyFor(t, &user_model.User{}, &Team{})
}
func TestRemoveOrgUser(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
testSuccess := func(orgID, userID int64) {
- org := unittest.AssertExistsAndLoadBean(t, &User{ID: orgID}).(*User)
+ org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: orgID}).(*user_model.User)
expectedNumMembers := org.NumMembers
if unittest.BeanExists(t, &OrgUser{OrgID: orgID, UID: userID}) {
expectedNumMembers--
}
assert.NoError(t, RemoveOrgUser(orgID, userID))
unittest.AssertNotExistsBean(t, &OrgUser{OrgID: orgID, UID: userID})
- org = unittest.AssertExistsAndLoadBean(t, &User{ID: orgID}).(*User)
+ org = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: orgID}).(*user_model.User)
assert.EqualValues(t, expectedNumMembers, org.NumMembers)
}
testSuccess(3, 4)
@@ -488,7 +489,7 @@ func TestRemoveOrgUser(t *testing.T) {
assert.Error(t, err)
assert.True(t, IsErrLastOrgOwner(err))
unittest.AssertExistsAndLoadBean(t, &OrgUser{OrgID: 7, UID: 5})
- unittest.CheckConsistencyFor(t, &User{}, &Team{})
+ unittest.CheckConsistencyFor(t, &user_model.User{}, &Team{})
}
func TestUser_GetUserTeamIDs(t *testing.T) {
@@ -572,8 +573,8 @@ func TestAccessibleReposEnv_MirrorRepos(t *testing.T) {
func TestHasOrgVisibleTypePublic(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- owner := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
- user3 := unittest.AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
+ user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
const newOrgName = "test-org-public"
org := &Organization{
@@ -581,10 +582,10 @@ func TestHasOrgVisibleTypePublic(t *testing.T) {
Visibility: structs.VisibleTypePublic,
}
- unittest.AssertNotExistsBean(t, &User{Name: org.Name, Type: UserTypeOrganization})
+ unittest.AssertNotExistsBean(t, &user_model.User{Name: org.Name, Type: user_model.UserTypeOrganization})
assert.NoError(t, CreateOrganization(org, owner))
org = unittest.AssertExistsAndLoadBean(t,
- &Organization{Name: org.Name, Type: UserTypeOrganization}).(*Organization)
+ &Organization{Name: org.Name, Type: user_model.UserTypeOrganization}).(*Organization)
test1 := HasOrgOrUserVisible(org.AsUser(), owner)
test2 := HasOrgOrUserVisible(org.AsUser(), user3)
test3 := HasOrgOrUserVisible(org.AsUser(), nil)
@@ -595,8 +596,8 @@ func TestHasOrgVisibleTypePublic(t *testing.T) {
func TestHasOrgVisibleTypeLimited(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- owner := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
- user3 := unittest.AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
+ user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
const newOrgName = "test-org-limited"
org := &Organization{
@@ -604,10 +605,10 @@ func TestHasOrgVisibleTypeLimited(t *testing.T) {
Visibility: structs.VisibleTypeLimited,
}
- unittest.AssertNotExistsBean(t, &User{Name: org.Name, Type: UserTypeOrganization})
+ unittest.AssertNotExistsBean(t, &user_model.User{Name: org.Name, Type: user_model.UserTypeOrganization})
assert.NoError(t, CreateOrganization(org, owner))
org = unittest.AssertExistsAndLoadBean(t,
- &Organization{Name: org.Name, Type: UserTypeOrganization}).(*Organization)
+ &Organization{Name: org.Name, Type: user_model.UserTypeOrganization}).(*Organization)
test1 := HasOrgOrUserVisible(org.AsUser(), owner)
test2 := HasOrgOrUserVisible(org.AsUser(), user3)
test3 := HasOrgOrUserVisible(org.AsUser(), nil)
@@ -618,8 +619,8 @@ func TestHasOrgVisibleTypeLimited(t *testing.T) {
func TestHasOrgVisibleTypePrivate(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- owner := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
- user3 := unittest.AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
+ user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
const newOrgName = "test-org-private"
org := &Organization{
@@ -627,10 +628,10 @@ func TestHasOrgVisibleTypePrivate(t *testing.T) {
Visibility: structs.VisibleTypePrivate,
}
- unittest.AssertNotExistsBean(t, &User{Name: org.Name, Type: UserTypeOrganization})
+ unittest.AssertNotExistsBean(t, &user_model.User{Name: org.Name, Type: user_model.UserTypeOrganization})
assert.NoError(t, CreateOrganization(org, owner))
org = unittest.AssertExistsAndLoadBean(t,
- &Organization{Name: org.Name, Type: UserTypeOrganization}).(*Organization)
+ &Organization{Name: org.Name, Type: user_model.UserTypeOrganization}).(*Organization)
test1 := HasOrgOrUserVisible(org.AsUser(), owner)
test2 := HasOrgOrUserVisible(org.AsUser(), user3)
test3 := HasOrgOrUserVisible(org.AsUser(), nil)
diff --git a/models/project_issue.go b/models/project_issue.go
index 6f314ca931..fb08efa994 100644
--- a/models/project_issue.go
+++ b/models/project_issue.go
@@ -9,6 +9,7 @@ import (
"fmt"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
)
// ProjectIssue saves relation from issue to a project
@@ -130,7 +131,7 @@ func (p *Project) NumOpenIssues() int {
}
// ChangeProjectAssign changes the project associated with an issue
-func ChangeProjectAssign(issue *Issue, doer *User, newProjectID int64) error {
+func ChangeProjectAssign(issue *Issue, doer *user_model.User, newProjectID int64) error {
ctx, committer, err := db.TxContext()
if err != nil {
return err
@@ -144,7 +145,7 @@ func ChangeProjectAssign(issue *Issue, doer *User, newProjectID int64) error {
return committer.Commit()
}
-func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *User, newProjectID int64) error {
+func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.User, newProjectID int64) error {
e := db.GetEngine(ctx)
oldProjectID := issue.projectID(e)
diff --git a/models/pull.go b/models/pull.go
index 1e1dd13c57..85ca0b3fc8 100644
--- a/models/pull.go
+++ b/models/pull.go
@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unit"
+ 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"
@@ -78,7 +79,7 @@ type PullRequest struct {
HasMerged bool `xorm:"INDEX"`
MergedCommitID string `xorm:"VARCHAR(40)"`
MergerID int64 `xorm:"INDEX"`
- Merger *User `xorm:"-"`
+ Merger *user_model.User `xorm:"-"`
MergedUnix timeutil.TimeStamp `xorm:"updated INDEX"`
isHeadRepoLoaded bool `xorm:"-"`
@@ -109,10 +110,10 @@ func (pr *PullRequest) MustHeadUserName() string {
// Note: don't try to get Issue because will end up recursive querying.
func (pr *PullRequest) loadAttributes(e db.Engine) (err error) {
if pr.HasMerged && pr.Merger == nil {
- pr.Merger, err = getUserByID(e, pr.MergerID)
- if IsErrUserNotExist(err) {
+ pr.Merger, err = user_model.GetUserByIDEngine(e, pr.MergerID)
+ if user_model.IsErrUserNotExist(err) {
pr.MergerID = -1
- pr.Merger = NewGhostUser()
+ pr.Merger = user_model.NewGhostUser()
} else if err != nil {
return fmt.Errorf("getUserByID [%d]: %v", pr.MergerID, err)
}
@@ -310,7 +311,7 @@ func (pr *PullRequest) getReviewedByLines(writer io.Writer) error {
break
}
- if err := review.loadReviewer(sess); err != nil && !IsErrUserNotExist(err) {
+ if err := review.loadReviewer(sess); err != nil && !user_model.IsErrUserNotExist(err) {
log.Error("Unable to LoadReviewer[%d] for PR ID %d : %v", review.ReviewerID, pr.ID, err)
return err
} else if review.Reviewer == nil {
diff --git a/models/pull_list.go b/models/pull_list.go
index 57ef210213..7c5b83ae5f 100644
--- a/models/pull_list.go
+++ b/models/pull_list.go
@@ -8,6 +8,7 @@ import (
"fmt"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
@@ -147,7 +148,7 @@ func (prs PullRequestList) LoadAttributes() error {
return prs.loadAttributes(db.GetEngine(db.DefaultContext))
}
-func (prs PullRequestList) invalidateCodeComments(e db.Engine, doer *User, repo *git.Repository, branch string) error {
+func (prs PullRequestList) invalidateCodeComments(e db.Engine, doer *user_model.User, repo *git.Repository, branch string) error {
if len(prs) == 0 {
return nil
}
@@ -168,6 +169,6 @@ func (prs PullRequestList) invalidateCodeComments(e db.Engine, doer *User, repo
}
// InvalidateCodeComments will lookup the prs for code comments which got invalidated by change
-func (prs PullRequestList) InvalidateCodeComments(doer *User, repo *git.Repository, branch string) error {
+func (prs PullRequestList) InvalidateCodeComments(doer *user_model.User, repo *git.Repository, branch string) error {
return prs.invalidateCodeComments(db.GetEngine(db.DefaultContext), doer, repo, branch)
}
diff --git a/models/pull_sign.go b/models/pull_sign.go
index 028a3e5c3b..269e8e06d2 100644
--- a/models/pull_sign.go
+++ b/models/pull_sign.go
@@ -7,13 +7,14 @@ package models
import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/login"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
)
// SignMerge determines if we should sign a PR merge commit to the base repository
-func (pr *PullRequest) SignMerge(u *User, tmpBasePath, baseCommit, headCommit string) (bool, string, *git.Signature, error) {
+func (pr *PullRequest) SignMerge(u *user_model.User, tmpBasePath, baseCommit, headCommit string) (bool, string, *git.Signature, error) {
if err := pr.LoadBaseRepo(); err != nil {
log.Error("Unable to get Base Repo for pull request")
return false, "", nil, err
diff --git a/models/pull_test.go b/models/pull_test.go
index c967cca313..2281dbffda 100644
--- a/models/pull_test.go
+++ b/models/pull_test.go
@@ -10,6 +10,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"github.com/stretchr/testify/assert"
)
@@ -264,7 +265,7 @@ func TestPullRequest_GetDefaultMergeMessage_ExternalTracker(t *testing.T) {
},
}
baseRepo := &Repository{Name: "testRepo", ID: 1}
- baseRepo.Owner = &User{Name: "testOwner"}
+ baseRepo.Owner = &user_model.User{Name: "testOwner"}
baseRepo.Units = []*RepoUnit{&externalTracker}
pr := unittest.AssertExistsAndLoadBean(t, &PullRequest{ID: 2, BaseRepo: baseRepo}).(*PullRequest)
diff --git a/models/release.go b/models/release.go
index 69d2ceda5e..f60024c710 100644
--- a/models/release.go
+++ b/models/release.go
@@ -15,6 +15,7 @@ import (
"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/structs"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
@@ -24,12 +25,12 @@ import (
// Release represents a release of repository.
type Release struct {
- ID int64 `xorm:"pk autoincr"`
- RepoID int64 `xorm:"INDEX UNIQUE(n)"`
- Repo *Repository `xorm:"-"`
- PublisherID int64 `xorm:"INDEX"`
- Publisher *User `xorm:"-"`
- TagName string `xorm:"INDEX UNIQUE(n)"`
+ ID int64 `xorm:"pk autoincr"`
+ RepoID int64 `xorm:"INDEX UNIQUE(n)"`
+ Repo *Repository `xorm:"-"`
+ PublisherID int64 `xorm:"INDEX"`
+ Publisher *user_model.User `xorm:"-"`
+ TagName string `xorm:"INDEX UNIQUE(n)"`
OriginalAuthor string
OriginalAuthorID int64 `xorm:"index"`
LowerTagName string
@@ -60,10 +61,10 @@ func (r *Release) loadAttributes(e db.Engine) error {
}
}
if r.Publisher == nil {
- r.Publisher, err = getUserByID(e, r.PublisherID)
+ r.Publisher, err = user_model.GetUserByIDEngine(e, r.PublisherID)
if err != nil {
- if IsErrUserNotExist(err) {
- r.Publisher = NewGhostUser()
+ if user_model.IsErrUserNotExist(err) {
+ r.Publisher = user_model.NewGhostUser()
} else {
return err
}
diff --git a/models/repo.go b/models/repo.go
index 860c5c4813..bf5c160297 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -27,6 +27,7 @@ import (
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/log"
@@ -44,9 +45,6 @@ import (
var (
// ErrMirrorNotExist mirror does not exist error
ErrMirrorNotExist = errors.New("Mirror does not exist")
-
- // ErrNameEmpty name is empty error
- ErrNameEmpty = errors.New("Name is empty")
)
var (
@@ -195,7 +193,7 @@ type Repository struct {
ID int64 `xorm:"pk autoincr"`
OwnerID int64 `xorm:"UNIQUE(s) index"`
OwnerName string
- Owner *User `xorm:"-"`
+ Owner *user_model.User `xorm:"-"`
LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"`
Name string `xorm:"INDEX NOT NULL"`
Description string `xorm:"TEXT"`
@@ -308,11 +306,11 @@ func (repo *Repository) AfterLoad() {
repo.NumOpenProjects = repo.NumProjects - repo.NumClosedProjects
}
-// MustOwner always returns a valid *User object to avoid
+// MustOwner always returns a valid *user_model.User object to avoid
// conceptually impossible error handling.
// It creates a fake object that contains error details
// when error occurs.
-func (repo *Repository) MustOwner() *User {
+func (repo *Repository) MustOwner() *user_model.User {
return repo.mustOwner(db.GetEngine(db.DefaultContext))
}
@@ -364,11 +362,11 @@ func (repo *Repository) getUnits(e db.Engine) (err error) {
}
// CheckUnitUser check whether user could visit the unit of this repository
-func (repo *Repository) CheckUnitUser(user *User, unitType unit.Type) bool {
+func (repo *Repository) CheckUnitUser(user *user_model.User, unitType unit.Type) bool {
return repo.checkUnitUser(db.GetEngine(db.DefaultContext), user, unitType)
}
-func (repo *Repository) checkUnitUser(e db.Engine, user *User, unitType unit.Type) bool {
+func (repo *Repository) checkUnitUser(e db.Engine, user *user_model.User, unitType unit.Type) bool {
if user.IsAdmin {
return true
}
@@ -465,7 +463,7 @@ func (repo *Repository) getOwner(e db.Engine) (err error) {
return nil
}
- repo.Owner, err = getUserByID(e, repo.OwnerID)
+ repo.Owner, err = user_model.GetUserByIDEngine(e, repo.OwnerID)
return err
}
@@ -474,9 +472,9 @@ func (repo *Repository) GetOwner() error {
return repo.getOwner(db.GetEngine(db.DefaultContext))
}
-func (repo *Repository) mustOwner(e db.Engine) *User {
+func (repo *Repository) mustOwner(e db.Engine) *user_model.User {
if err := repo.getOwner(e); err != nil {
- return &User{
+ return &user_model.User{
Name: "error",
FullName: err.Error(),
}
@@ -537,7 +535,7 @@ func (repo *Repository) ComposeDocumentMetas() map[string]string {
return repo.DocumentRenderingMetas
}
-func (repo *Repository) getAssignees(e db.Engine) (_ []*User, err error) {
+func (repo *Repository) getAssignees(e db.Engine) (_ []*user_model.User, err error) {
if err = repo.getOwner(e); err != nil {
return nil, err
}
@@ -551,7 +549,7 @@ func (repo *Repository) getAssignees(e db.Engine) (_ []*User, err error) {
// Leave a seat for owner itself to append later, but if owner is an organization
// and just waste 1 unit is cheaper than re-allocate memory once.
- users := make([]*User, 0, len(accesses)+1)
+ users := make([]*user_model.User, 0, len(accesses)+1)
if len(accesses) > 0 {
userIDs := make([]int64, len(accesses))
for i := 0; i < len(accesses); i++ {
@@ -571,17 +569,17 @@ func (repo *Repository) getAssignees(e db.Engine) (_ []*User, err error) {
// GetAssignees returns all users that have write access and can be assigned to issues
// of the repository,
-func (repo *Repository) GetAssignees() (_ []*User, err error) {
+func (repo *Repository) GetAssignees() (_ []*user_model.User, err error) {
return repo.getAssignees(db.GetEngine(db.DefaultContext))
}
-func (repo *Repository) getReviewers(e db.Engine, doerID, posterID int64) ([]*User, error) {
+func (repo *Repository) getReviewers(e db.Engine, doerID, posterID int64) ([]*user_model.User, error) {
// Get the owner of the repository - this often already pre-cached and if so saves complexity for the following queries
if err := repo.getOwner(e); err != nil {
return nil, err
}
- var users []*User
+ var users []*user_model.User
if repo.IsPrivate || repo.Owner.Visibility == api.VisibleTypePrivate {
// This a private repository:
@@ -623,7 +621,7 @@ func (repo *Repository) getReviewers(e db.Engine, doerID, posterID int64) ([]*Us
// * for public repositories this returns all users that have read access or higher to the repository,
// all repo watchers and all organization members.
// TODO: may be we should have a busy choice for users to block review request to them.
-func (repo *Repository) GetReviewers(doerID, posterID int64) ([]*User, error) {
+func (repo *Repository) GetReviewers(doerID, posterID int64) ([]*user_model.User, error) {
return repo.getReviewers(db.GetEngine(db.DefaultContext), doerID, posterID)
}
@@ -761,7 +759,7 @@ func (repo *Repository) UpdateSize(ctx context.Context) error {
}
// CanUserForkRepo returns true if specified user can fork repository.
-func CanUserForkRepo(user *User, repo *Repository) (bool, error) {
+func CanUserForkRepo(user *user_model.User, repo *Repository) (bool, error) {
if user == nil {
return false, nil
}
@@ -781,7 +779,7 @@ func CanUserForkRepo(user *User, repo *Repository) (bool, error) {
}
// CanUserDelete returns true if user could delete the repository
-func (repo *Repository) CanUserDelete(user *User) (bool, error) {
+func (repo *Repository) CanUserDelete(user *user_model.User) (bool, error) {
if user.IsAdmin || user.ID == repo.OwnerID {
return true, nil
}
@@ -818,12 +816,12 @@ func (repo *Repository) CanEnableEditor() bool {
}
// GetReaders returns all users that have explicit read access or higher to the repository.
-func (repo *Repository) GetReaders() (_ []*User, err error) {
+func (repo *Repository) GetReaders() (_ []*user_model.User, err error) {
return repo.getUsersWithAccessMode(db.GetEngine(db.DefaultContext), AccessModeRead)
}
// GetWriters returns all users that have write access to the repository.
-func (repo *Repository) GetWriters() (_ []*User, err error) {
+func (repo *Repository) GetWriters() (_ []*user_model.User, err error) {
return repo.getUsersWithAccessMode(db.GetEngine(db.DefaultContext), AccessModeWrite)
}
@@ -836,7 +834,7 @@ func (repo *Repository) IsReader(userID int64) (bool, error) {
}
// getUsersWithAccessMode returns users that have at least given access mode to the repository.
-func (repo *Repository) getUsersWithAccessMode(e db.Engine, mode AccessMode) (_ []*User, err error) {
+func (repo *Repository) getUsersWithAccessMode(e db.Engine, mode AccessMode) (_ []*user_model.User, err error) {
if err = repo.getOwner(e); err != nil {
return nil, err
}
@@ -848,7 +846,7 @@ func (repo *Repository) getUsersWithAccessMode(e db.Engine, mode AccessMode) (_
// Leave a seat for owner itself to append later, but if owner is an organization
// and just waste 1 unit is cheaper than re-allocate memory once.
- users := make([]*User, 0, len(accesses)+1)
+ users := make([]*user_model.User, 0, len(accesses)+1)
if len(accesses) > 0 {
userIDs := make([]int64, len(accesses))
for i := 0; i < len(accesses); i++ {
@@ -884,7 +882,7 @@ func (repo *Repository) ReadBy(userID int64) error {
return setRepoNotificationStatusReadIfUnread(db.GetEngine(db.DefaultContext), userID, repo.ID)
}
-func isRepositoryExist(e db.Engine, u *User, repoName string) (bool, error) {
+func isRepositoryExist(e db.Engine, u *user_model.User, repoName string) (bool, error) {
has, err := e.Get(&Repository{
OwnerID: u.ID,
LowerName: strings.ToLower(repoName),
@@ -897,7 +895,7 @@ func isRepositoryExist(e db.Engine, u *User, repoName string) (bool, error) {
}
// IsRepositoryExist returns true if the repository with given name under user has already existed.
-func IsRepositoryExist(u *User, repoName string) (bool, error) {
+func IsRepositoryExist(u *user_model.User, repoName string) (bool, error) {
return isRepositoryExist(db.GetEngine(db.DefaultContext), u, repoName)
}
@@ -951,7 +949,7 @@ func (repo *Repository) CloneLink() (cl *CloneLink) {
}
// CheckCreateRepository check if could created a repository
-func CheckCreateRepository(doer, u *User, name string, overwriteOrAdopt bool) error {
+func CheckCreateRepository(doer, u *user_model.User, name string, overwriteOrAdopt bool) error {
if !doer.CanCreateRepo() {
return ErrReachLimitOfRepo{u.MaxRepoCreation}
}
@@ -1041,15 +1039,15 @@ var (
// IsUsableRepoName returns true when repository is usable
func IsUsableRepoName(name string) error {
- if alphaDashDotPattern.MatchString(name) {
+ if db.AlphaDashDotPattern.MatchString(name) {
// Note: usually this error is normally caught up earlier in the UI
- return ErrNameCharsNotAllowed{Name: name}
+ return db.ErrNameCharsNotAllowed{Name: name}
}
- return isUsableName(reservedRepoNames, reservedRepoPatterns, name)
+ return db.IsUsableName(reservedRepoNames, reservedRepoPatterns, name)
}
// CreateRepository creates a repository for the user/organization.
-func CreateRepository(ctx context.Context, doer, u *User, repo *Repository, overwriteOrAdopt bool) (err error) {
+func CreateRepository(ctx context.Context, doer, u *user_model.User, repo *Repository, overwriteOrAdopt bool) (err error) {
if err = IsUsableRepoName(repo.Name); err != nil {
return err
}
@@ -1115,11 +1113,11 @@ func CreateRepository(ctx context.Context, doer, u *User, repo *Repository, over
// Remember visibility preference.
u.LastRepoVisibility = repo.IsPrivate
- if err = updateUserCols(db.GetEngine(ctx), u, "last_repo_visibility"); err != nil {
+ if err = user_model.UpdateUserColsEngine(db.GetEngine(ctx), u, "last_repo_visibility"); err != nil {
return fmt.Errorf("updateUser: %v", err)
}
- if _, err = db.GetEngine(ctx).Incr("num_repos").ID(u.ID).Update(new(User)); err != nil {
+ if _, err = db.GetEngine(ctx).Incr("num_repos").ID(u.ID).Update(new(user_model.User)); err != nil {
return fmt.Errorf("increment user total_repos: %v", err)
}
u.NumRepos++
@@ -1232,7 +1230,7 @@ func CountUserRepositories(userID int64, private bool) int64 {
// RepoPath returns repository path by given user and repository name.
func RepoPath(userName, repoName string) string {
- return filepath.Join(UserPath(userName), strings.ToLower(repoName)+".git")
+ return filepath.Join(user_model.UserPath(userName), strings.ToLower(repoName)+".git")
}
// IncrementRepoForkNum increment repository fork number
@@ -1248,7 +1246,7 @@ func DecrementRepoForkNum(ctx context.Context, repoID int64) error {
}
// ChangeRepositoryName changes all corresponding setting from old repository name to new one.
-func ChangeRepositoryName(doer *User, repo *Repository, newRepoName string) (err error) {
+func ChangeRepositoryName(doer *user_model.User, repo *Repository, newRepoName string) (err error) {
oldRepoName := repo.Name
newRepoName = strings.ToLower(newRepoName)
if err = IsUsableRepoName(newRepoName); err != nil {
@@ -1441,7 +1439,7 @@ func UpdateRepositoryUnits(repo *Repository, units []RepoUnit, deleteUnitTypes [
// DeleteRepository deletes a repository for a user or organization.
// make sure if you call this func to close open sessions (sqlite will otherwise get a deadlock)
-func DeleteRepository(doer *User, uid, repoID int64) error {
+func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
ctx, committer, err := db.TxContext()
if err != nil {
return err
@@ -1450,7 +1448,7 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
sess := db.GetEngine(ctx)
// In case is a organization.
- org, err := getUserByID(sess, uid)
+ org, err := user_model.GetUserByIDEngine(sess, uid)
if err != nil {
return err
}
@@ -1802,11 +1800,11 @@ func getRepositoryCount(e db.Engine, ownerID int64) (int64, error) {
return e.Count(&Repository{OwnerID: ownerID})
}
-func getPublicRepositoryCount(e db.Engine, u *User) (int64, error) {
+func getPublicRepositoryCount(e db.Engine, u *user_model.User) (int64, error) {
return e.Where("is_private = ?", false).Count(&Repository{OwnerID: u.ID})
}
-func getPrivateRepositoryCount(e db.Engine, u *User) (int64, error) {
+func getPrivateRepositoryCount(e db.Engine, u *user_model.User) (int64, error) {
return e.Where("is_private = ?", true).Count(&Repository{OwnerID: u.ID})
}
@@ -1816,12 +1814,12 @@ func GetRepositoryCount(ctx context.Context, ownerID int64) (int64, error) {
}
// GetPublicRepositoryCount returns the total number of public repositories of user.
-func GetPublicRepositoryCount(u *User) (int64, error) {
+func GetPublicRepositoryCount(u *user_model.User) (int64, error) {
return getPublicRepositoryCount(db.GetEngine(db.DefaultContext), u)
}
// GetPrivateRepositoryCount returns the total number of private repositories of user.
-func GetPrivateRepositoryCount(u *User) (int64, error) {
+func GetPrivateRepositoryCount(u *user_model.User) (int64, error) {
return getPrivateRepositoryCount(db.GetEngine(db.DefaultContext), u)
}
@@ -2155,7 +2153,7 @@ func (repo *Repository) GetTrustModel() TrustModelType {
return trustModel
}
-func updateUserStarNumbers(users []User) error {
+func updateUserStarNumbers(users []user_model.User) error {
ctx, committer, err := db.TxContext()
if err != nil {
return err
@@ -2176,7 +2174,7 @@ func DoctorUserStarNum() (err error) {
const batchSize = 100
for start := 0; ; start += batchSize {
- users := make([]User, 0, batchSize)
+ users := make([]user_model.User, 0, batchSize)
if err = db.GetEngine(db.DefaultContext).Limit(batchSize, start).Where("type = ?", 0).Cols("id").Find(&users); err != nil {
return
}
diff --git a/models/repo_activity.go b/models/repo_activity.go
index 5986da7e77..d3d4c7bbd7 100644
--- a/models/repo_activity.go
+++ b/models/repo_activity.go
@@ -10,6 +10,7 @@ import (
"time"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"xorm.io/xorm"
@@ -94,13 +95,13 @@ func GetActivityStatsTopAuthors(repo *Repository, timeFrom time.Time, count int)
}
users := make(map[int64]*ActivityAuthorData)
var unknownUserID int64
- unknownUserAvatarLink := NewGhostUser().AvatarLink()
+ unknownUserAvatarLink := user_model.NewGhostUser().AvatarLink()
for _, v := range code.Authors {
if len(v.Email) == 0 {
continue
}
- u, err := GetUserByEmail(v.Email)
- if u == nil || IsErrUserNotExist(err) {
+ u, err := user_model.GetUserByEmail(v.Email)
+ if u == nil || user_model.IsErrUserNotExist(err) {
unknownUserID--
users[unknownUserID] = &ActivityAuthorData{
Name: v.Name,
diff --git a/models/repo_collaboration.go b/models/repo_collaboration.go
index 6502d7959c..11d1a0e1d0 100644
--- a/models/repo_collaboration.go
+++ b/models/repo_collaboration.go
@@ -10,6 +10,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unit"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
@@ -30,7 +31,7 @@ func init() {
db.RegisterModel(new(Collaboration))
}
-func (repo *Repository) addCollaborator(e db.Engine, u *User) error {
+func (repo *Repository) addCollaborator(e db.Engine, u *user_model.User) error {
collaboration := &Collaboration{
RepoID: repo.ID,
UserID: u.ID,
@@ -52,7 +53,7 @@ func (repo *Repository) addCollaborator(e db.Engine, u *User) error {
}
// AddCollaborator adds new collaboration to a repository with default access mode.
-func (repo *Repository) AddCollaborator(u *User) error {
+func (repo *Repository) AddCollaborator(u *user_model.User) error {
ctx, committer, err := db.TxContext()
if err != nil {
return err
@@ -80,7 +81,7 @@ func (repo *Repository) getCollaborations(e db.Engine, listOptions db.ListOption
// Collaborator represents a user with collaboration details.
type Collaborator struct {
- *User
+ *user_model.User
Collaboration *Collaboration
}
@@ -92,11 +93,11 @@ func (repo *Repository) getCollaborators(e db.Engine, listOptions db.ListOptions
collaborators := make([]*Collaborator, 0, len(collaborations))
for _, c := range collaborations {
- user, err := getUserByID(e, c.UserID)
+ user, err := user_model.GetUserByIDEngine(e, c.UserID)
if err != nil {
- if IsErrUserNotExist(err) {
+ if user_model.IsErrUserNotExist(err) {
log.Warn("Inconsistent DB: User: %d is listed as collaborator of %-v but does not exist", c.UserID, repo)
- user = NewGhostUser()
+ user = user_model.NewGhostUser()
} else {
return nil, err
}
@@ -227,7 +228,7 @@ func (repo *Repository) DeleteCollaboration(uid int64) (err error) {
}
func (repo *Repository) reconsiderIssueAssignees(e db.Engine, uid int64) error {
- user, err := getUserByID(e, uid)
+ user, err := user_model.GetUserByIDEngine(e, uid)
if err != nil {
return err
}
diff --git a/models/repo_collaboration_test.go b/models/repo_collaboration_test.go
index 060afc2139..94dd238cb6 100644
--- a/models/repo_collaboration_test.go
+++ b/models/repo_collaboration_test.go
@@ -9,6 +9,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"github.com/stretchr/testify/assert"
)
@@ -19,9 +20,9 @@ func TestRepository_AddCollaborator(t *testing.T) {
testSuccess := func(repoID, userID int64) {
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository)
assert.NoError(t, repo.GetOwner())
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: userID}).(*User)
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID}).(*user_model.User)
assert.NoError(t, repo.AddCollaborator(user))
- unittest.CheckConsistencyFor(t, &Repository{ID: repoID}, &User{ID: userID})
+ unittest.CheckConsistencyFor(t, &Repository{ID: repoID}, &user_model.User{ID: userID})
}
testSuccess(1, 4)
testSuccess(1, 4)
diff --git a/models/repo_list.go b/models/repo_list.go
index 511b446711..ff86f61577 100644
--- a/models/repo_list.go
+++ b/models/repo_list.go
@@ -9,6 +9,7 @@ import (
"strings"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
@@ -55,7 +56,7 @@ func (repos RepositoryList) loadAttributes(e db.Engine) error {
}
// Load owners.
- users := make(map[int64]*User, len(set))
+ users := make(map[int64]*user_model.User, len(set))
if err := e.
Where("id > 0").
In("id", keysInt64(set)).
@@ -135,12 +136,12 @@ func (repos MirrorRepositoryList) LoadAttributes() error {
// SearchRepoOptions holds the search options
type SearchRepoOptions struct {
db.ListOptions
- Actor *User
+ Actor *user_model.User
Keyword string
OwnerID int64
PriorityOwnerID int64
TeamID int64
- OrderBy SearchOrderBy
+ OrderBy db.SearchOrderBy
Private bool // Include private repositories in results
StarredByID int64
WatchedByID int64
@@ -182,31 +183,6 @@ type SearchRepoOptions struct {
LowerNames []string
}
-// SearchOrderBy is used to sort the result
-type SearchOrderBy string
-
-func (s SearchOrderBy) String() string {
- return string(s)
-}
-
-// Strings for sorting result
-const (
- SearchOrderByAlphabetically SearchOrderBy = "name ASC"
- SearchOrderByAlphabeticallyReverse SearchOrderBy = "name DESC"
- SearchOrderByLeastUpdated SearchOrderBy = "updated_unix ASC"
- SearchOrderByRecentUpdated SearchOrderBy = "updated_unix DESC"
- SearchOrderByOldest SearchOrderBy = "created_unix ASC"
- SearchOrderByNewest SearchOrderBy = "created_unix DESC"
- SearchOrderBySize SearchOrderBy = "size ASC"
- SearchOrderBySizeReverse SearchOrderBy = "size DESC"
- SearchOrderByID SearchOrderBy = "id ASC"
- SearchOrderByIDReverse SearchOrderBy = "id DESC"
- SearchOrderByStars SearchOrderBy = "num_stars ASC"
- SearchOrderByStarsReverse SearchOrderBy = "num_stars DESC"
- SearchOrderByForks SearchOrderBy = "num_forks ASC"
- SearchOrderByForksReverse SearchOrderBy = "num_forks DESC"
-)
-
// SearchRepositoryCondition creates a query condition according search repository options
func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
cond := builder.NewCond()
@@ -278,7 +254,7 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
Join("INNER", "`user`", "`user`.id = `org_user`.org_id").
Where(builder.Eq{
"`org_user`.uid": opts.OwnerID,
- "`user`.type": UserTypeOrganization,
+ "`user`.type": user_model.UserTypeOrganization,
"`user`.visibility": structs.VisibleTypePrivate,
})))),
)
@@ -401,11 +377,11 @@ func searchRepositoryByCondition(opts *SearchRepoOptions, cond builder.Cond) (db
}
if len(opts.OrderBy) == 0 {
- opts.OrderBy = SearchOrderByAlphabetically
+ opts.OrderBy = db.SearchOrderByAlphabetically
}
if opts.PriorityOwnerID > 0 {
- opts.OrderBy = SearchOrderBy(fmt.Sprintf("CASE WHEN owner_id = %d THEN 0 ELSE owner_id END, %s", opts.PriorityOwnerID, opts.OrderBy))
+ opts.OrderBy = db.SearchOrderBy(fmt.Sprintf("CASE WHEN owner_id = %d THEN 0 ELSE owner_id END, %s", opts.PriorityOwnerID, opts.OrderBy))
}
sess := db.GetEngine(db.DefaultContext)
@@ -429,7 +405,7 @@ func searchRepositoryByCondition(opts *SearchRepoOptions, cond builder.Cond) (db
}
// accessibleRepositoryCondition takes a user a returns a condition for checking if a repository is accessible
-func accessibleRepositoryCondition(user *User) builder.Cond {
+func accessibleRepositoryCondition(user *user_model.User) builder.Cond {
cond := builder.NewCond()
if user == nil || !user.IsRestricted || user.ID <= 0 {
@@ -443,7 +419,7 @@ func accessibleRepositoryCondition(user *User) builder.Cond {
// 2. Aren't in an private organisation or limited organisation if we're not logged in
builder.NotIn("`repository`.owner_id", builder.Select("id").From("`user`").Where(
builder.And(
- builder.Eq{"type": UserTypeOrganization},
+ builder.Eq{"type": user_model.UserTypeOrganization},
builder.In("visibility", orgVisibilityLimit)),
))))
}
@@ -508,13 +484,13 @@ func SearchRepositoryIDs(opts *SearchRepoOptions) ([]int64, int64, error) {
}
// AccessibleRepoIDsQuery queries accessible repository ids. Usable as a subquery wherever repo ids need to be filtered.
-func AccessibleRepoIDsQuery(user *User) *builder.Builder {
+func AccessibleRepoIDsQuery(user *user_model.User) *builder.Builder {
// NB: Please note this code needs to still work if user is nil
return builder.Select("id").From("repository").Where(accessibleRepositoryCondition(user))
}
// FindUserAccessibleRepoIDs find all accessible repositories' ID by user's id
-func FindUserAccessibleRepoIDs(user *User) ([]int64, error) {
+func FindUserAccessibleRepoIDs(user *user_model.User) ([]int64, error) {
repoIDs := make([]int64, 0, 10)
if err := db.GetEngine(db.DefaultContext).
Table("repository").
diff --git a/models/repo_permission.go b/models/repo_permission.go
index a6304cf1aa..96abb9037a 100644
--- a/models/repo_permission.go
+++ b/models/repo_permission.go
@@ -9,6 +9,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unit"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
)
@@ -140,11 +141,11 @@ func (p *Permission) ColorFormat(s fmt.State) {
}
// GetUserRepoPermission returns the user permissions to the repository
-func GetUserRepoPermission(repo *Repository, user *User) (Permission, error) {
+func GetUserRepoPermission(repo *Repository, user *user_model.User) (Permission, error) {
return getUserRepoPermission(db.GetEngine(db.DefaultContext), repo, user)
}
-func getUserRepoPermission(e db.Engine, repo *Repository, user *User) (perm Permission, err error) {
+func getUserRepoPermission(e db.Engine, repo *Repository, user *user_model.User) (perm Permission, err error) {
if log.IsTrace() {
defer func() {
if user == nil {
@@ -274,7 +275,7 @@ func getUserRepoPermission(e db.Engine, repo *Repository, user *User) (perm Perm
}
// IsUserRealRepoAdmin check if this user is real repo admin
-func IsUserRealRepoAdmin(repo *Repository, user *User) (bool, error) {
+func IsUserRealRepoAdmin(repo *Repository, user *user_model.User) (bool, error) {
if repo.OwnerID == user.ID {
return true, nil
}
@@ -294,11 +295,11 @@ func IsUserRealRepoAdmin(repo *Repository, user *User) (bool, error) {
}
// IsUserRepoAdmin return true if user has admin right of a repo
-func IsUserRepoAdmin(repo *Repository, user *User) (bool, error) {
+func IsUserRepoAdmin(repo *Repository, user *user_model.User) (bool, error) {
return isUserRepoAdmin(db.GetEngine(db.DefaultContext), repo, user)
}
-func isUserRepoAdmin(e db.Engine, repo *Repository, user *User) (bool, error) {
+func isUserRepoAdmin(e db.Engine, repo *Repository, user *user_model.User) (bool, error) {
if user == nil || repo == nil {
return false, nil
}
@@ -329,17 +330,17 @@ func isUserRepoAdmin(e db.Engine, repo *Repository, user *User) (bool, error) {
// AccessLevel returns the Access a user has to a repository. Will return NoneAccess if the
// user does not have access.
-func AccessLevel(user *User, repo *Repository) (AccessMode, error) {
+func AccessLevel(user *user_model.User, repo *Repository) (AccessMode, error) {
return accessLevelUnit(db.GetEngine(db.DefaultContext), user, repo, unit.TypeCode)
}
// AccessLevelUnit returns the Access a user has to a repository's. Will return NoneAccess if the
// user does not have access.
-func AccessLevelUnit(user *User, repo *Repository, unitType unit.Type) (AccessMode, error) {
+func AccessLevelUnit(user *user_model.User, repo *Repository, unitType unit.Type) (AccessMode, error) {
return accessLevelUnit(db.GetEngine(db.DefaultContext), user, repo, unitType)
}
-func accessLevelUnit(e db.Engine, user *User, repo *Repository, unitType unit.Type) (AccessMode, error) {
+func accessLevelUnit(e db.Engine, user *user_model.User, repo *Repository, unitType unit.Type) (AccessMode, error) {
perm, err := getUserRepoPermission(e, repo, user)
if err != nil {
return AccessModeNone, err
@@ -347,24 +348,24 @@ func accessLevelUnit(e db.Engine, user *User, repo *Repository, unitType unit.Ty
return perm.UnitAccessMode(unitType), nil
}
-func hasAccessUnit(e db.Engine, user *User, repo *Repository, unitType unit.Type, testMode AccessMode) (bool, error) {
+func hasAccessUnit(e db.Engine, user *user_model.User, repo *Repository, unitType unit.Type, testMode AccessMode) (bool, error) {
mode, err := accessLevelUnit(e, user, repo, unitType)
return testMode <= mode, err
}
// HasAccessUnit returns true if user has testMode to the unit of the repository
-func HasAccessUnit(user *User, repo *Repository, unitType unit.Type, testMode AccessMode) (bool, error) {
+func HasAccessUnit(user *user_model.User, repo *Repository, unitType unit.Type, testMode AccessMode) (bool, error) {
return hasAccessUnit(db.GetEngine(db.DefaultContext), user, repo, unitType, testMode)
}
// CanBeAssigned return true if user can be assigned to issue or pull requests in repo
// Currently any write access (code, issues or pr's) is assignable, to match assignee list in user interface.
// FIXME: user could send PullRequest also could be assigned???
-func CanBeAssigned(user *User, repo *Repository, isPull bool) (bool, error) {
+func CanBeAssigned(user *user_model.User, repo *Repository, isPull bool) (bool, error) {
return canBeAssigned(db.GetEngine(db.DefaultContext), user, repo, isPull)
}
-func canBeAssigned(e db.Engine, user *User, repo *Repository, _ bool) (bool, error) {
+func canBeAssigned(e db.Engine, user *user_model.User, repo *Repository, _ bool) (bool, error) {
if user.IsOrganization() {
return false, fmt.Errorf("Organization can't be added as assignee [user_id: %d, repo_id: %d]", user.ID, repo.ID)
}
@@ -376,10 +377,10 @@ func canBeAssigned(e db.Engine, user *User, repo *Repository, _ bool) (bool, err
}
func hasAccess(e db.Engine, userID int64, repo *Repository) (bool, error) {
- var user *User
+ var user *user_model.User
var err error
if userID > 0 {
- user, err = getUserByID(e, userID)
+ user, err = user_model.GetUserByIDEngine(e, userID)
if err != nil {
return false, err
}
@@ -397,7 +398,7 @@ func HasAccess(userID int64, repo *Repository) (bool, error) {
}
// FilterOutRepoIdsWithoutUnitAccess filter out repos where user has no access to repositories
-func FilterOutRepoIdsWithoutUnitAccess(u *User, repoIDs []int64, units ...unit.Type) ([]int64, error) {
+func FilterOutRepoIdsWithoutUnitAccess(u *user_model.User, repoIDs []int64, units ...unit.Type) ([]int64, error) {
i := 0
for _, rID := range repoIDs {
repo, err := GetRepositoryByID(rID)
diff --git a/models/repo_permission_test.go b/models/repo_permission_test.go
index 180a85a2f5..ce046eba7a 100644
--- a/models/repo_permission_test.go
+++ b/models/repo_permission_test.go
@@ -10,6 +10,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"github.com/stretchr/testify/assert"
)
@@ -22,7 +23,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) {
assert.NoError(t, repo.getUnits(db.GetEngine(db.DefaultContext)))
// plain user
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
perm, err := GetUserRepoPermission(repo, user)
assert.NoError(t, err)
for _, unit := range repo.Units {
@@ -40,7 +41,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) {
}
// collaborator
- collaborator := unittest.AssertExistsAndLoadBean(t, &User{ID: 4}).(*User)
+ collaborator := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User)
perm, err = GetUserRepoPermission(repo, collaborator)
assert.NoError(t, err)
for _, unit := range repo.Units {
@@ -49,7 +50,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) {
}
// owner
- owner := unittest.AssertExistsAndLoadBean(t, &User{ID: 5}).(*User)
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User)
perm, err = GetUserRepoPermission(repo, owner)
assert.NoError(t, err)
for _, unit := range repo.Units {
@@ -58,7 +59,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) {
}
// admin
- admin := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
+ admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
perm, err = GetUserRepoPermission(repo, admin)
assert.NoError(t, err)
for _, unit := range repo.Units {
@@ -75,7 +76,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) {
assert.NoError(t, repo.getUnits(db.GetEngine(db.DefaultContext)))
// plain user
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: 4}).(*User)
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User)
perm, err := GetUserRepoPermission(repo, user)
assert.NoError(t, err)
for _, unit := range repo.Units {
@@ -101,7 +102,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) {
}
// owner
- owner := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
perm, err = GetUserRepoPermission(repo, owner)
assert.NoError(t, err)
for _, unit := range repo.Units {
@@ -110,7 +111,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) {
}
// admin
- admin := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
+ admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
perm, err = GetUserRepoPermission(repo, admin)
assert.NoError(t, err)
for _, unit := range repo.Units {
@@ -127,7 +128,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) {
assert.NoError(t, repo.getUnits(db.GetEngine(db.DefaultContext)))
// plain user
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: 5}).(*User)
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User)
perm, err := GetUserRepoPermission(repo, user)
assert.NoError(t, err)
for _, unit := range repo.Units {
@@ -153,7 +154,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) {
}
// org member team owner
- owner := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
perm, err = GetUserRepoPermission(repo, owner)
assert.NoError(t, err)
for _, unit := range repo.Units {
@@ -162,7 +163,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) {
}
// org member team tester
- member := unittest.AssertExistsAndLoadBean(t, &User{ID: 15}).(*User)
+ member := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}).(*user_model.User)
perm, err = GetUserRepoPermission(repo, member)
assert.NoError(t, err)
for _, unit := range repo.Units {
@@ -172,7 +173,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) {
assert.False(t, perm.CanWrite(unit.TypeCode))
// admin
- admin := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
+ admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
perm, err = GetUserRepoPermission(repo, admin)
assert.NoError(t, err)
for _, unit := range repo.Units {
@@ -189,7 +190,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) {
assert.NoError(t, repo.getUnits(db.GetEngine(db.DefaultContext)))
// plain user
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: 5}).(*User)
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User)
perm, err := GetUserRepoPermission(repo, user)
assert.NoError(t, err)
for _, unit := range repo.Units {
@@ -215,7 +216,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) {
}
// org member team owner
- owner := unittest.AssertExistsAndLoadBean(t, &User{ID: 15}).(*User)
+ owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}).(*user_model.User)
perm, err = GetUserRepoPermission(repo, owner)
assert.NoError(t, err)
for _, unit := range repo.Units {
@@ -235,7 +236,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) {
}
// org member team tester
- tester := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ tester := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
perm, err = GetUserRepoPermission(repo, tester)
assert.NoError(t, err)
assert.True(t, perm.CanWrite(unit.TypeIssues))
@@ -243,7 +244,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) {
assert.False(t, perm.CanRead(unit.TypeCode))
// org member team reviewer
- reviewer := unittest.AssertExistsAndLoadBean(t, &User{ID: 20}).(*User)
+ reviewer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 20}).(*user_model.User)
perm, err = GetUserRepoPermission(repo, reviewer)
assert.NoError(t, err)
assert.False(t, perm.CanRead(unit.TypeIssues))
@@ -251,7 +252,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) {
assert.True(t, perm.CanRead(unit.TypeCode))
// admin
- admin := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
+ admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
perm, err = GetUserRepoPermission(repo, admin)
assert.NoError(t, err)
for _, unit := range repo.Units {
diff --git a/models/repo_sign.go b/models/repo_sign.go
index f7a303b0c1..f30ba4748c 100644
--- a/models/repo_sign.go
+++ b/models/repo_sign.go
@@ -9,6 +9,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/login"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
@@ -107,7 +108,7 @@ func PublicSigningKey(repoPath string) (string, error) {
}
// SignInitialCommit determines if we should sign the initial commit to this repository
-func SignInitialCommit(repoPath string, u *User) (bool, string, *git.Signature, error) {
+func SignInitialCommit(repoPath string, u *user_model.User) (bool, string, *git.Signature, error) {
rules := signingModeFromStrings(setting.Repository.Signing.InitialCommit)
signingKey, sig := SigningKey(repoPath)
if signingKey == "" {
@@ -143,7 +144,7 @@ Loop:
}
// SignWikiCommit determines if we should sign the commits to this repository wiki
-func (repo *Repository) SignWikiCommit(u *User) (bool, string, *git.Signature, error) {
+func (repo *Repository) SignWikiCommit(u *user_model.User) (bool, string, *git.Signature, error) {
rules := signingModeFromStrings(setting.Repository.Signing.Wiki)
signingKey, sig := SigningKey(repo.WikiPath())
if signingKey == "" {
@@ -196,7 +197,7 @@ Loop:
}
// SignCRUDAction determines if we should sign a CRUD commit to this repository
-func (repo *Repository) SignCRUDAction(u *User, tmpBasePath, parentCommit string) (bool, string, *git.Signature, error) {
+func (repo *Repository) SignCRUDAction(u *user_model.User, tmpBasePath, parentCommit string) (bool, string, *git.Signature, error) {
rules := signingModeFromStrings(setting.Repository.Signing.CRUDActions)
signingKey, sig := SigningKey(repo.RepoPath())
if signingKey == "" {
diff --git a/models/repo_test.go b/models/repo_test.go
index 5cc396eb76..e6aaedaae6 100644
--- a/models/repo_test.go
+++ b/models/repo_test.go
@@ -16,6 +16,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/markup"
"github.com/stretchr/testify/assert"
@@ -25,7 +26,7 @@ func TestMetas(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
repo := &Repository{Name: "testRepo"}
- repo.Owner = &User{Name: "testOwner"}
+ repo.Owner = &user_model.User{Name: "testOwner"}
repo.OwnerName = repo.Owner.Name
repo.Units = nil
@@ -73,8 +74,8 @@ func TestGetRepositoryCount(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
count, err1 := GetRepositoryCount(db.DefaultContext, 10)
- privateCount, err2 := GetPrivateRepositoryCount(&User{ID: int64(10)})
- publicCount, err3 := GetPublicRepositoryCount(&User{ID: int64(10)})
+ privateCount, err2 := GetPrivateRepositoryCount(&user_model.User{ID: int64(10)})
+ publicCount, err3 := GetPublicRepositoryCount(&user_model.User{ID: int64(10)})
assert.NoError(t, err1)
assert.NoError(t, err2)
assert.NoError(t, err3)
@@ -85,7 +86,7 @@ func TestGetRepositoryCount(t *testing.T) {
func TestGetPublicRepositoryCount(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- count, err := GetPublicRepositoryCount(&User{ID: int64(10)})
+ count, err := GetPublicRepositoryCount(&user_model.User{ID: int64(10)})
assert.NoError(t, err)
assert.Equal(t, int64(1), count)
}
@@ -93,7 +94,7 @@ func TestGetPublicRepositoryCount(t *testing.T) {
func TestGetPrivateRepositoryCount(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- count, err := GetPrivateRepositoryCount(&User{ID: int64(10)})
+ count, err := GetPrivateRepositoryCount(&user_model.User{ID: int64(10)})
assert.NoError(t, err)
assert.Equal(t, int64(2), count)
}
diff --git a/models/repo_transfer.go b/models/repo_transfer.go
index 3b5ac21b09..9918a10d76 100644
--- a/models/repo_transfer.go
+++ b/models/repo_transfer.go
@@ -9,6 +9,7 @@ import (
"os"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
@@ -18,9 +19,9 @@ import (
type RepoTransfer struct {
ID int64 `xorm:"pk autoincr"`
DoerID int64
- Doer *User `xorm:"-"`
+ Doer *user_model.User `xorm:"-"`
RecipientID int64
- Recipient *User `xorm:"-"`
+ Recipient *user_model.User `xorm:"-"`
RepoID int64
TeamIDs []int64
Teams []*Team `xorm:"-"`
@@ -36,7 +37,7 @@ func init() {
// LoadAttributes fetches the transfer recipient from the database
func (r *RepoTransfer) LoadAttributes() error {
if r.Recipient == nil {
- u, err := GetUserByID(r.RecipientID)
+ u, err := user_model.GetUserByID(r.RecipientID)
if err != nil {
return err
}
@@ -60,7 +61,7 @@ func (r *RepoTransfer) LoadAttributes() error {
}
if r.Doer == nil {
- u, err := GetUserByID(r.DoerID)
+ u, err := user_model.GetUserByID(r.DoerID)
if err != nil {
return err
}
@@ -74,7 +75,7 @@ func (r *RepoTransfer) LoadAttributes() error {
// CanUserAcceptTransfer checks if the user has the rights to accept/decline a repo transfer.
// For user, it checks if it's himself
// For organizations, it checks if the user is able to create repos
-func (r *RepoTransfer) CanUserAcceptTransfer(u *User) bool {
+func (r *RepoTransfer) CanUserAcceptTransfer(u *user_model.User) bool {
if err := r.LoadAttributes(); err != nil {
log.Error("LoadAttributes: %v", err)
return false
@@ -150,7 +151,7 @@ func TestRepositoryReadyForTransfer(status RepositoryStatus) error {
// CreatePendingRepositoryTransfer transfer a repo from one owner to a new one.
// it marks the repository transfer as "pending"
-func CreatePendingRepositoryTransfer(doer, newOwner *User, repoID int64, teams []*Team) error {
+func CreatePendingRepositoryTransfer(doer, newOwner *user_model.User, repoID int64, teams []*Team) error {
ctx, committer, err := db.TxContext()
if err != nil {
return err
@@ -201,7 +202,7 @@ func CreatePendingRepositoryTransfer(doer, newOwner *User, repoID int64, teams [
}
// TransferOwnership transfers all corresponding repository items from old user to new one.
-func TransferOwnership(doer *User, newOwnerName string, repo *Repository) (err error) {
+func TransferOwnership(doer *user_model.User, newOwnerName string, repo *Repository) (err error) {
repoRenamed := false
wikiRenamed := false
oldOwnerName := doer.Name
@@ -242,7 +243,7 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) (err e
sess := db.GetEngine(ctx)
- newOwner, err := getUserByName(sess, newOwnerName)
+ newOwner, err := user_model.GetUserByNameCtx(ctx, newOwnerName)
if err != nil {
return fmt.Errorf("get new owner '%s': %v", newOwnerName, err)
}
@@ -371,7 +372,7 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) (err e
}
// Rename remote repository to new path and delete local copy.
- dir := UserPath(newOwner.Name)
+ dir := user_model.UserPath(newOwner.Name)
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
return fmt.Errorf("Failed to create dir %s: %v", dir, err)
diff --git a/models/repo_transfer_test.go b/models/repo_transfer_test.go
index 368fea598d..1bde5628c1 100644
--- a/models/repo_transfer_test.go
+++ b/models/repo_transfer_test.go
@@ -8,6 +8,7 @@ import (
"testing"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"github.com/stretchr/testify/assert"
)
@@ -15,7 +16,7 @@ import (
func TestRepositoryTransfer(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- doer := unittest.AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+ doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository)
transfer, err := GetPendingRepositoryTransfer(repo)
@@ -30,7 +31,7 @@ func TestRepositoryTransfer(t *testing.T) {
assert.Nil(t, transfer)
assert.True(t, IsErrNoPendingTransfer(err))
- user2 := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
assert.NoError(t, CreatePendingRepositoryTransfer(doer, user2, repo.ID, nil))
@@ -39,7 +40,7 @@ func TestRepositoryTransfer(t *testing.T) {
assert.NoError(t, transfer.LoadAttributes())
assert.Equal(t, "user2", transfer.Recipient.Name)
- user6 := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ user6 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
// Only transfer can be started at any given time
err = CreatePendingRepositoryTransfer(doer, user6, repo.ID, nil)
@@ -47,7 +48,7 @@ func TestRepositoryTransfer(t *testing.T) {
assert.True(t, IsErrRepoTransferInProgress(err))
// Unknown user
- err = CreatePendingRepositoryTransfer(doer, &User{ID: 1000, LowerName: "user1000"}, repo.ID, nil)
+ err = CreatePendingRepositoryTransfer(doer, &user_model.User{ID: 1000, LowerName: "user1000"}, repo.ID, nil)
assert.Error(t, err)
// Cancel transfer
diff --git a/models/repo_watch.go b/models/repo_watch.go
index fb1b1086aa..e225c945e9 100644
--- a/models/repo_watch.go
+++ b/models/repo_watch.go
@@ -9,6 +9,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unit"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
)
@@ -166,18 +167,18 @@ func getRepoWatchersIDs(e db.Engine, repoID int64) ([]int64, error) {
}
// GetWatchers returns range of users watching given repository.
-func (repo *Repository) GetWatchers(opts db.ListOptions) ([]*User, error) {
+func (repo *Repository) GetWatchers(opts db.ListOptions) ([]*user_model.User, error) {
sess := db.GetEngine(db.DefaultContext).Where("watch.repo_id=?", repo.ID).
Join("LEFT", "watch", "`user`.id=`watch`.user_id").
And("`watch`.mode<>?", RepoWatchModeDont)
if opts.Page > 0 {
sess = db.SetSessionPagination(sess, &opts)
- users := make([]*User, 0, opts.PageSize)
+ users := make([]*user_model.User, 0, opts.PageSize)
return users, sess.Find(&users)
}
- users := make([]*User, 0, 8)
+ users := make([]*user_model.User, 0, 8)
return users, sess.Find(&users)
}
@@ -232,7 +233,7 @@ func notifyWatchers(e db.Engine, actions ...*Action) error {
permIssue = make([]bool, len(watchers))
permPR = make([]bool, len(watchers))
for i, watcher := range watchers {
- user, err := getUserByID(e, watcher.UserID)
+ user, err := user_model.GetUserByIDEngine(e, watcher.UserID)
if err != nil {
permCode[i] = false
permIssue[i] = false
diff --git a/models/review.go b/models/review.go
index 00906c7a27..1c4943f699 100644
--- a/models/review.go
+++ b/models/review.go
@@ -10,6 +10,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unit"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/timeutil"
@@ -55,10 +56,10 @@ func (rt ReviewType) Icon() string {
type Review struct {
ID int64 `xorm:"pk autoincr"`
Type ReviewType
- Reviewer *User `xorm:"-"`
- ReviewerID int64 `xorm:"index"`
- ReviewerTeamID int64 `xorm:"NOT NULL DEFAULT 0"`
- ReviewerTeam *Team `xorm:"-"`
+ Reviewer *user_model.User `xorm:"-"`
+ ReviewerID int64 `xorm:"index"`
+ ReviewerTeamID int64 `xorm:"NOT NULL DEFAULT 0"`
+ ReviewerTeam *Team `xorm:"-"`
OriginalAuthor string
OriginalAuthorID int64
Issue *Issue `xorm:"-"`
@@ -111,7 +112,7 @@ func (r *Review) loadReviewer(e db.Engine) (err error) {
if r.ReviewerID == 0 || r.Reviewer != nil {
return
}
- r.Reviewer, err = getUserByID(e, r.ReviewerID)
+ r.Reviewer, err = user_model.GetUserByIDEngine(e, r.ReviewerID)
return
}
@@ -224,7 +225,7 @@ type CreateReviewOptions struct {
Content string
Type ReviewType
Issue *Issue
- Reviewer *User
+ Reviewer *user_model.User
ReviewerTeam *Team
Official bool
CommitID string
@@ -232,11 +233,11 @@ type CreateReviewOptions struct {
}
// IsOfficialReviewer check if at least one of the provided reviewers can make official reviews in issue (counts towards required approvals)
-func IsOfficialReviewer(issue *Issue, reviewers ...*User) (bool, error) {
+func IsOfficialReviewer(issue *Issue, reviewers ...*user_model.User) (bool, error) {
return isOfficialReviewer(db.GetEngine(db.DefaultContext), issue, reviewers...)
}
-func isOfficialReviewer(e db.Engine, issue *Issue, reviewers ...*User) (bool, error) {
+func isOfficialReviewer(e db.Engine, issue *Issue, reviewers ...*user_model.User) (bool, error) {
pr, err := getPullRequestByIssueID(e, issue.ID)
if err != nil {
return false, err
@@ -314,7 +315,7 @@ func CreateReview(opts CreateReviewOptions) (*Review, error) {
return createReview(db.GetEngine(db.DefaultContext), opts)
}
-func getCurrentReview(e db.Engine, reviewer *User, issue *Issue) (*Review, error) {
+func getCurrentReview(e db.Engine, reviewer *user_model.User, issue *Issue) (*Review, error) {
if reviewer == nil {
return nil, nil
}
@@ -340,7 +341,7 @@ func ReviewExists(issue *Issue, treePath string, line int64) (bool, error) {
}
// GetCurrentReview returns the current pending review of reviewer for given issue
-func GetCurrentReview(reviewer *User, issue *Issue) (*Review, error) {
+func GetCurrentReview(reviewer *user_model.User, issue *Issue) (*Review, error) {
return getCurrentReview(db.GetEngine(db.DefaultContext), reviewer, issue)
}
@@ -358,7 +359,7 @@ func IsContentEmptyErr(err error) bool {
}
// SubmitReview creates a review out of the existing pending review or creates a new one if no pending review exist
-func SubmitReview(doer *User, issue *Issue, reviewType ReviewType, content, commitID string, stale bool, attachmentUUIDs []string) (*Review, *Comment, error) {
+func SubmitReview(doer *user_model.User, issue *Issue, reviewType ReviewType, content, commitID string, stale bool, attachmentUUIDs []string) (*Review, *Comment, error) {
ctx, committer, err := db.TxContext()
if err != nil {
return nil, nil, err
@@ -627,7 +628,7 @@ func InsertReviews(reviews []*Review) error {
}
// AddReviewRequest add a review request from one reviewer
-func AddReviewRequest(issue *Issue, reviewer, doer *User) (*Comment, error) {
+func AddReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Comment, error) {
ctx, committer, err := db.TxContext()
if err != nil {
return nil, err
@@ -682,7 +683,7 @@ func AddReviewRequest(issue *Issue, reviewer, doer *User) (*Comment, error) {
}
// RemoveReviewRequest remove a review request from one reviewer
-func RemoveReviewRequest(issue *Issue, reviewer, doer *User) (*Comment, error) {
+func RemoveReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Comment, error) {
ctx, committer, err := db.TxContext()
if err != nil {
return nil, err
@@ -736,7 +737,7 @@ func RemoveReviewRequest(issue *Issue, reviewer, doer *User) (*Comment, error) {
}
// AddTeamReviewRequest add a review request from one team
-func AddTeamReviewRequest(issue *Issue, reviewer *Team, doer *User) (*Comment, error) {
+func AddTeamReviewRequest(issue *Issue, reviewer *Team, doer *user_model.User) (*Comment, error) {
ctx, committer, err := db.TxContext()
if err != nil {
return nil, err
@@ -796,7 +797,7 @@ func AddTeamReviewRequest(issue *Issue, reviewer *Team, doer *User) (*Comment, e
}
// RemoveTeamReviewRequest remove a review request from one team
-func RemoveTeamReviewRequest(issue *Issue, reviewer *Team, doer *User) (*Comment, error) {
+func RemoveTeamReviewRequest(issue *Issue, reviewer *Team, doer *user_model.User) (*Comment, error) {
ctx, committer, err := db.TxContext()
if err != nil {
return nil, err
@@ -856,7 +857,7 @@ func RemoveTeamReviewRequest(issue *Issue, reviewer *Team, doer *User) (*Comment
}
// MarkConversation Add or remove Conversation mark for a code comment
-func MarkConversation(comment *Comment, doer *User, isResolve bool) (err error) {
+func MarkConversation(comment *Comment, doer *user_model.User, isResolve bool) (err error) {
if comment.Type != CommentTypeCode {
return nil
}
@@ -884,7 +885,7 @@ func MarkConversation(comment *Comment, doer *User, isResolve bool) (err error)
// CanMarkConversation Add or remove Conversation mark for a code comment permission check
// the PR writer , offfcial reviewer and poster can do it
-func CanMarkConversation(issue *Issue, doer *User) (permResult bool, err error) {
+func CanMarkConversation(issue *Issue, doer *user_model.User) (permResult bool, err error) {
if doer == nil || issue == nil {
return false, fmt.Errorf("issue or doer is nil")
}
diff --git a/models/review_test.go b/models/review_test.go
index 7b8b86df13..b9d156ceb1 100644
--- a/models/review_test.go
+++ b/models/review_test.go
@@ -8,6 +8,7 @@ import (
"testing"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"github.com/stretchr/testify/assert"
)
@@ -72,7 +73,7 @@ func TestFindReviews(t *testing.T) {
func TestGetCurrentReview(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 2}).(*Issue)
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
review, err := GetCurrentReview(user, issue)
assert.NoError(t, err)
@@ -80,7 +81,7 @@ func TestGetCurrentReview(t *testing.T) {
assert.Equal(t, ReviewTypePending, review.Type)
assert.Equal(t, "Pending Review", review.Content)
- user2 := unittest.AssertExistsAndLoadBean(t, &User{ID: 7}).(*User)
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 7}).(*user_model.User)
review2, err := GetCurrentReview(user2, issue)
assert.Error(t, err)
assert.True(t, IsErrReviewNotExist(err))
@@ -91,7 +92,7 @@ func TestCreateReview(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 2}).(*Issue)
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
review, err := CreateReview(CreateReviewOptions{
Content: "New Review",
@@ -108,9 +109,9 @@ func TestGetReviewersByIssueID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 3}).(*Issue)
- user2 := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
- user3 := unittest.AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
- user4 := unittest.AssertExistsAndLoadBean(t, &User{ID: 4}).(*User)
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
+ user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
+ user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User)
expectedReviews := []*Review{}
expectedReviews = append(expectedReviews,
diff --git a/models/ssh_key.go b/models/ssh_key.go
index 21d5b7d496..780eb2e15c 100644
--- a/models/ssh_key.go
+++ b/models/ssh_key.go
@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/login"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
@@ -324,7 +325,7 @@ func PublicKeyIsExternallyManaged(id int64) (bool, error) {
}
// DeletePublicKey deletes SSH key information both in database and authorized_keys file.
-func DeletePublicKey(doer *User, id int64) (err error) {
+func DeletePublicKey(doer *user_model.User, id int64) (err error) {
key, err := GetPublicKeyByID(id)
if err != nil {
return err
@@ -390,7 +391,7 @@ func deleteKeysMarkedForDeletion(keys []string) (bool, error) {
}
// AddPublicKeysBySource add a users public keys. Returns true if there are changes.
-func AddPublicKeysBySource(usr *User, s *login.Source, sshPublicKeys []string) bool {
+func AddPublicKeysBySource(usr *user_model.User, s *login.Source, sshPublicKeys []string) bool {
var sshKeysNeedUpdate bool
for _, sshKey := range sshPublicKeys {
var err error
@@ -428,7 +429,7 @@ func AddPublicKeysBySource(usr *User, s *login.Source, sshPublicKeys []string) b
}
// SynchronizePublicKeys updates a users public keys. Returns true if there are changes.
-func SynchronizePublicKeys(usr *User, s *login.Source, sshPublicKeys []string) bool {
+func SynchronizePublicKeys(usr *user_model.User, s *login.Source, sshPublicKeys []string) bool {
var sshKeysNeedUpdate bool
log.Trace("synchronizePublicKeys[%s]: Handling Public SSH Key synchronization for user %s", s.Name, usr.Name)
diff --git a/models/ssh_key_deploy.go b/models/ssh_key_deploy.go
index c31379dcb4..cf439f6282 100644
--- a/models/ssh_key_deploy.go
+++ b/models/ssh_key_deploy.go
@@ -9,6 +9,7 @@ import (
"time"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/timeutil"
"xorm.io/builder"
@@ -212,7 +213,7 @@ func UpdateDeployKey(key *DeployKey) error {
}
// DeleteDeployKey deletes deploy key from its repository authorized_keys file if needed.
-func DeleteDeployKey(doer *User, id int64) error {
+func DeleteDeployKey(doer *user_model.User, id int64) error {
ctx, committer, err := db.TxContext()
if err != nil {
return err
@@ -225,7 +226,7 @@ func DeleteDeployKey(doer *User, id int64) error {
return committer.Commit()
}
-func deleteDeployKey(sess db.Engine, doer *User, id int64) error {
+func deleteDeployKey(sess db.Engine, doer *user_model.User, id int64) error {
key, err := getDeployKeyByID(sess, id)
if err != nil {
if IsErrDeployKeyNotExist(err) {
diff --git a/models/ssh_key_principals.go b/models/ssh_key_principals.go
index 55d8e40397..63c38f6886 100644
--- a/models/ssh_key_principals.go
+++ b/models/ssh_key_principals.go
@@ -73,7 +73,7 @@ func addPrincipalKey(e db.Engine, key *PublicKey) (err error) {
}
// CheckPrincipalKeyString strips spaces and returns an error if the given principal contains newlines
-func CheckPrincipalKeyString(user *User, content string) (_ string, err error) {
+func CheckPrincipalKeyString(user *user_model.User, content string) (_ string, err error) {
if setting.SSH.Disabled {
return "", ErrSSHDisabled{}
}
diff --git a/models/star.go b/models/star.go
index c0b15be21a..58bc77132d 100644
--- a/models/star.go
+++ b/models/star.go
@@ -6,6 +6,7 @@ package models
import (
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/timeutil"
)
@@ -74,16 +75,16 @@ func isStaring(e db.Engine, userID, repoID int64) bool {
}
// GetStargazers returns the users that starred the repo.
-func GetStargazers(repo *Repository, opts db.ListOptions) ([]*User, error) {
+func GetStargazers(repo *Repository, opts db.ListOptions) ([]*user_model.User, error) {
sess := db.GetEngine(db.DefaultContext).Where("star.repo_id = ?", repo.ID).
Join("LEFT", "star", "`user`.id = star.uid")
if opts.Page > 0 {
sess = db.SetSessionPagination(sess, &opts)
- users := make([]*User, 0, opts.PageSize)
+ users := make([]*user_model.User, 0, opts.PageSize)
return users, sess.Find(&users)
}
- users := make([]*User, 0, 8)
+ users := make([]*user_model.User, 0, 8)
return users, sess.Find(&users)
}
diff --git a/models/statistic.go b/models/statistic.go
index cb300c1a87..9a2a0d5c47 100644
--- a/models/statistic.go
+++ b/models/statistic.go
@@ -45,7 +45,7 @@ type IssueByRepositoryCount struct {
// GetStatistic returns the database statistics
func GetStatistic() (stats Statistic) {
e := db.GetEngine(db.DefaultContext)
- stats.Counter.User = CountUsers()
+ stats.Counter.User = user_model.CountUsers()
stats.Counter.Org = CountOrganizations()
stats.Counter.PublicKey, _ = e.Count(new(PublicKey))
stats.Counter.Repo = CountRepositories(true)
diff --git a/models/task.go b/models/task.go
index 9bff00cd8c..1999957270 100644
--- a/models/task.go
+++ b/models/task.go
@@ -8,6 +8,7 @@ import (
"fmt"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/migration"
"code.gitea.io/gitea/modules/secret"
@@ -22,12 +23,12 @@ import (
// Task represents a task
type Task struct {
ID int64
- DoerID int64 `xorm:"index"` // operator
- Doer *User `xorm:"-"`
- OwnerID int64 `xorm:"index"` // repo owner id, when creating, the repoID maybe zero
- Owner *User `xorm:"-"`
- RepoID int64 `xorm:"index"`
- Repo *Repository `xorm:"-"`
+ DoerID int64 `xorm:"index"` // operator
+ Doer *user_model.User `xorm:"-"`
+ OwnerID int64 `xorm:"index"` // repo owner id, when creating, the repoID maybe zero
+ Owner *user_model.User `xorm:"-"`
+ RepoID int64 `xorm:"index"`
+ Repo *Repository `xorm:"-"`
Type structs.TaskType
Status structs.TaskStatus `xorm:"index"`
StartTime timeutil.TimeStamp
@@ -75,12 +76,12 @@ func (task *Task) LoadDoer() error {
return nil
}
- var doer User
+ var doer user_model.User
has, err := db.GetEngine(db.DefaultContext).ID(task.DoerID).Get(&doer)
if err != nil {
return err
} else if !has {
- return ErrUserNotExist{
+ return user_model.ErrUserNotExist{
UID: task.DoerID,
}
}
@@ -95,12 +96,12 @@ func (task *Task) LoadOwner() error {
return nil
}
- var owner User
+ var owner user_model.User
has, err := db.GetEngine(db.DefaultContext).ID(task.OwnerID).Get(&owner)
if err != nil {
return err
} else if !has {
- return ErrUserNotExist{
+ return user_model.ErrUserNotExist{
UID: task.OwnerID,
}
}
diff --git a/models/user.go b/models/user.go
index 4126606e24..9816fcc713 100644
--- a/models/user.go
+++ b/models/user.go
@@ -7,491 +7,22 @@ package models
import (
"context"
- "crypto/sha256"
- "crypto/subtle"
- "encoding/hex"
- "errors"
"fmt"
- "net/url"
- "os"
- "path/filepath"
- "regexp"
- "strings"
"time"
- "unicode/utf8"
_ "image/jpeg" // Needed for jpeg support
"code.gitea.io/gitea/models/db"
- "code.gitea.io/gitea/models/login"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
- "code.gitea.io/gitea/modules/auth/openid"
- "code.gitea.io/gitea/modules/base"
- "code.gitea.io/gitea/modules/git"
- "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
- "code.gitea.io/gitea/modules/timeutil"
- "code.gitea.io/gitea/modules/util"
- "golang.org/x/crypto/argon2"
- "golang.org/x/crypto/bcrypt"
- "golang.org/x/crypto/pbkdf2"
- "golang.org/x/crypto/scrypt"
"xorm.io/builder"
- "xorm.io/xorm"
)
-// UserType defines the user type
-type UserType int
-
-const (
- // UserTypeIndividual defines an individual user
- UserTypeIndividual UserType = iota // Historic reason to make it starts at 0.
-
- // UserTypeOrganization defines an organization
- UserTypeOrganization
-)
-
-const (
- algoBcrypt = "bcrypt"
- algoScrypt = "scrypt"
- algoArgon2 = "argon2"
- algoPbkdf2 = "pbkdf2"
-)
-
-// AvailableHashAlgorithms represents the available password hashing algorithms
-var AvailableHashAlgorithms = []string{
- algoPbkdf2,
- algoArgon2,
- algoScrypt,
- algoBcrypt,
-}
-
-const (
- // EmailNotificationsEnabled indicates that the user would like to receive all email notifications
- EmailNotificationsEnabled = "enabled"
- // EmailNotificationsOnMention indicates that the user would like to be notified via email when mentioned.
- EmailNotificationsOnMention = "onmention"
- // EmailNotificationsDisabled indicates that the user would not like to be notified via email.
- EmailNotificationsDisabled = "disabled"
-)
-
-var (
- // ErrUserNameIllegal user name contains illegal characters error
- ErrUserNameIllegal = errors.New("User name contains illegal characters")
-
- // ErrLoginSourceNotActived login source is not actived error
- ErrLoginSourceNotActived = errors.New("Login source is not actived")
-
- // ErrUnsupportedLoginType login source is unknown error
- ErrUnsupportedLoginType = errors.New("Login source is unknown")
-
- // Characters prohibited in a user name (anything except A-Za-z0-9_.-)
- alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
-)
-
-// User represents the object of individual and member of organization.
-type User struct {
- ID int64 `xorm:"pk autoincr"`
- LowerName string `xorm:"UNIQUE NOT NULL"`
- Name string `xorm:"UNIQUE NOT NULL"`
- FullName string
- // Email is the primary email address (to be used for communication)
- Email string `xorm:"NOT NULL"`
- KeepEmailPrivate bool
- EmailNotificationsPreference string `xorm:"VARCHAR(20) NOT NULL DEFAULT 'enabled'"`
- Passwd string `xorm:"NOT NULL"`
- PasswdHashAlgo string `xorm:"NOT NULL DEFAULT 'argon2'"`
-
- // MustChangePassword is an attribute that determines if a user
- // is to change his/her password after registration.
- MustChangePassword bool `xorm:"NOT NULL DEFAULT false"`
-
- LoginType login.Type
- LoginSource int64 `xorm:"NOT NULL DEFAULT 0"`
- LoginName string
- Type UserType
- Location string
- Website string
- Rands string `xorm:"VARCHAR(10)"`
- Salt string `xorm:"VARCHAR(10)"`
- Language string `xorm:"VARCHAR(5)"`
- Description string
-
- CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
- UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
- LastLoginUnix timeutil.TimeStamp `xorm:"INDEX"`
-
- // Remember visibility choice for convenience, true for private
- LastRepoVisibility bool
- // Maximum repository creation limit, -1 means use global default
- MaxRepoCreation int `xorm:"NOT NULL DEFAULT -1"`
-
- // IsActive true: primary email is activated, user can access Web UI and Git SSH.
- // false: an inactive user can only log in Web UI for account operations (ex: activate the account by email), no other access.
- IsActive bool `xorm:"INDEX"`
- // the user is a Gitea admin, who can access all repositories and the admin pages.
- IsAdmin bool
- // true: the user is only allowed to see organizations/repositories that they has explicit rights to.
- // (ex: in private Gitea instances user won't be allowed to see even organizations/repositories that are set as public)
- IsRestricted bool `xorm:"NOT NULL DEFAULT false"`
-
- AllowGitHook bool
- AllowImportLocal bool // Allow migrate repository by local path
- AllowCreateOrganization bool `xorm:"DEFAULT true"`
-
- // true: the user is not allowed to log in Web UI. Git/SSH access could still be allowed (please refer to Git/SSH access related code/documents)
- ProhibitLogin bool `xorm:"NOT NULL DEFAULT false"`
-
- // Avatar
- Avatar string `xorm:"VARCHAR(2048) NOT NULL"`
- AvatarEmail string `xorm:"NOT NULL"`
- UseCustomAvatar bool
-
- // Counters
- NumFollowers int
- NumFollowing int `xorm:"NOT NULL DEFAULT 0"`
- NumStars int
- NumRepos int
-
- // For organization
- NumTeams int
- NumMembers int
- Visibility structs.VisibleType `xorm:"NOT NULL DEFAULT 0"`
- RepoAdminChangeTeamAccess bool `xorm:"NOT NULL DEFAULT false"`
-
- // Preferences
- DiffViewStyle string `xorm:"NOT NULL DEFAULT ''"`
- Theme string `xorm:"NOT NULL DEFAULT ''"`
- KeepActivityPrivate bool `xorm:"NOT NULL DEFAULT false"`
-}
-
-func init() {
- db.RegisterModel(new(User))
-}
-
-// SearchOrganizationsOptions options to filter organizations
-type SearchOrganizationsOptions struct {
- db.ListOptions
- All bool
-}
-
-// ColorFormat writes a colored string to identify this struct
-func (u *User) ColorFormat(s fmt.State) {
- log.ColorFprintf(s, "%d:%s",
- log.NewColoredIDValue(u.ID),
- log.NewColoredValue(u.Name))
-}
-
-// BeforeUpdate is invoked from XORM before updating this object.
-func (u *User) BeforeUpdate() {
- if u.MaxRepoCreation < -1 {
- u.MaxRepoCreation = -1
- }
-
- // Organization does not need email
- u.Email = strings.ToLower(u.Email)
- if !u.IsOrganization() {
- if len(u.AvatarEmail) == 0 {
- u.AvatarEmail = u.Email
- }
- }
-
- u.LowerName = strings.ToLower(u.Name)
- u.Location = base.TruncateString(u.Location, 255)
- u.Website = base.TruncateString(u.Website, 255)
- u.Description = base.TruncateString(u.Description, 255)
-}
-
-// AfterLoad is invoked from XORM after filling all the fields of this object.
-func (u *User) AfterLoad() {
- if u.Theme == "" {
- u.Theme = setting.UI.DefaultTheme
- }
-}
-
-// SetLastLogin set time to last login
-func (u *User) SetLastLogin() {
- u.LastLoginUnix = timeutil.TimeStampNow()
-}
-
-// UpdateUserDiffViewStyle updates the users diff view style
-func UpdateUserDiffViewStyle(u *User, style string) error {
- u.DiffViewStyle = style
- return UpdateUserCols(db.DefaultContext, u, "diff_view_style")
-}
-
-// UpdateUserTheme updates a users' theme irrespective of the site wide theme
-func UpdateUserTheme(u *User, themeName string) error {
- u.Theme = themeName
- return UpdateUserCols(db.DefaultContext, u, "theme")
-}
-
-// GetEmail returns an noreply email, if the user has set to keep his
-// email address private, otherwise the primary email address.
-func (u *User) GetEmail() string {
- if u.KeepEmailPrivate {
- return fmt.Sprintf("%s@%s", u.LowerName, setting.Service.NoReplyAddress)
- }
- return u.Email
-}
-
-// GetAllUsers returns a slice of all individual users found in DB.
-func GetAllUsers() ([]*User, error) {
- users := make([]*User, 0)
- return users, db.GetEngine(db.DefaultContext).OrderBy("id").Where("type = ?", UserTypeIndividual).Find(&users)
-}
-
-// IsLocal returns true if user login type is LoginPlain.
-func (u *User) IsLocal() bool {
- return u.LoginType <= login.Plain
-}
-
-// IsOAuth2 returns true if user login type is LoginOAuth2.
-func (u *User) IsOAuth2() bool {
- return u.LoginType == login.OAuth2
-}
-
-// MaxCreationLimit returns the number of repositories a user is allowed to create
-func (u *User) MaxCreationLimit() int {
- if u.MaxRepoCreation <= -1 {
- return setting.Repository.MaxCreationLimit
- }
- return u.MaxRepoCreation
-}
-
-// CanCreateRepo returns if user login can create a repository
-// NOTE: functions calling this assume a failure due to repository count limit; if new checks are added, those functions should be revised
-func (u *User) CanCreateRepo() bool {
- if u.IsAdmin {
- return true
- }
- if u.MaxRepoCreation <= -1 {
- if setting.Repository.MaxCreationLimit <= -1 {
- return true
- }
- return u.NumRepos < setting.Repository.MaxCreationLimit
- }
- return u.NumRepos < u.MaxRepoCreation
-}
-
-// CanCreateOrganization returns true if user can create organisation.
-func (u *User) CanCreateOrganization() bool {
- return u.IsAdmin || (u.AllowCreateOrganization && !setting.Admin.DisableRegularOrgCreation)
-}
-
-// CanEditGitHook returns true if user can edit Git hooks.
-func (u *User) CanEditGitHook() bool {
- return !setting.DisableGitHooks && (u.IsAdmin || u.AllowGitHook)
-}
-
-// CanImportLocal returns true if user can migrate repository by local path.
-func (u *User) CanImportLocal() bool {
- if !setting.ImportLocalPaths || u == nil {
- return false
- }
- return u.IsAdmin || u.AllowImportLocal
-}
-
-// DashboardLink returns the user dashboard page link.
-func (u *User) DashboardLink() string {
- if u.IsOrganization() {
- return u.OrganisationLink() + "/dashboard"
- }
- return setting.AppSubURL + "/"
-}
-
-// HomeLink returns the user or organization home page link.
-func (u *User) HomeLink() string {
- return setting.AppSubURL + "/" + url.PathEscape(u.Name)
-}
-
-// HTMLURL returns the user or organization's full link.
-func (u *User) HTMLURL() string {
- return setting.AppURL + url.PathEscape(u.Name)
-}
-
-// OrganisationLink returns the organization sub page link.
-func (u *User) OrganisationLink() string {
- return setting.AppSubURL + "/org/" + url.PathEscape(u.Name)
-}
-
-// GenerateEmailActivateCode generates an activate code based on user information and given e-mail.
-func (u *User) GenerateEmailActivateCode(email string) string {
- code := base.CreateTimeLimitCode(
- fmt.Sprintf("%d%s%s%s%s", u.ID, email, u.LowerName, u.Passwd, u.Rands),
- setting.Service.ActiveCodeLives, nil)
-
- // Add tail hex username
- code += hex.EncodeToString([]byte(u.LowerName))
- return code
-}
-
-// GetUserFollowers returns range of user's followers.
-func GetUserFollowers(u *User, listOptions db.ListOptions) ([]*User, error) {
- sess := db.GetEngine(db.DefaultContext).
- Where("follow.follow_id=?", u.ID).
- Join("LEFT", "follow", "`user`.id=follow.user_id")
-
- if listOptions.Page != 0 {
- sess = db.SetSessionPagination(sess, &listOptions)
-
- users := make([]*User, 0, listOptions.PageSize)
- return users, sess.Find(&users)
- }
-
- users := make([]*User, 0, 8)
- return users, sess.Find(&users)
-}
-
-// GetUserFollowing returns range of user's following.
-func GetUserFollowing(u *User, listOptions db.ListOptions) ([]*User, error) {
- sess := db.GetEngine(db.DefaultContext).
- Where("follow.user_id=?", u.ID).
- Join("LEFT", "follow", "`user`.id=follow.follow_id")
-
- if listOptions.Page != 0 {
- sess = db.SetSessionPagination(sess, &listOptions)
-
- users := make([]*User, 0, listOptions.PageSize)
- return users, sess.Find(&users)
- }
-
- users := make([]*User, 0, 8)
- return users, sess.Find(&users)
-}
-
-// NewGitSig generates and returns the signature of given user.
-func (u *User) NewGitSig() *git.Signature {
- return &git.Signature{
- Name: u.GitName(),
- Email: u.GetEmail(),
- When: time.Now(),
- }
-}
-
-func hashPassword(passwd, salt, algo string) string {
- var tempPasswd []byte
-
- switch algo {
- case algoBcrypt:
- tempPasswd, _ = bcrypt.GenerateFromPassword([]byte(passwd), bcrypt.DefaultCost)
- return string(tempPasswd)
- case algoScrypt:
- tempPasswd, _ = scrypt.Key([]byte(passwd), []byte(salt), 65536, 16, 2, 50)
- case algoArgon2:
- tempPasswd = argon2.IDKey([]byte(passwd), []byte(salt), 2, 65536, 8, 50)
- case algoPbkdf2:
- fallthrough
- default:
- tempPasswd = pbkdf2.Key([]byte(passwd), []byte(salt), 10000, 50, sha256.New)
- }
-
- return fmt.Sprintf("%x", tempPasswd)
-}
-
-// SetPassword hashes a password using the algorithm defined in the config value of PASSWORD_HASH_ALGO
-// change passwd, salt and passwd_hash_algo fields
-func (u *User) SetPassword(passwd string) (err error) {
- if len(passwd) == 0 {
- u.Passwd = ""
- u.Salt = ""
- u.PasswdHashAlgo = ""
- return nil
- }
-
- if u.Salt, err = GetUserSalt(); err != nil {
- return err
- }
- u.PasswdHashAlgo = setting.PasswordHashAlgo
- u.Passwd = hashPassword(passwd, u.Salt, setting.PasswordHashAlgo)
-
- return nil
-}
-
-// ValidatePassword checks if given password matches the one belongs to the user.
-func (u *User) ValidatePassword(passwd string) bool {
- tempHash := hashPassword(passwd, u.Salt, u.PasswdHashAlgo)
-
- if u.PasswdHashAlgo != algoBcrypt && subtle.ConstantTimeCompare([]byte(u.Passwd), []byte(tempHash)) == 1 {
- return true
- }
- if u.PasswdHashAlgo == algoBcrypt && bcrypt.CompareHashAndPassword([]byte(u.Passwd), []byte(passwd)) == nil {
- return true
- }
- return false
-}
-
-// IsPasswordSet checks if the password is set or left empty
-func (u *User) IsPasswordSet() bool {
- return len(u.Passwd) != 0
-}
-
-// IsUserVisibleToViewer check if viewer is able to see user profile
-func IsUserVisibleToViewer(u *User, viewer *User) bool {
- return isUserVisibleToViewer(db.GetEngine(db.DefaultContext), u, viewer)
-}
-
-func isUserVisibleToViewer(e db.Engine, u *User, viewer *User) bool {
- if viewer != nil && viewer.IsAdmin {
- return true
- }
-
- switch u.Visibility {
- case structs.VisibleTypePublic:
- return true
- case structs.VisibleTypeLimited:
- if viewer == nil || viewer.IsRestricted {
- return false
- }
- return true
- case structs.VisibleTypePrivate:
- if viewer == nil || viewer.IsRestricted {
- return false
- }
-
- // If they follow - they see each over
- follower := user_model.IsFollowing(u.ID, viewer.ID)
- if follower {
- return true
- }
-
- // Now we need to check if they in some organization together
- count, err := e.Table("team_user").
- Where(
- builder.And(
- builder.Eq{"uid": viewer.ID},
- builder.Or(
- builder.Eq{"org_id": u.ID},
- builder.In("org_id",
- builder.Select("org_id").
- From("team_user", "t2").
- Where(builder.Eq{"uid": u.ID}))))).
- Count(new(TeamUser))
- if err != nil {
- return false
- }
-
- if count < 0 {
- // No common organization
- return false
- }
-
- // they are in an organization together
- return true
- }
- return false
-}
-
-// IsOrganization returns true if user is actually a organization.
-func (u *User) IsOrganization() bool {
- return u.Type == UserTypeOrganization
-}
-
// GetOrganizationCount returns count of membership of organization of the user.
-func GetOrganizationCount(ctx context.Context, u *User) (int64, error) {
+func GetOrganizationCount(ctx context.Context, u *user_model.User) (int64, error) {
return db.GetEngine(ctx).
Where("uid=?", u.ID).
Count(new(OrgUser))
@@ -499,7 +30,7 @@ func GetOrganizationCount(ctx context.Context, u *User) (int64, error) {
// GetRepositoryIDs returns repositories IDs where user owned and has unittypes
// Caller shall check that units is not globally disabled
-func (u *User) GetRepositoryIDs(units ...unit.Type) ([]int64, error) {
+func GetRepositoryIDs(u *user_model.User, units ...unit.Type) ([]int64, error) {
var ids []int64
sess := db.GetEngine(db.DefaultContext).Table("repository").Cols("repository.id")
@@ -514,7 +45,7 @@ func (u *User) GetRepositoryIDs(units ...unit.Type) ([]int64, error) {
// GetActiveRepositoryIDs returns non-archived repositories IDs where user owned and has unittypes
// Caller shall check that units is not globally disabled
-func (u *User) GetActiveRepositoryIDs(units ...unit.Type) ([]int64, error) {
+func GetActiveRepositoryIDs(u *user_model.User, units ...unit.Type) ([]int64, error) {
var ids []int64
sess := db.GetEngine(db.DefaultContext).Table("repository").Cols("repository.id")
@@ -531,7 +62,7 @@ func (u *User) GetActiveRepositoryIDs(units ...unit.Type) ([]int64, error) {
// GetOrgRepositoryIDs returns repositories IDs where user's team owned and has unittypes
// Caller shall check that units is not globally disabled
-func (u *User) GetOrgRepositoryIDs(units ...unit.Type) ([]int64, error) {
+func GetOrgRepositoryIDs(u *user_model.User, units ...unit.Type) ([]int64, error) {
var ids []int64
if err := db.GetEngine(db.DefaultContext).Table("repository").
@@ -552,7 +83,7 @@ func (u *User) GetOrgRepositoryIDs(units ...unit.Type) ([]int64, error) {
// GetActiveOrgRepositoryIDs returns non-archived repositories IDs where user's team owned and has unittypes
// Caller shall check that units is not globally disabled
-func (u *User) GetActiveOrgRepositoryIDs(units ...unit.Type) ([]int64, error) {
+func GetActiveOrgRepositoryIDs(u *user_model.User, units ...unit.Type) ([]int64, error) {
var ids []int64
if err := db.GetEngine(db.DefaultContext).Table("repository").
@@ -574,12 +105,12 @@ func (u *User) GetActiveOrgRepositoryIDs(units ...unit.Type) ([]int64, error) {
// GetAccessRepoIDs returns all repositories IDs where user's or user is a team member organizations
// Caller shall check that units is not globally disabled
-func (u *User) GetAccessRepoIDs(units ...unit.Type) ([]int64, error) {
- ids, err := u.GetRepositoryIDs(units...)
+func GetAccessRepoIDs(u *user_model.User, units ...unit.Type) ([]int64, error) {
+ ids, err := GetRepositoryIDs(u, units...)
if err != nil {
return nil, err
}
- ids2, err := u.GetOrgRepositoryIDs(units...)
+ ids2, err := GetOrgRepositoryIDs(u, units...)
if err != nil {
return nil, err
}
@@ -588,467 +119,18 @@ func (u *User) GetAccessRepoIDs(units ...unit.Type) ([]int64, error) {
// GetActiveAccessRepoIDs returns all non-archived repositories IDs where user's or user is a team member organizations
// Caller shall check that units is not globally disabled
-func (u *User) GetActiveAccessRepoIDs(units ...unit.Type) ([]int64, error) {
- ids, err := u.GetActiveRepositoryIDs(units...)
+func GetActiveAccessRepoIDs(u *user_model.User, units ...unit.Type) ([]int64, error) {
+ ids, err := GetActiveRepositoryIDs(u, units...)
if err != nil {
return nil, err
}
- ids2, err := u.GetActiveOrgRepositoryIDs(units...)
+ ids2, err := GetActiveOrgRepositoryIDs(u, units...)
if err != nil {
return nil, err
}
return append(ids, ids2...), nil
}
-// DisplayName returns full name if it's not empty,
-// returns username otherwise.
-func (u *User) DisplayName() string {
- trimmed := strings.TrimSpace(u.FullName)
- if len(trimmed) > 0 {
- return trimmed
- }
- return u.Name
-}
-
-// GetDisplayName returns full name if it's not empty and DEFAULT_SHOW_FULL_NAME is set,
-// returns username otherwise.
-func (u *User) GetDisplayName() string {
- if setting.UI.DefaultShowFullName {
- trimmed := strings.TrimSpace(u.FullName)
- if len(trimmed) > 0 {
- return trimmed
- }
- }
- return u.Name
-}
-
-func gitSafeName(name string) string {
- return strings.TrimSpace(strings.NewReplacer("\n", "", "<", "", ">", "").Replace(name))
-}
-
-// GitName returns a git safe name
-func (u *User) GitName() string {
- gitName := gitSafeName(u.FullName)
- if len(gitName) > 0 {
- return gitName
- }
- // Although u.Name should be safe if created in our system
- // LDAP users may have bad names
- gitName = gitSafeName(u.Name)
- if len(gitName) > 0 {
- return gitName
- }
- // Totally pathological name so it's got to be:
- return fmt.Sprintf("user-%d", u.ID)
-}
-
-// ShortName ellipses username to length
-func (u *User) ShortName(length int) string {
- return base.EllipsisString(u.Name, length)
-}
-
-// IsMailable checks if a user is eligible
-// to receive emails.
-func (u *User) IsMailable() bool {
- return u.IsActive
-}
-
-// EmailNotifications returns the User's email notification preference
-func (u *User) EmailNotifications() string {
- return u.EmailNotificationsPreference
-}
-
-// SetEmailNotifications sets the user's email notification preference
-func SetEmailNotifications(u *User, set string) error {
- u.EmailNotificationsPreference = set
- if err := UpdateUserCols(db.DefaultContext, u, "email_notifications_preference"); err != nil {
- log.Error("SetEmailNotifications: %v", err)
- return err
- }
- return nil
-}
-
-func isUserExist(e db.Engine, uid int64, name string) (bool, error) {
- if len(name) == 0 {
- return false, nil
- }
- return e.
- Where("id!=?", uid).
- Get(&User{LowerName: strings.ToLower(name)})
-}
-
-// IsUserExist checks if given user name exist,
-// the user name should be noncased unique.
-// If uid is presented, then check will rule out that one,
-// it is used when update a user name in settings page.
-func IsUserExist(uid int64, name string) (bool, error) {
- return isUserExist(db.GetEngine(db.DefaultContext), uid, name)
-}
-
-// GetUserSalt returns a random user salt token.
-func GetUserSalt() (string, error) {
- return util.RandomString(10)
-}
-
-// NewGhostUser creates and returns a fake user for someone has deleted his/her account.
-func NewGhostUser() *User {
- return &User{
- ID: -1,
- Name: "Ghost",
- LowerName: "ghost",
- }
-}
-
-// NewReplaceUser creates and returns a fake user for external user
-func NewReplaceUser(name string) *User {
- return &User{
- ID: -1,
- Name: name,
- LowerName: strings.ToLower(name),
- }
-}
-
-// IsGhost check if user is fake user for a deleted account
-func (u *User) IsGhost() bool {
- if u == nil {
- return false
- }
- return u.ID == -1 && u.Name == "Ghost"
-}
-
-var (
- reservedUsernames = []string{
- ".",
- "..",
- ".well-known",
- "admin",
- "api",
- "assets",
- "attachments",
- "avatars",
- "captcha",
- "commits",
- "debug",
- "error",
- "explore",
- "favicon.ico",
- "ghost",
- "help",
- "install",
- "issues",
- "less",
- "login",
- "manifest.json",
- "metrics",
- "milestones",
- "new",
- "notifications",
- "org",
- "plugins",
- "pulls",
- "raw",
- "repo",
- "robots.txt",
- "search",
- "serviceworker.js",
- "stars",
- "template",
- "user",
- }
-
- reservedUserPatterns = []string{"*.keys", "*.gpg", "*.rss", "*.atom"}
-)
-
-// isUsableName checks if name is reserved or pattern of name is not allowed
-// based on given reserved names and patterns.
-// Names are exact match, patterns can be prefix or suffix match with placeholder '*'.
-func isUsableName(names, patterns []string, name string) error {
- name = strings.TrimSpace(strings.ToLower(name))
- if utf8.RuneCountInString(name) == 0 {
- return ErrNameEmpty
- }
-
- for i := range names {
- if name == names[i] {
- return ErrNameReserved{name}
- }
- }
-
- for _, pat := range patterns {
- if pat[0] == '*' && strings.HasSuffix(name, pat[1:]) ||
- (pat[len(pat)-1] == '*' && strings.HasPrefix(name, pat[:len(pat)-1])) {
- return ErrNamePatternNotAllowed{pat}
- }
- }
-
- return nil
-}
-
-// IsUsableUsername returns an error when a username is reserved
-func IsUsableUsername(name string) error {
- // Validate username make sure it satisfies requirement.
- if alphaDashDotPattern.MatchString(name) {
- // Note: usually this error is normally caught up earlier in the UI
- return ErrNameCharsNotAllowed{Name: name}
- }
- return isUsableName(reservedUsernames, reservedUserPatterns, name)
-}
-
-// CreateUserOverwriteOptions are an optional options who overwrite system defaults on user creation
-type CreateUserOverwriteOptions struct {
- Visibility structs.VisibleType
-}
-
-// CreateUser creates record of a new user.
-func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err error) {
- if err = IsUsableUsername(u.Name); err != nil {
- return err
- }
-
- // set system defaults
- u.KeepEmailPrivate = setting.Service.DefaultKeepEmailPrivate
- u.Visibility = setting.Service.DefaultUserVisibilityMode
- u.AllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization && !setting.Admin.DisableRegularOrgCreation
- u.EmailNotificationsPreference = setting.Admin.DefaultEmailNotification
- u.MaxRepoCreation = -1
- u.Theme = setting.UI.DefaultTheme
-
- // overwrite defaults if set
- if len(overwriteDefault) != 0 && overwriteDefault[0] != nil {
- u.Visibility = overwriteDefault[0].Visibility
- }
-
- ctx, committer, err := db.TxContext()
- if err != nil {
- return err
- }
- defer committer.Close()
-
- sess := db.GetEngine(ctx)
-
- // validate data
- if err := validateUser(u); err != nil {
- return err
- }
-
- isExist, err := isUserExist(sess, 0, u.Name)
- if err != nil {
- return err
- } else if isExist {
- return ErrUserAlreadyExist{u.Name}
- }
-
- isExist, err = user_model.IsEmailUsed(ctx, u.Email)
- if err != nil {
- return err
- } else if isExist {
- return user_model.ErrEmailAlreadyUsed{
- Email: u.Email,
- }
- }
-
- // prepare for database
-
- u.LowerName = strings.ToLower(u.Name)
- u.AvatarEmail = u.Email
- if u.Rands, err = GetUserSalt(); err != nil {
- return err
- }
- if err = u.SetPassword(u.Passwd); err != nil {
- return err
- }
-
- // save changes to database
-
- if err = user_model.DeleteUserRedirect(ctx, u.Name); err != nil {
- return err
- }
-
- if err = db.Insert(ctx, u); err != nil {
- return err
- }
-
- // insert email address
- if err := db.Insert(ctx, &user_model.EmailAddress{
- UID: u.ID,
- Email: u.Email,
- LowerEmail: strings.ToLower(u.Email),
- IsActivated: u.IsActive,
- IsPrimary: true,
- }); err != nil {
- return err
- }
-
- return committer.Commit()
-}
-
-func countUsers(e db.Engine) int64 {
- count, _ := e.
- Where("type=0").
- Count(new(User))
- return count
-}
-
-// CountUsers returns number of users.
-func CountUsers() int64 {
- return countUsers(db.GetEngine(db.DefaultContext))
-}
-
-// get user by verify code
-func getVerifyUser(code string) (user *User) {
- if len(code) <= base.TimeLimitCodeLength {
- return nil
- }
-
- // use tail hex username query user
- hexStr := code[base.TimeLimitCodeLength:]
- if b, err := hex.DecodeString(hexStr); err == nil {
- if user, err = GetUserByName(string(b)); user != nil {
- return user
- }
- log.Error("user.getVerifyUser: %v", err)
- }
-
- return nil
-}
-
-// VerifyUserActiveCode verifies active code when active account
-func VerifyUserActiveCode(code string) (user *User) {
- minutes := setting.Service.ActiveCodeLives
-
- if user = getVerifyUser(code); user != nil {
- // time limit code
- prefix := code[:base.TimeLimitCodeLength]
- data := fmt.Sprintf("%d%s%s%s%s", user.ID, user.Email, user.LowerName, user.Passwd, user.Rands)
-
- if base.VerifyTimeLimitCode(data, minutes, prefix) {
- return user
- }
- }
- return nil
-}
-
-// ChangeUserName changes all corresponding setting from old user name to new one.
-func ChangeUserName(u *User, newUserName string) (err error) {
- oldUserName := u.Name
- if err = IsUsableUsername(newUserName); err != nil {
- return err
- }
-
- ctx, committer, err := db.TxContext()
- if err != nil {
- return err
- }
- defer committer.Close()
- sess := db.GetEngine(ctx)
-
- isExist, err := isUserExist(sess, 0, newUserName)
- if err != nil {
- return err
- } else if isExist {
- return ErrUserAlreadyExist{newUserName}
- }
-
- if _, err = sess.Exec("UPDATE `repository` SET owner_name=? WHERE owner_name=?", newUserName, oldUserName); err != nil {
- return fmt.Errorf("Change repo owner name: %v", err)
- }
-
- // Do not fail if directory does not exist
- if err = util.Rename(UserPath(oldUserName), UserPath(newUserName)); err != nil && !os.IsNotExist(err) {
- return fmt.Errorf("Rename user directory: %v", err)
- }
-
- if err = user_model.NewUserRedirect(ctx, u.ID, oldUserName, newUserName); err != nil {
- return err
- }
-
- if err = committer.Commit(); err != nil {
- if err2 := util.Rename(UserPath(newUserName), UserPath(oldUserName)); err2 != nil && !os.IsNotExist(err2) {
- log.Critical("Unable to rollback directory change during failed username change from: %s to: %s. DB Error: %v. Filesystem Error: %v", oldUserName, newUserName, err, err2)
- return fmt.Errorf("failed to rollback directory change during failed username change from: %s to: %s. DB Error: %w. Filesystem Error: %v", oldUserName, newUserName, err, err2)
- }
- return err
- }
-
- return nil
-}
-
-// checkDupEmail checks whether there are the same email with the user
-func checkDupEmail(e db.Engine, u *User) error {
- u.Email = strings.ToLower(u.Email)
- has, err := e.
- Where("id!=?", u.ID).
- And("type=?", u.Type).
- And("email=?", u.Email).
- Get(new(User))
- if err != nil {
- return err
- } else if has {
- return user_model.ErrEmailAlreadyUsed{
- Email: u.Email,
- }
- }
- return nil
-}
-
-// validateUser check if user is valid to insert / update into database
-func validateUser(u *User) error {
- if !setting.Service.AllowedUserVisibilityModesSlice.IsAllowedVisibility(u.Visibility) && !u.IsOrganization() {
- return fmt.Errorf("visibility Mode not allowed: %s", u.Visibility.String())
- }
-
- u.Email = strings.ToLower(u.Email)
- return user_model.ValidateEmail(u.Email)
-}
-
-func updateUser(e db.Engine, u *User) error {
- if err := validateUser(u); err != nil {
- return err
- }
-
- _, err := e.ID(u.ID).AllCols().Update(u)
- return err
-}
-
-// UpdateUser updates user's information.
-func UpdateUser(u *User) error {
- return updateUser(db.GetEngine(db.DefaultContext), u)
-}
-
-// UpdateUserCols update user according special columns
-func UpdateUserCols(ctx context.Context, u *User, cols ...string) error {
- return updateUserCols(db.GetEngine(ctx), u, cols...)
-}
-
-func updateUserCols(e db.Engine, u *User, cols ...string) error {
- if err := validateUser(u); err != nil {
- return err
- }
-
- _, err := e.ID(u.ID).Cols(cols...).Update(u)
- return err
-}
-
-// UpdateUserSetting updates user's settings.
-func UpdateUserSetting(u *User) (err error) {
- ctx, committer, err := db.TxContext()
- if err != nil {
- return err
- }
- defer committer.Close()
- sess := db.GetEngine(ctx)
-
- if !u.IsOrganization() {
- if err = checkDupEmail(sess, u); err != nil {
- return err
- }
- }
- if err = updateUser(sess, u); err != nil {
- return err
- }
- return committer.Commit()
-}
-
// deleteBeans deletes all given beans, beans should contain delete conditions.
func deleteBeans(e db.Engine, beans ...interface{}) (err error) {
for i := range beans {
@@ -1060,7 +142,7 @@ func deleteBeans(e db.Engine, beans ...interface{}) (err error) {
}
// DeleteUser deletes models associated to an user.
-func DeleteUser(ctx context.Context, u *User) (err error) {
+func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
e := db.GetEngine(ctx)
// ***** START: Watch *****
@@ -1089,7 +171,7 @@ func DeleteUser(ctx context.Context, u *User) (err error) {
if err = e.Table("follow").Cols("follow.follow_id").
Where("follow.user_id = ?", u.ID).Find(&followeeIDs); err != nil {
return fmt.Errorf("get all followees: %v", err)
- } else if _, err = e.Decr("num_followers").In("id", followeeIDs).Update(new(User)); err != nil {
+ } else if _, err = e.Decr("num_followers").In("id", followeeIDs).Update(new(user_model.User)); err != nil {
return fmt.Errorf("decrease user num_followers: %v", err)
}
@@ -1097,7 +179,7 @@ func DeleteUser(ctx context.Context, u *User) (err error) {
if err = e.Table("follow").Cols("follow.user_id").
Where("follow.follow_id = ?", u.ID).Find(&followerIDs); err != nil {
return fmt.Errorf("get all followers: %v", err)
- } else if _, err = e.Decr("num_following").In("id", followerIDs).Update(new(User)); err != nil {
+ } else if _, err = e.Decr("num_following").In("id", followerIDs).Update(new(user_model.User)); err != nil {
return fmt.Errorf("decrease user num_following: %v", err)
}
// ***** END: Follow *****
@@ -1183,386 +265,13 @@ func DeleteUser(ctx context.Context, u *User) (err error) {
}
// ***** END: ExternalLoginUser *****
- if _, err = e.ID(u.ID).Delete(new(User)); err != nil {
+ if _, err = e.ID(u.ID).Delete(new(user_model.User)); err != nil {
return fmt.Errorf("Delete: %v", err)
}
return nil
}
-// GetInactiveUsers gets all inactive users
-func GetInactiveUsers(ctx context.Context, olderThan time.Duration) ([]*User, error) {
- var cond builder.Cond = builder.Eq{"is_active": false}
-
- if olderThan > 0 {
- cond = cond.And(builder.Lt{"created_unix": time.Now().Add(-olderThan).Unix()})
- }
-
- users := make([]*User, 0, 10)
- return users, db.GetEngine(ctx).
- Where(cond).
- Find(&users)
-}
-
-// UserPath returns the path absolute path of user repositories.
-func UserPath(userName string) string {
- return filepath.Join(setting.RepoRootPath, strings.ToLower(userName))
-}
-
-func getUserByID(e db.Engine, id int64) (*User, error) {
- u := new(User)
- has, err := e.ID(id).Get(u)
- if err != nil {
- return nil, err
- } else if !has {
- return nil, ErrUserNotExist{id, "", 0}
- }
- return u, nil
-}
-
-// GetUserByID returns the user object by given ID if exists.
-func GetUserByID(id int64) (*User, error) {
- return GetUserByIDCtx(db.DefaultContext, id)
-}
-
-// GetUserByIDCtx returns the user object by given ID if exists.
-func GetUserByIDCtx(ctx context.Context, id int64) (*User, error) {
- return getUserByID(db.GetEngine(ctx), id)
-}
-
-// GetUserByName returns user by given name.
-func GetUserByName(name string) (*User, error) {
- return getUserByName(db.GetEngine(db.DefaultContext), name)
-}
-
-func getUserByName(e db.Engine, name string) (*User, error) {
- if len(name) == 0 {
- return nil, ErrUserNotExist{0, name, 0}
- }
- u := &User{LowerName: strings.ToLower(name)}
- has, err := e.Get(u)
- if err != nil {
- return nil, err
- } else if !has {
- return nil, ErrUserNotExist{0, name, 0}
- }
- return u, nil
-}
-
-// GetUserEmailsByNames returns a list of e-mails corresponds to names of users
-// that have their email notifications set to enabled or onmention.
-func GetUserEmailsByNames(names []string) []string {
- return getUserEmailsByNames(db.GetEngine(db.DefaultContext), names)
-}
-
-func getUserEmailsByNames(e db.Engine, names []string) []string {
- mails := make([]string, 0, len(names))
- for _, name := range names {
- u, err := getUserByName(e, name)
- if err != nil {
- continue
- }
- if u.IsMailable() && u.EmailNotifications() != EmailNotificationsDisabled {
- mails = append(mails, u.Email)
- }
- }
- return mails
-}
-
-// GetMaileableUsersByIDs gets users from ids, but only if they can receive mails
-func GetMaileableUsersByIDs(ids []int64, isMention bool) ([]*User, error) {
- if len(ids) == 0 {
- return nil, nil
- }
- ous := make([]*User, 0, len(ids))
-
- if isMention {
- return ous, db.GetEngine(db.DefaultContext).In("id", ids).
- Where("`type` = ?", UserTypeIndividual).
- And("`prohibit_login` = ?", false).
- And("`is_active` = ?", true).
- And("`email_notifications_preference` IN ( ?, ?)", EmailNotificationsEnabled, EmailNotificationsOnMention).
- Find(&ous)
- }
-
- return ous, db.GetEngine(db.DefaultContext).In("id", ids).
- Where("`type` = ?", UserTypeIndividual).
- And("`prohibit_login` = ?", false).
- And("`is_active` = ?", true).
- And("`email_notifications_preference` = ?", EmailNotificationsEnabled).
- Find(&ous)
-}
-
-// GetUserNamesByIDs returns usernames for all resolved users from a list of Ids.
-func GetUserNamesByIDs(ids []int64) ([]string, error) {
- unames := make([]string, 0, len(ids))
- err := db.GetEngine(db.DefaultContext).In("id", ids).
- Table("user").
- Asc("name").
- Cols("name").
- Find(&unames)
- return unames, err
-}
-
-// GetUsersByIDs returns all resolved users from a list of Ids.
-func GetUsersByIDs(ids []int64) (UserList, error) {
- ous := make([]*User, 0, len(ids))
- if len(ids) == 0 {
- return ous, nil
- }
- err := db.GetEngine(db.DefaultContext).In("id", ids).
- Asc("name").
- Find(&ous)
- return ous, err
-}
-
-// GetUserIDsByNames returns a slice of ids corresponds to names.
-func GetUserIDsByNames(names []string, ignoreNonExistent bool) ([]int64, error) {
- ids := make([]int64, 0, len(names))
- for _, name := range names {
- u, err := GetUserByName(name)
- if err != nil {
- if ignoreNonExistent {
- continue
- } else {
- return nil, err
- }
- }
- ids = append(ids, u.ID)
- }
- return ids, nil
-}
-
-// GetUsersBySource returns a list of Users for a login source
-func GetUsersBySource(s *login.Source) ([]*User, error) {
- var users []*User
- err := db.GetEngine(db.DefaultContext).Where("login_type = ? AND login_source = ?", s.Type, s.ID).Find(&users)
- return users, err
-}
-
-// UserCommit represents a commit with validation of user.
-type UserCommit struct {
- User *User
- *git.Commit
-}
-
-// ValidateCommitWithEmail check if author's e-mail of commit is corresponding to a user.
-func ValidateCommitWithEmail(c *git.Commit) *User {
- if c.Author == nil {
- return nil
- }
- u, err := GetUserByEmail(c.Author.Email)
- if err != nil {
- return nil
- }
- return u
-}
-
-// ValidateCommitsWithEmails checks if authors' e-mails of commits are corresponding to users.
-func ValidateCommitsWithEmails(oldCommits []*git.Commit) []*UserCommit {
- var (
- emails = make(map[string]*User)
- newCommits = make([]*UserCommit, 0, len(oldCommits))
- )
- for _, c := range oldCommits {
- var u *User
- if c.Author != nil {
- if v, ok := emails[c.Author.Email]; !ok {
- u, _ = GetUserByEmail(c.Author.Email)
- emails[c.Author.Email] = u
- } else {
- u = v
- }
- }
-
- newCommits = append(newCommits, &UserCommit{
- User: u,
- Commit: c,
- })
- }
- return newCommits
-}
-
-// GetUserByEmail returns the user object by given e-mail if exists.
-func GetUserByEmail(email string) (*User, error) {
- return GetUserByEmailContext(db.DefaultContext, email)
-}
-
-// GetUserByEmailContext returns the user object by given e-mail if exists with db context
-func GetUserByEmailContext(ctx context.Context, email string) (*User, error) {
- if len(email) == 0 {
- return nil, ErrUserNotExist{0, email, 0}
- }
-
- email = strings.ToLower(email)
- // First try to find the user by primary email
- user := &User{Email: email}
- has, err := db.GetEngine(ctx).Get(user)
- if err != nil {
- return nil, err
- }
- if has {
- return user, nil
- }
-
- // Otherwise, check in alternative list for activated email addresses
- emailAddress := &user_model.EmailAddress{Email: email, IsActivated: true}
- has, err = db.GetEngine(ctx).Get(emailAddress)
- if err != nil {
- return nil, err
- }
- if has {
- return GetUserByIDCtx(ctx, emailAddress.UID)
- }
-
- // Finally, if email address is the protected email address:
- if strings.HasSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) {
- username := strings.TrimSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress))
- user := &User{}
- has, err := db.GetEngine(ctx).Where("lower_name=?", username).Get(user)
- if err != nil {
- return nil, err
- }
- if has {
- return user, nil
- }
- }
-
- return nil, ErrUserNotExist{0, email, 0}
-}
-
-// GetUser checks if a user already exists
-func GetUser(user *User) (bool, error) {
- return db.GetEngine(db.DefaultContext).Get(user)
-}
-
-// SearchUserOptions contains the options for searching
-type SearchUserOptions struct {
- db.ListOptions
- Keyword string
- Type UserType
- UID int64
- OrderBy SearchOrderBy
- Visible []structs.VisibleType
- Actor *User // The user doing the search
- SearchByEmail bool // Search by email as well as username/full name
-
- IsActive util.OptionalBool
- IsAdmin util.OptionalBool
- IsRestricted util.OptionalBool
- IsTwoFactorEnabled util.OptionalBool
- IsProhibitLogin util.OptionalBool
-}
-
-func (opts *SearchUserOptions) toSearchQueryBase() *xorm.Session {
- var cond builder.Cond = builder.Eq{"type": opts.Type}
- if len(opts.Keyword) > 0 {
- lowerKeyword := strings.ToLower(opts.Keyword)
- keywordCond := builder.Or(
- builder.Like{"lower_name", lowerKeyword},
- builder.Like{"LOWER(full_name)", lowerKeyword},
- )
- if opts.SearchByEmail {
- keywordCond = keywordCond.Or(builder.Like{"LOWER(email)", lowerKeyword})
- }
-
- cond = cond.And(keywordCond)
- }
-
- // If visibility filtered
- if len(opts.Visible) > 0 {
- cond = cond.And(builder.In("visibility", opts.Visible))
- }
-
- if opts.Actor != nil {
- var exprCond builder.Cond = builder.Expr("org_user.org_id = `user`.id")
-
- // If Admin - they see all users!
- if !opts.Actor.IsAdmin {
- // Force visibility for privacy
- var accessCond builder.Cond
- if !opts.Actor.IsRestricted {
- accessCond = builder.Or(
- builder.In("id", builder.Select("org_id").From("org_user").LeftJoin("`user`", exprCond).Where(builder.And(builder.Eq{"uid": opts.Actor.ID}, builder.Eq{"visibility": structs.VisibleTypePrivate}))),
- builder.In("visibility", structs.VisibleTypePublic, structs.VisibleTypeLimited))
- } else {
- // restricted users only see orgs they are a member of
- accessCond = builder.In("id", builder.Select("org_id").From("org_user").LeftJoin("`user`", exprCond).Where(builder.And(builder.Eq{"uid": opts.Actor.ID})))
- }
- // Don't forget about self
- accessCond = accessCond.Or(builder.Eq{"id": opts.Actor.ID})
- cond = cond.And(accessCond)
- }
-
- } else {
- // Force visibility for privacy
- // Not logged in - only public users
- cond = cond.And(builder.In("visibility", structs.VisibleTypePublic))
- }
-
- if opts.UID > 0 {
- cond = cond.And(builder.Eq{"id": opts.UID})
- }
-
- if !opts.IsActive.IsNone() {
- cond = cond.And(builder.Eq{"is_active": opts.IsActive.IsTrue()})
- }
-
- if !opts.IsAdmin.IsNone() {
- cond = cond.And(builder.Eq{"is_admin": opts.IsAdmin.IsTrue()})
- }
-
- if !opts.IsRestricted.IsNone() {
- cond = cond.And(builder.Eq{"is_restricted": opts.IsRestricted.IsTrue()})
- }
-
- if !opts.IsProhibitLogin.IsNone() {
- cond = cond.And(builder.Eq{"prohibit_login": opts.IsProhibitLogin.IsTrue()})
- }
-
- e := db.GetEngine(db.DefaultContext)
- if opts.IsTwoFactorEnabled.IsNone() {
- return e.Where(cond)
- }
-
- // 2fa filter uses LEFT JOIN to check whether a user has a 2fa record
- // TODO: bad performance here, maybe there will be a column "is_2fa_enabled" in the future
- if opts.IsTwoFactorEnabled.IsTrue() {
- cond = cond.And(builder.Expr("two_factor.uid IS NOT NULL"))
- } else {
- cond = cond.And(builder.Expr("two_factor.uid IS NULL"))
- }
-
- return e.Join("LEFT OUTER", "two_factor", "two_factor.uid = `user`.id").
- Where(cond)
-}
-
-// SearchUsers takes options i.e. keyword and part of user name to search,
-// it returns results in given range and number of total results.
-func SearchUsers(opts *SearchUserOptions) (users []*User, _ int64, _ error) {
- sessCount := opts.toSearchQueryBase()
- defer sessCount.Close()
- count, err := sessCount.Count(new(User))
- if err != nil {
- return nil, 0, fmt.Errorf("Count: %v", err)
- }
-
- if len(opts.OrderBy) == 0 {
- opts.OrderBy = SearchOrderByAlphabetically
- }
-
- sessQuery := opts.toSearchQueryBase().OrderBy(opts.OrderBy.String())
- defer sessQuery.Close()
- if opts.Page != 0 {
- sessQuery = db.SetSessionPagination(sessQuery, opts)
- }
-
- // the sql may contain JOIN, so we must only select User related columns
- sessQuery = sessQuery.Select("`user`.*")
- users = make([]*User, 0, opts.PageSize)
- return users, count, sessQuery.Find(&users)
-}
-
// GetStarredRepos returns the repos starred by a particular user
func GetStarredRepos(userID int64, private bool, listOptions db.ListOptions) ([]*Repository, error) {
sess := db.GetEngine(db.DefaultContext).Where("star.uid=?", userID).
@@ -1604,63 +313,58 @@ func GetWatchedRepos(userID int64, private bool, listOptions db.ListOptions) ([]
return repos, total, err
}
-// IterateUser iterate users
-func IterateUser(f func(user *User) error) error {
- var start int
- batchSize := setting.Database.IterateBufferSize
- for {
- users := make([]*User, 0, batchSize)
- if err := db.GetEngine(db.DefaultContext).Limit(batchSize, start).Find(&users); err != nil {
- return err
- }
- if len(users) == 0 {
- return nil
- }
- start += len(users)
-
- for _, user := range users {
- if err := f(user); err != nil {
- return err
- }
- }
- }
+// IsUserVisibleToViewer check if viewer is able to see user profile
+func IsUserVisibleToViewer(u *user_model.User, viewer *user_model.User) bool {
+ return isUserVisibleToViewer(db.GetEngine(db.DefaultContext), u, viewer)
}
-// GetUserByOpenID returns the user object by given OpenID if exists.
-func GetUserByOpenID(uri string) (*User, error) {
- if len(uri) == 0 {
- return nil, ErrUserNotExist{0, uri, 0}
+func isUserVisibleToViewer(e db.Engine, u *user_model.User, viewer *user_model.User) bool {
+ if viewer != nil && viewer.IsAdmin {
+ return true
}
- uri, err := openid.Normalize(uri)
- if err != nil {
- return nil, err
- }
+ switch u.Visibility {
+ case structs.VisibleTypePublic:
+ return true
+ case structs.VisibleTypeLimited:
+ if viewer == nil || viewer.IsRestricted {
+ return false
+ }
+ return true
+ case structs.VisibleTypePrivate:
+ if viewer == nil || viewer.IsRestricted {
+ return false
+ }
- log.Trace("Normalized OpenID URI: " + uri)
+ // If they follow - they see each over
+ follower := user_model.IsFollowing(u.ID, viewer.ID)
+ if follower {
+ return true
+ }
- // Otherwise, check in openid table
- oid := &user_model.UserOpenID{}
- has, err := db.GetEngine(db.DefaultContext).Where("uri=?", uri).Get(oid)
- if err != nil {
- return nil, err
- }
- if has {
- return GetUserByID(oid.UID)
- }
+ // Now we need to check if they in some organization together
+ count, err := e.Table("team_user").
+ Where(
+ builder.And(
+ builder.Eq{"uid": viewer.ID},
+ builder.Or(
+ builder.Eq{"org_id": u.ID},
+ builder.In("org_id",
+ builder.Select("org_id").
+ From("team_user", "t2").
+ Where(builder.Eq{"uid": u.ID}))))).
+ Count(new(TeamUser))
+ if err != nil {
+ return false
+ }
- return nil, ErrUserNotExist{0, uri, 0}
-}
+ if count < 0 {
+ // No common organization
+ return false
+ }
-// GetAdminUser returns the first administrator
-func GetAdminUser() (*User, error) {
- var admin User
- has, err := db.GetEngine(db.DefaultContext).Where("is_admin=?", true).Get(&admin)
- if err != nil {
- return nil, err
- } else if !has {
- return nil, ErrUserNotExist{}
+ // they are in an organization together
+ return true
}
-
- return &admin, nil
+ return false
}
diff --git a/models/user_avatar.go b/models/user/avatar.go
index ae4cd1e5ec..c881642b56 100644
--- a/models/user_avatar.go
+++ b/models/user/avatar.go
@@ -2,9 +2,10 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
-package models
+package user
import (
+ "context"
"crypto/md5"
"fmt"
"image/png"
@@ -26,10 +27,11 @@ func (u *User) CustomAvatarRelativePath() string {
// GenerateRandomAvatar generates a random avatar for user.
func GenerateRandomAvatar(u *User) error {
- return generateRandomAvatar(db.GetEngine(db.DefaultContext), u)
+ return GenerateRandomAvatarCtx(db.DefaultContext, u)
}
-func generateRandomAvatar(e db.Engine, u *User) error {
+// GenerateRandomAvatarCtx generates a random avatar for user.
+func GenerateRandomAvatarCtx(ctx context.Context, u *User) error {
seed := u.Email
if len(seed) == 0 {
seed = u.Name
@@ -52,7 +54,7 @@ func generateRandomAvatar(e db.Engine, u *User) error {
return fmt.Errorf("Failed to create dir %s: %v", u.CustomAvatarRelativePath(), err)
}
- if _, err := e.ID(u.ID).Cols("avatar").Update(u); err != nil {
+ if _, err := db.GetEngine(ctx).ID(u.ID).Cols("avatar").Update(u); err != nil {
return err
}
diff --git a/models/user/error.go b/models/user/error.go
new file mode 100644
index 0000000000..25e0d8ea8a
--- /dev/null
+++ b/models/user/error.go
@@ -0,0 +1,80 @@
+// Copyright 2021 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package user
+
+import (
+ "fmt"
+)
+
+// ____ ___
+// | | \______ ___________
+// | | / ___// __ \_ __ \
+// | | /\___ \\ ___/| | \/
+// |______//____ >\___ >__|
+// \/ \/
+
+// ErrUserAlreadyExist represents a "user already exists" error.
+type ErrUserAlreadyExist struct {
+ Name string
+}
+
+// IsErrUserAlreadyExist checks if an error is a ErrUserAlreadyExists.
+func IsErrUserAlreadyExist(err error) bool {
+ _, ok := err.(ErrUserAlreadyExist)
+ return ok
+}
+
+func (err ErrUserAlreadyExist) Error() string {
+ return fmt.Sprintf("user already exists [name: %s]", err.Name)
+}
+
+// ErrUserNotExist represents a "UserNotExist" kind of error.
+type ErrUserNotExist struct {
+ UID int64
+ Name string
+ KeyID int64
+}
+
+// IsErrUserNotExist checks if an error is a ErrUserNotExist.
+func IsErrUserNotExist(err error) bool {
+ _, ok := err.(ErrUserNotExist)
+ return ok
+}
+
+func (err ErrUserNotExist) Error() string {
+ return fmt.Sprintf("user does not exist [uid: %d, name: %s, keyid: %d]", err.UID, err.Name, err.KeyID)
+}
+
+// ErrUserProhibitLogin represents a "ErrUserProhibitLogin" kind of error.
+type ErrUserProhibitLogin struct {
+ UID int64
+ Name string
+}
+
+// IsErrUserProhibitLogin checks if an error is a ErrUserProhibitLogin
+func IsErrUserProhibitLogin(err error) bool {
+ _, ok := err.(ErrUserProhibitLogin)
+ return ok
+}
+
+func (err ErrUserProhibitLogin) Error() string {
+ return fmt.Sprintf("user is not allowed login [uid: %d, name: %s]", err.UID, err.Name)
+}
+
+// ErrUserInactive represents a "ErrUserInactive" kind of error.
+type ErrUserInactive struct {
+ UID int64
+ Name string
+}
+
+// IsErrUserInactive checks if an error is a ErrUserInactive
+func IsErrUserInactive(err error) bool {
+ _, ok := err.(ErrUserInactive)
+ return ok
+}
+
+func (err ErrUserInactive) Error() string {
+ return fmt.Sprintf("user is inactive [uid: %d, name: %s]", err.UID, err.Name)
+}
diff --git a/models/user/main_test.go b/models/user/main_test.go
index 925af0e8b2..55e5f9341c 100644
--- a/models/user/main_test.go
+++ b/models/user/main_test.go
@@ -17,5 +17,8 @@ func TestMain(m *testing.M) {
"user_redirect.yml",
"follow.yml",
"user_open_id.yml",
+ "two_factor.yml",
+ "oauth2_application.yml",
+ "user.yml",
)
}
diff --git a/models/user/search.go b/models/user/search.go
new file mode 100644
index 0000000000..5c37bb9961
--- /dev/null
+++ b/models/user/search.go
@@ -0,0 +1,167 @@
+// Copyright 2021 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package user
+
+import (
+ "fmt"
+ "strings"
+
+ "code.gitea.io/gitea/models/db"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/util"
+
+ "xorm.io/builder"
+ "xorm.io/xorm"
+)
+
+// SearchUserOptions contains the options for searching
+type SearchUserOptions struct {
+ db.ListOptions
+ Keyword string
+ Type UserType
+ UID int64
+ OrderBy db.SearchOrderBy
+ Visible []structs.VisibleType
+ Actor *User // The user doing the search
+ SearchByEmail bool // Search by email as well as username/full name
+
+ IsActive util.OptionalBool
+ IsAdmin util.OptionalBool
+ IsRestricted util.OptionalBool
+ IsTwoFactorEnabled util.OptionalBool
+ IsProhibitLogin util.OptionalBool
+}
+
+func (opts *SearchUserOptions) toSearchQueryBase() *xorm.Session {
+ var cond builder.Cond = builder.Eq{"type": opts.Type}
+ if len(opts.Keyword) > 0 {
+ lowerKeyword := strings.ToLower(opts.Keyword)
+ keywordCond := builder.Or(
+ builder.Like{"lower_name", lowerKeyword},
+ builder.Like{"LOWER(full_name)", lowerKeyword},
+ )
+ if opts.SearchByEmail {
+ keywordCond = keywordCond.Or(builder.Like{"LOWER(email)", lowerKeyword})
+ }
+
+ cond = cond.And(keywordCond)
+ }
+
+ // If visibility filtered
+ if len(opts.Visible) > 0 {
+ cond = cond.And(builder.In("visibility", opts.Visible))
+ }
+
+ if opts.Actor != nil {
+ var exprCond builder.Cond = builder.Expr("org_user.org_id = `user`.id")
+
+ // If Admin - they see all users!
+ if !opts.Actor.IsAdmin {
+ // Force visibility for privacy
+ var accessCond builder.Cond
+ if !opts.Actor.IsRestricted {
+ accessCond = builder.Or(
+ builder.In("id", builder.Select("org_id").From("org_user").LeftJoin("`user`", exprCond).Where(builder.And(builder.Eq{"uid": opts.Actor.ID}, builder.Eq{"visibility": structs.VisibleTypePrivate}))),
+ builder.In("visibility", structs.VisibleTypePublic, structs.VisibleTypeLimited))
+ } else {
+ // restricted users only see orgs they are a member of
+ accessCond = builder.In("id", builder.Select("org_id").From("org_user").LeftJoin("`user`", exprCond).Where(builder.And(builder.Eq{"uid": opts.Actor.ID})))
+ }
+ // Don't forget about self
+ accessCond = accessCond.Or(builder.Eq{"id": opts.Actor.ID})
+ cond = cond.And(accessCond)
+ }
+
+ } else {
+ // Force visibility for privacy
+ // Not logged in - only public users
+ cond = cond.And(builder.In("visibility", structs.VisibleTypePublic))
+ }
+
+ if opts.UID > 0 {
+ cond = cond.And(builder.Eq{"id": opts.UID})
+ }
+
+ if !opts.IsActive.IsNone() {
+ cond = cond.And(builder.Eq{"is_active": opts.IsActive.IsTrue()})
+ }
+
+ if !opts.IsAdmin.IsNone() {
+ cond = cond.And(builder.Eq{"is_admin": opts.IsAdmin.IsTrue()})
+ }
+
+ if !opts.IsRestricted.IsNone() {
+ cond = cond.And(builder.Eq{"is_restricted": opts.IsRestricted.IsTrue()})
+ }
+
+ if !opts.IsProhibitLogin.IsNone() {
+ cond = cond.And(builder.Eq{"prohibit_login": opts.IsProhibitLogin.IsTrue()})
+ }
+
+ e := db.GetEngine(db.DefaultContext)
+ if opts.IsTwoFactorEnabled.IsNone() {
+ return e.Where(cond)
+ }
+
+ // 2fa filter uses LEFT JOIN to check whether a user has a 2fa record
+ // TODO: bad performance here, maybe there will be a column "is_2fa_enabled" in the future
+ if opts.IsTwoFactorEnabled.IsTrue() {
+ cond = cond.And(builder.Expr("two_factor.uid IS NOT NULL"))
+ } else {
+ cond = cond.And(builder.Expr("two_factor.uid IS NULL"))
+ }
+
+ return e.Join("LEFT OUTER", "two_factor", "two_factor.uid = `user`.id").
+ Where(cond)
+}
+
+// SearchUsers takes options i.e. keyword and part of user name to search,
+// it returns results in given range and number of total results.
+func SearchUsers(opts *SearchUserOptions) (users []*User, _ int64, _ error) {
+ sessCount := opts.toSearchQueryBase()
+ defer sessCount.Close()
+ count, err := sessCount.Count(new(User))
+ if err != nil {
+ return nil, 0, fmt.Errorf("Count: %v", err)
+ }
+
+ if len(opts.OrderBy) == 0 {
+ opts.OrderBy = db.SearchOrderByAlphabetically
+ }
+
+ sessQuery := opts.toSearchQueryBase().OrderBy(opts.OrderBy.String())
+ defer sessQuery.Close()
+ if opts.Page != 0 {
+ sessQuery = db.SetSessionPagination(sessQuery, opts)
+ }
+
+ // the sql may contain JOIN, so we must only select User related columns
+ sessQuery = sessQuery.Select("`user`.*")
+ users = make([]*User, 0, opts.PageSize)
+ return users, count, sessQuery.Find(&users)
+}
+
+// IterateUser iterate users
+func IterateUser(f func(user *User) error) error {
+ var start int
+ batchSize := setting.Database.IterateBufferSize
+ for {
+ users := make([]*User, 0, batchSize)
+ if err := db.GetEngine(db.DefaultContext).Limit(batchSize, start).Find(&users); err != nil {
+ return err
+ }
+ if len(users) == 0 {
+ return nil
+ }
+ start += len(users)
+
+ for _, user := range users {
+ if err := f(user); err != nil {
+ return err
+ }
+ }
+ }
+}
diff --git a/models/user/user.go b/models/user/user.go
new file mode 100644
index 0000000000..f8ccee0b38
--- /dev/null
+++ b/models/user/user.go
@@ -0,0 +1,1125 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Copyright 2019 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package user
+
+import (
+ "context"
+ "crypto/sha256"
+ "crypto/subtle"
+ "encoding/hex"
+ "errors"
+ "fmt"
+ "net/url"
+ "os"
+ "path/filepath"
+ "strings"
+ "time"
+
+ _ "image/jpeg" // Needed for jpeg support
+
+ "code.gitea.io/gitea/models/db"
+ "code.gitea.io/gitea/models/login"
+ "code.gitea.io/gitea/modules/auth/openid"
+ "code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/timeutil"
+ "code.gitea.io/gitea/modules/util"
+
+ "golang.org/x/crypto/argon2"
+ "golang.org/x/crypto/bcrypt"
+ "golang.org/x/crypto/pbkdf2"
+ "golang.org/x/crypto/scrypt"
+ "xorm.io/builder"
+)
+
+// UserType defines the user type
+type UserType int //revive:disable-line:exported
+
+const (
+ // UserTypeIndividual defines an individual user
+ UserTypeIndividual UserType = iota // Historic reason to make it starts at 0.
+
+ // UserTypeOrganization defines an organization
+ UserTypeOrganization
+)
+
+const (
+ algoBcrypt = "bcrypt"
+ algoScrypt = "scrypt"
+ algoArgon2 = "argon2"
+ algoPbkdf2 = "pbkdf2"
+)
+
+// AvailableHashAlgorithms represents the available password hashing algorithms
+var AvailableHashAlgorithms = []string{
+ algoPbkdf2,
+ algoArgon2,
+ algoScrypt,
+ algoBcrypt,
+}
+
+const (
+ // EmailNotificationsEnabled indicates that the user would like to receive all email notifications
+ EmailNotificationsEnabled = "enabled"
+ // EmailNotificationsOnMention indicates that the user would like to be notified via email when mentioned.
+ EmailNotificationsOnMention = "onmention"
+ // EmailNotificationsDisabled indicates that the user would not like to be notified via email.
+ EmailNotificationsDisabled = "disabled"
+)
+
+var (
+ // ErrUserNameIllegal user name contains illegal characters error
+ ErrUserNameIllegal = errors.New("User name contains illegal characters")
+)
+
+// User represents the object of individual and member of organization.
+type User struct {
+ ID int64 `xorm:"pk autoincr"`
+ LowerName string `xorm:"UNIQUE NOT NULL"`
+ Name string `xorm:"UNIQUE NOT NULL"`
+ FullName string
+ // Email is the primary email address (to be used for communication)
+ Email string `xorm:"NOT NULL"`
+ KeepEmailPrivate bool
+ EmailNotificationsPreference string `xorm:"VARCHAR(20) NOT NULL DEFAULT 'enabled'"`
+ Passwd string `xorm:"NOT NULL"`
+ PasswdHashAlgo string `xorm:"NOT NULL DEFAULT 'argon2'"`
+
+ // MustChangePassword is an attribute that determines if a user
+ // is to change his/her password after registration.
+ MustChangePassword bool `xorm:"NOT NULL DEFAULT false"`
+
+ LoginType login.Type
+ LoginSource int64 `xorm:"NOT NULL DEFAULT 0"`
+ LoginName string
+ Type UserType
+ Location string
+ Website string
+ Rands string `xorm:"VARCHAR(10)"`
+ Salt string `xorm:"VARCHAR(10)"`
+ Language string `xorm:"VARCHAR(5)"`
+ Description string
+
+ CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
+ UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
+ LastLoginUnix timeutil.TimeStamp `xorm:"INDEX"`
+
+ // Remember visibility choice for convenience, true for private
+ LastRepoVisibility bool
+ // Maximum repository creation limit, -1 means use global default
+ MaxRepoCreation int `xorm:"NOT NULL DEFAULT -1"`
+
+ // IsActive true: primary email is activated, user can access Web UI and Git SSH.
+ // false: an inactive user can only log in Web UI for account operations (ex: activate the account by email), no other access.
+ IsActive bool `xorm:"INDEX"`
+ // the user is a Gitea admin, who can access all repositories and the admin pages.
+ IsAdmin bool
+ // true: the user is only allowed to see organizations/repositories that they has explicit rights to.
+ // (ex: in private Gitea instances user won't be allowed to see even organizations/repositories that are set as public)
+ IsRestricted bool `xorm:"NOT NULL DEFAULT false"`
+
+ AllowGitHook bool
+ AllowImportLocal bool // Allow migrate repository by local path
+ AllowCreateOrganization bool `xorm:"DEFAULT true"`
+
+ // true: the user is not allowed to log in Web UI. Git/SSH access could still be allowed (please refer to Git/SSH access related code/documents)
+ ProhibitLogin bool `xorm:"NOT NULL DEFAULT false"`
+
+ // Avatar
+ Avatar string `xorm:"VARCHAR(2048) NOT NULL"`
+ AvatarEmail string `xorm:"NOT NULL"`
+ UseCustomAvatar bool
+
+ // Counters
+ NumFollowers int
+ NumFollowing int `xorm:"NOT NULL DEFAULT 0"`
+ NumStars int
+ NumRepos int
+
+ // For organization
+ NumTeams int
+ NumMembers int
+ Visibility structs.VisibleType `xorm:"NOT NULL DEFAULT 0"`
+ RepoAdminChangeTeamAccess bool `xorm:"NOT NULL DEFAULT false"`
+
+ // Preferences
+ DiffViewStyle string `xorm:"NOT NULL DEFAULT ''"`
+ Theme string `xorm:"NOT NULL DEFAULT ''"`
+ KeepActivityPrivate bool `xorm:"NOT NULL DEFAULT false"`
+}
+
+func init() {
+ db.RegisterModel(new(User))
+}
+
+// SearchOrganizationsOptions options to filter organizations
+type SearchOrganizationsOptions struct {
+ db.ListOptions
+ All bool
+}
+
+// ColorFormat writes a colored string to identify this struct
+func (u *User) ColorFormat(s fmt.State) {
+ log.ColorFprintf(s, "%d:%s",
+ log.NewColoredIDValue(u.ID),
+ log.NewColoredValue(u.Name))
+}
+
+// BeforeUpdate is invoked from XORM before updating this object.
+func (u *User) BeforeUpdate() {
+ if u.MaxRepoCreation < -1 {
+ u.MaxRepoCreation = -1
+ }
+
+ // Organization does not need email
+ u.Email = strings.ToLower(u.Email)
+ if !u.IsOrganization() {
+ if len(u.AvatarEmail) == 0 {
+ u.AvatarEmail = u.Email
+ }
+ }
+
+ u.LowerName = strings.ToLower(u.Name)
+ u.Location = base.TruncateString(u.Location, 255)
+ u.Website = base.TruncateString(u.Website, 255)
+ u.Description = base.TruncateString(u.Description, 255)
+}
+
+// AfterLoad is invoked from XORM after filling all the fields of this object.
+func (u *User) AfterLoad() {
+ if u.Theme == "" {
+ u.Theme = setting.UI.DefaultTheme
+ }
+}
+
+// SetLastLogin set time to last login
+func (u *User) SetLastLogin() {
+ u.LastLoginUnix = timeutil.TimeStampNow()
+}
+
+// UpdateUserDiffViewStyle updates the users diff view style
+func UpdateUserDiffViewStyle(u *User, style string) error {
+ u.DiffViewStyle = style
+ return UpdateUserCols(db.DefaultContext, u, "diff_view_style")
+}
+
+// UpdateUserTheme updates a users' theme irrespective of the site wide theme
+func UpdateUserTheme(u *User, themeName string) error {
+ u.Theme = themeName
+ return UpdateUserCols(db.DefaultContext, u, "theme")
+}
+
+// GetEmail returns an noreply email, if the user has set to keep his
+// email address private, otherwise the primary email address.
+func (u *User) GetEmail() string {
+ if u.KeepEmailPrivate {
+ return fmt.Sprintf("%s@%s", u.LowerName, setting.Service.NoReplyAddress)
+ }
+ return u.Email
+}
+
+// GetAllUsers returns a slice of all individual users found in DB.
+func GetAllUsers() ([]*User, error) {
+ users := make([]*User, 0)
+ return users, db.GetEngine(db.DefaultContext).OrderBy("id").Where("type = ?", UserTypeIndividual).Find(&users)
+}
+
+// IsLocal returns true if user login type is LoginPlain.
+func (u *User) IsLocal() bool {
+ return u.LoginType <= login.Plain
+}
+
+// IsOAuth2 returns true if user login type is LoginOAuth2.
+func (u *User) IsOAuth2() bool {
+ return u.LoginType == login.OAuth2
+}
+
+// MaxCreationLimit returns the number of repositories a user is allowed to create
+func (u *User) MaxCreationLimit() int {
+ if u.MaxRepoCreation <= -1 {
+ return setting.Repository.MaxCreationLimit
+ }
+ return u.MaxRepoCreation
+}
+
+// CanCreateRepo returns if user login can create a repository
+// NOTE: functions calling this assume a failure due to repository count limit; if new checks are added, those functions should be revised
+func (u *User) CanCreateRepo() bool {
+ if u.IsAdmin {
+ return true
+ }
+ if u.MaxRepoCreation <= -1 {
+ if setting.Repository.MaxCreationLimit <= -1 {
+ return true
+ }
+ return u.NumRepos < setting.Repository.MaxCreationLimit
+ }
+ return u.NumRepos < u.MaxRepoCreation
+}
+
+// CanCreateOrganization returns true if user can create organisation.
+func (u *User) CanCreateOrganization() bool {
+ return u.IsAdmin || (u.AllowCreateOrganization && !setting.Admin.DisableRegularOrgCreation)
+}
+
+// CanEditGitHook returns true if user can edit Git hooks.
+func (u *User) CanEditGitHook() bool {
+ return !setting.DisableGitHooks && (u.IsAdmin || u.AllowGitHook)
+}
+
+// CanImportLocal returns true if user can migrate repository by local path.
+func (u *User) CanImportLocal() bool {
+ if !setting.ImportLocalPaths || u == nil {
+ return false
+ }
+ return u.IsAdmin || u.AllowImportLocal
+}
+
+// DashboardLink returns the user dashboard page link.
+func (u *User) DashboardLink() string {
+ if u.IsOrganization() {
+ return u.OrganisationLink() + "/dashboard"
+ }
+ return setting.AppSubURL + "/"
+}
+
+// HomeLink returns the user or organization home page link.
+func (u *User) HomeLink() string {
+ return setting.AppSubURL + "/" + url.PathEscape(u.Name)
+}
+
+// HTMLURL returns the user or organization's full link.
+func (u *User) HTMLURL() string {
+ return setting.AppURL + url.PathEscape(u.Name)
+}
+
+// OrganisationLink returns the organization sub page link.
+func (u *User) OrganisationLink() string {
+ return setting.AppSubURL + "/org/" + url.PathEscape(u.Name)
+}
+
+// GenerateEmailActivateCode generates an activate code based on user information and given e-mail.
+func (u *User) GenerateEmailActivateCode(email string) string {
+ code := base.CreateTimeLimitCode(
+ fmt.Sprintf("%d%s%s%s%s", u.ID, email, u.LowerName, u.Passwd, u.Rands),
+ setting.Service.ActiveCodeLives, nil)
+
+ // Add tail hex username
+ code += hex.EncodeToString([]byte(u.LowerName))
+ return code
+}
+
+// GetUserFollowers returns range of user's followers.
+func GetUserFollowers(u *User, listOptions db.ListOptions) ([]*User, error) {
+ sess := db.GetEngine(db.DefaultContext).
+ Where("follow.follow_id=?", u.ID).
+ Join("LEFT", "follow", "`user`.id=follow.user_id")
+
+ if listOptions.Page != 0 {
+ sess = db.SetSessionPagination(sess, &listOptions)
+
+ users := make([]*User, 0, listOptions.PageSize)
+ return users, sess.Find(&users)
+ }
+
+ users := make([]*User, 0, 8)
+ return users, sess.Find(&users)
+}
+
+// GetUserFollowing returns range of user's following.
+func GetUserFollowing(u *User, listOptions db.ListOptions) ([]*User, error) {
+ sess := db.GetEngine(db.DefaultContext).
+ Where("follow.user_id=?", u.ID).
+ Join("LEFT", "follow", "`user`.id=follow.follow_id")
+
+ if listOptions.Page != 0 {
+ sess = db.SetSessionPagination(sess, &listOptions)
+
+ users := make([]*User, 0, listOptions.PageSize)
+ return users, sess.Find(&users)
+ }
+
+ users := make([]*User, 0, 8)
+ return users, sess.Find(&users)
+}
+
+// NewGitSig generates and returns the signature of given user.
+func (u *User) NewGitSig() *git.Signature {
+ return &git.Signature{
+ Name: u.GitName(),
+ Email: u.GetEmail(),
+ When: time.Now(),
+ }
+}
+
+func hashPassword(passwd, salt, algo string) string {
+ var tempPasswd []byte
+
+ switch algo {
+ case algoBcrypt:
+ tempPasswd, _ = bcrypt.GenerateFromPassword([]byte(passwd), bcrypt.DefaultCost)
+ return string(tempPasswd)
+ case algoScrypt:
+ tempPasswd, _ = scrypt.Key([]byte(passwd), []byte(salt), 65536, 16, 2, 50)
+ case algoArgon2:
+ tempPasswd = argon2.IDKey([]byte(passwd), []byte(salt), 2, 65536, 8, 50)
+ case algoPbkdf2:
+ fallthrough
+ default:
+ tempPasswd = pbkdf2.Key([]byte(passwd), []byte(salt), 10000, 50, sha256.New)
+ }
+
+ return fmt.Sprintf("%x", tempPasswd)
+}
+
+// SetPassword hashes a password using the algorithm defined in the config value of PASSWORD_HASH_ALGO
+// change passwd, salt and passwd_hash_algo fields
+func (u *User) SetPassword(passwd string) (err error) {
+ if len(passwd) == 0 {
+ u.Passwd = ""
+ u.Salt = ""
+ u.PasswdHashAlgo = ""
+ return nil
+ }
+
+ if u.Salt, err = GetUserSalt(); err != nil {
+ return err
+ }
+ u.PasswdHashAlgo = setting.PasswordHashAlgo
+ u.Passwd = hashPassword(passwd, u.Salt, setting.PasswordHashAlgo)
+
+ return nil
+}
+
+// ValidatePassword checks if given password matches the one belongs to the user.
+func (u *User) ValidatePassword(passwd string) bool {
+ tempHash := hashPassword(passwd, u.Salt, u.PasswdHashAlgo)
+
+ if u.PasswdHashAlgo != algoBcrypt && subtle.ConstantTimeCompare([]byte(u.Passwd), []byte(tempHash)) == 1 {
+ return true
+ }
+ if u.PasswdHashAlgo == algoBcrypt && bcrypt.CompareHashAndPassword([]byte(u.Passwd), []byte(passwd)) == nil {
+ return true
+ }
+ return false
+}
+
+// IsPasswordSet checks if the password is set or left empty
+func (u *User) IsPasswordSet() bool {
+ return len(u.Passwd) != 0
+}
+
+// IsOrganization returns true if user is actually a organization.
+func (u *User) IsOrganization() bool {
+ return u.Type == UserTypeOrganization
+}
+
+// DisplayName returns full name if it's not empty,
+// returns username otherwise.
+func (u *User) DisplayName() string {
+ trimmed := strings.TrimSpace(u.FullName)
+ if len(trimmed) > 0 {
+ return trimmed
+ }
+ return u.Name
+}
+
+// GetDisplayName returns full name if it's not empty and DEFAULT_SHOW_FULL_NAME is set,
+// returns username otherwise.
+func (u *User) GetDisplayName() string {
+ if setting.UI.DefaultShowFullName {
+ trimmed := strings.TrimSpace(u.FullName)
+ if len(trimmed) > 0 {
+ return trimmed
+ }
+ }
+ return u.Name
+}
+
+func gitSafeName(name string) string {
+ return strings.TrimSpace(strings.NewReplacer("\n", "", "<", "", ">", "").Replace(name))
+}
+
+// GitName returns a git safe name
+func (u *User) GitName() string {
+ gitName := gitSafeName(u.FullName)
+ if len(gitName) > 0 {
+ return gitName
+ }
+ // Although u.Name should be safe if created in our system
+ // LDAP users may have bad names
+ gitName = gitSafeName(u.Name)
+ if len(gitName) > 0 {
+ return gitName
+ }
+ // Totally pathological name so it's got to be:
+ return fmt.Sprintf("user-%d", u.ID)
+}
+
+// ShortName ellipses username to length
+func (u *User) ShortName(length int) string {
+ return base.EllipsisString(u.Name, length)
+}
+
+// IsMailable checks if a user is eligible
+// to receive emails.
+func (u *User) IsMailable() bool {
+ return u.IsActive
+}
+
+// EmailNotifications returns the User's email notification preference
+func (u *User) EmailNotifications() string {
+ return u.EmailNotificationsPreference
+}
+
+// SetEmailNotifications sets the user's email notification preference
+func SetEmailNotifications(u *User, set string) error {
+ u.EmailNotificationsPreference = set
+ if err := UpdateUserCols(db.DefaultContext, u, "email_notifications_preference"); err != nil {
+ log.Error("SetEmailNotifications: %v", err)
+ return err
+ }
+ return nil
+}
+
+func isUserExist(e db.Engine, uid int64, name string) (bool, error) {
+ if len(name) == 0 {
+ return false, nil
+ }
+ return e.
+ Where("id!=?", uid).
+ Get(&User{LowerName: strings.ToLower(name)})
+}
+
+// IsUserExist checks if given user name exist,
+// the user name should be noncased unique.
+// If uid is presented, then check will rule out that one,
+// it is used when update a user name in settings page.
+func IsUserExist(uid int64, name string) (bool, error) {
+ return isUserExist(db.GetEngine(db.DefaultContext), uid, name)
+}
+
+// GetUserSalt returns a random user salt token.
+func GetUserSalt() (string, error) {
+ return util.RandomString(10)
+}
+
+// NewGhostUser creates and returns a fake user for someone has deleted his/her account.
+func NewGhostUser() *User {
+ return &User{
+ ID: -1,
+ Name: "Ghost",
+ LowerName: "ghost",
+ }
+}
+
+// NewReplaceUser creates and returns a fake user for external user
+func NewReplaceUser(name string) *User {
+ return &User{
+ ID: -1,
+ Name: name,
+ LowerName: strings.ToLower(name),
+ }
+}
+
+// IsGhost check if user is fake user for a deleted account
+func (u *User) IsGhost() bool {
+ if u == nil {
+ return false
+ }
+ return u.ID == -1 && u.Name == "Ghost"
+}
+
+var (
+ reservedUsernames = []string{
+ ".",
+ "..",
+ ".well-known",
+ "admin",
+ "api",
+ "assets",
+ "attachments",
+ "avatars",
+ "captcha",
+ "commits",
+ "debug",
+ "error",
+ "explore",
+ "favicon.ico",
+ "ghost",
+ "help",
+ "install",
+ "issues",
+ "less",
+ "login",
+ "manifest.json",
+ "metrics",
+ "milestones",
+ "new",
+ "notifications",
+ "org",
+ "plugins",
+ "pulls",
+ "raw",
+ "repo",
+ "robots.txt",
+ "search",
+ "serviceworker.js",
+ "stars",
+ "template",
+ "user",
+ }
+
+ reservedUserPatterns = []string{"*.keys", "*.gpg", "*.rss", "*.atom"}
+)
+
+// IsUsableUsername returns an error when a username is reserved
+func IsUsableUsername(name string) error {
+ // Validate username make sure it satisfies requirement.
+ if db.AlphaDashDotPattern.MatchString(name) {
+ // Note: usually this error is normally caught up earlier in the UI
+ return db.ErrNameCharsNotAllowed{Name: name}
+ }
+ return db.IsUsableName(reservedUsernames, reservedUserPatterns, name)
+}
+
+// CreateUserOverwriteOptions are an optional options who overwrite system defaults on user creation
+type CreateUserOverwriteOptions struct {
+ Visibility structs.VisibleType
+}
+
+// CreateUser creates record of a new user.
+func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err error) {
+ if err = IsUsableUsername(u.Name); err != nil {
+ return err
+ }
+
+ // set system defaults
+ u.KeepEmailPrivate = setting.Service.DefaultKeepEmailPrivate
+ u.Visibility = setting.Service.DefaultUserVisibilityMode
+ u.AllowCreateOrganization = setting.Service.DefaultAllowCreateOrganization && !setting.Admin.DisableRegularOrgCreation
+ u.EmailNotificationsPreference = setting.Admin.DefaultEmailNotification
+ u.MaxRepoCreation = -1
+ u.Theme = setting.UI.DefaultTheme
+
+ // overwrite defaults if set
+ if len(overwriteDefault) != 0 && overwriteDefault[0] != nil {
+ u.Visibility = overwriteDefault[0].Visibility
+ }
+
+ ctx, committer, err := db.TxContext()
+ if err != nil {
+ return err
+ }
+ defer committer.Close()
+
+ sess := db.GetEngine(ctx)
+
+ // validate data
+ if err := validateUser(u); err != nil {
+ return err
+ }
+
+ isExist, err := isUserExist(sess, 0, u.Name)
+ if err != nil {
+ return err
+ } else if isExist {
+ return ErrUserAlreadyExist{u.Name}
+ }
+
+ isExist, err = IsEmailUsed(ctx, u.Email)
+ if err != nil {
+ return err
+ } else if isExist {
+ return ErrEmailAlreadyUsed{
+ Email: u.Email,
+ }
+ }
+
+ // prepare for database
+
+ u.LowerName = strings.ToLower(u.Name)
+ u.AvatarEmail = u.Email
+ if u.Rands, err = GetUserSalt(); err != nil {
+ return err
+ }
+ if err = u.SetPassword(u.Passwd); err != nil {
+ return err
+ }
+
+ // save changes to database
+
+ if err = DeleteUserRedirect(ctx, u.Name); err != nil {
+ return err
+ }
+
+ if err = db.Insert(ctx, u); err != nil {
+ return err
+ }
+
+ // insert email address
+ if err := db.Insert(ctx, &EmailAddress{
+ UID: u.ID,
+ Email: u.Email,
+ LowerEmail: strings.ToLower(u.Email),
+ IsActivated: u.IsActive,
+ IsPrimary: true,
+ }); err != nil {
+ return err
+ }
+
+ return committer.Commit()
+}
+
+func countUsers(e db.Engine) int64 {
+ count, _ := e.
+ Where("type=0").
+ Count(new(User))
+ return count
+}
+
+// CountUsers returns number of users.
+func CountUsers() int64 {
+ return countUsers(db.GetEngine(db.DefaultContext))
+}
+
+// GetVerifyUser get user by verify code
+func GetVerifyUser(code string) (user *User) {
+ if len(code) <= base.TimeLimitCodeLength {
+ return nil
+ }
+
+ // use tail hex username query user
+ hexStr := code[base.TimeLimitCodeLength:]
+ if b, err := hex.DecodeString(hexStr); err == nil {
+ if user, err = GetUserByName(string(b)); user != nil {
+ return user
+ }
+ log.Error("user.getVerifyUser: %v", err)
+ }
+
+ return nil
+}
+
+// VerifyUserActiveCode verifies active code when active account
+func VerifyUserActiveCode(code string) (user *User) {
+ minutes := setting.Service.ActiveCodeLives
+
+ if user = GetVerifyUser(code); user != nil {
+ // time limit code
+ prefix := code[:base.TimeLimitCodeLength]
+ data := fmt.Sprintf("%d%s%s%s%s", user.ID, user.Email, user.LowerName, user.Passwd, user.Rands)
+
+ if base.VerifyTimeLimitCode(data, minutes, prefix) {
+ return user
+ }
+ }
+ return nil
+}
+
+// ChangeUserName changes all corresponding setting from old user name to new one.
+func ChangeUserName(u *User, newUserName string) (err error) {
+ oldUserName := u.Name
+ if err = IsUsableUsername(newUserName); err != nil {
+ return err
+ }
+
+ ctx, committer, err := db.TxContext()
+ if err != nil {
+ return err
+ }
+ defer committer.Close()
+ sess := db.GetEngine(ctx)
+
+ isExist, err := isUserExist(sess, 0, newUserName)
+ if err != nil {
+ return err
+ } else if isExist {
+ return ErrUserAlreadyExist{newUserName}
+ }
+
+ if _, err = sess.Exec("UPDATE `repository` SET owner_name=? WHERE owner_name=?", newUserName, oldUserName); err != nil {
+ return fmt.Errorf("Change repo owner name: %v", err)
+ }
+
+ // Do not fail if directory does not exist
+ if err = util.Rename(UserPath(oldUserName), UserPath(newUserName)); err != nil && !os.IsNotExist(err) {
+ return fmt.Errorf("Rename user directory: %v", err)
+ }
+
+ if err = NewUserRedirect(ctx, u.ID, oldUserName, newUserName); err != nil {
+ return err
+ }
+
+ if err = committer.Commit(); err != nil {
+ if err2 := util.Rename(UserPath(newUserName), UserPath(oldUserName)); err2 != nil && !os.IsNotExist(err2) {
+ log.Critical("Unable to rollback directory change during failed username change from: %s to: %s. DB Error: %v. Filesystem Error: %v", oldUserName, newUserName, err, err2)
+ return fmt.Errorf("failed to rollback directory change during failed username change from: %s to: %s. DB Error: %w. Filesystem Error: %v", oldUserName, newUserName, err, err2)
+ }
+ return err
+ }
+
+ return nil
+}
+
+// checkDupEmail checks whether there are the same email with the user
+func checkDupEmail(e db.Engine, u *User) error {
+ u.Email = strings.ToLower(u.Email)
+ has, err := e.
+ Where("id!=?", u.ID).
+ And("type=?", u.Type).
+ And("email=?", u.Email).
+ Get(new(User))
+ if err != nil {
+ return err
+ } else if has {
+ return ErrEmailAlreadyUsed{
+ Email: u.Email,
+ }
+ }
+ return nil
+}
+
+// validateUser check if user is valid to insert / update into database
+func validateUser(u *User) error {
+ if !setting.Service.AllowedUserVisibilityModesSlice.IsAllowedVisibility(u.Visibility) && !u.IsOrganization() {
+ return fmt.Errorf("visibility Mode not allowed: %s", u.Visibility.String())
+ }
+
+ u.Email = strings.ToLower(u.Email)
+ return ValidateEmail(u.Email)
+}
+
+func updateUser(e db.Engine, u *User) error {
+ if err := validateUser(u); err != nil {
+ return err
+ }
+
+ _, err := e.ID(u.ID).AllCols().Update(u)
+ return err
+}
+
+// UpdateUser updates user's information.
+func UpdateUser(u *User) error {
+ return updateUser(db.GetEngine(db.DefaultContext), u)
+}
+
+// UpdateUserCols update user according special columns
+func UpdateUserCols(ctx context.Context, u *User, cols ...string) error {
+ return updateUserCols(db.GetEngine(ctx), u, cols...)
+}
+
+// UpdateUserColsEngine update user according special columns
+func UpdateUserColsEngine(e db.Engine, u *User, cols ...string) error {
+ return updateUserCols(e, u, cols...)
+}
+
+func updateUserCols(e db.Engine, u *User, cols ...string) error {
+ if err := validateUser(u); err != nil {
+ return err
+ }
+
+ _, err := e.ID(u.ID).Cols(cols...).Update(u)
+ return err
+}
+
+// UpdateUserSetting updates user's settings.
+func UpdateUserSetting(u *User) (err error) {
+ ctx, committer, err := db.TxContext()
+ if err != nil {
+ return err
+ }
+ defer committer.Close()
+ sess := db.GetEngine(ctx)
+
+ if !u.IsOrganization() {
+ if err = checkDupEmail(sess, u); err != nil {
+ return err
+ }
+ }
+ if err = updateUser(sess, u); err != nil {
+ return err
+ }
+ return committer.Commit()
+}
+
+// GetInactiveUsers gets all inactive users
+func GetInactiveUsers(ctx context.Context, olderThan time.Duration) ([]*User, error) {
+ var cond builder.Cond = builder.Eq{"is_active": false}
+
+ if olderThan > 0 {
+ cond = cond.And(builder.Lt{"created_unix": time.Now().Add(-olderThan).Unix()})
+ }
+
+ users := make([]*User, 0, 10)
+ return users, db.GetEngine(ctx).
+ Where(cond).
+ Find(&users)
+}
+
+// UserPath returns the path absolute path of user repositories.
+func UserPath(userName string) string { //revive:disable-line:exported
+ return filepath.Join(setting.RepoRootPath, strings.ToLower(userName))
+}
+
+// GetUserByIDEngine returns the user object by given ID if exists.
+func GetUserByIDEngine(e db.Engine, id int64) (*User, error) {
+ u := new(User)
+ has, err := e.ID(id).Get(u)
+ if err != nil {
+ return nil, err
+ } else if !has {
+ return nil, ErrUserNotExist{id, "", 0}
+ }
+ return u, nil
+}
+
+// GetUserByID returns the user object by given ID if exists.
+func GetUserByID(id int64) (*User, error) {
+ return GetUserByIDCtx(db.DefaultContext, id)
+}
+
+// GetUserByIDCtx returns the user object by given ID if exists.
+func GetUserByIDCtx(ctx context.Context, id int64) (*User, error) {
+ return GetUserByIDEngine(db.GetEngine(ctx), id)
+}
+
+// GetUserByName returns user by given name.
+func GetUserByName(name string) (*User, error) {
+ return GetUserByNameCtx(db.DefaultContext, name)
+}
+
+// GetUserByNameCtx returns user by given name.
+func GetUserByNameCtx(ctx context.Context, name string) (*User, error) {
+ if len(name) == 0 {
+ return nil, ErrUserNotExist{0, name, 0}
+ }
+ u := &User{LowerName: strings.ToLower(name)}
+ has, err := db.GetEngine(ctx).Get(u)
+ if err != nil {
+ return nil, err
+ } else if !has {
+ return nil, ErrUserNotExist{0, name, 0}
+ }
+ return u, nil
+}
+
+// GetUserEmailsByNames returns a list of e-mails corresponds to names of users
+// that have their email notifications set to enabled or onmention.
+func GetUserEmailsByNames(names []string) []string {
+ return getUserEmailsByNames(db.DefaultContext, names)
+}
+
+func getUserEmailsByNames(ctx context.Context, names []string) []string {
+ mails := make([]string, 0, len(names))
+ for _, name := range names {
+ u, err := GetUserByNameCtx(ctx, name)
+ if err != nil {
+ continue
+ }
+ if u.IsMailable() && u.EmailNotifications() != EmailNotificationsDisabled {
+ mails = append(mails, u.Email)
+ }
+ }
+ return mails
+}
+
+// GetMaileableUsersByIDs gets users from ids, but only if they can receive mails
+func GetMaileableUsersByIDs(ids []int64, isMention bool) ([]*User, error) {
+ if len(ids) == 0 {
+ return nil, nil
+ }
+ ous := make([]*User, 0, len(ids))
+
+ if isMention {
+ return ous, db.GetEngine(db.DefaultContext).In("id", ids).
+ Where("`type` = ?", UserTypeIndividual).
+ And("`prohibit_login` = ?", false).
+ And("`is_active` = ?", true).
+ And("`email_notifications_preference` IN ( ?, ?)", EmailNotificationsEnabled, EmailNotificationsOnMention).
+ Find(&ous)
+ }
+
+ return ous, db.GetEngine(db.DefaultContext).In("id", ids).
+ Where("`type` = ?", UserTypeIndividual).
+ And("`prohibit_login` = ?", false).
+ And("`is_active` = ?", true).
+ And("`email_notifications_preference` = ?", EmailNotificationsEnabled).
+ Find(&ous)
+}
+
+// GetUserNamesByIDs returns usernames for all resolved users from a list of Ids.
+func GetUserNamesByIDs(ids []int64) ([]string, error) {
+ unames := make([]string, 0, len(ids))
+ err := db.GetEngine(db.DefaultContext).In("id", ids).
+ Table("user").
+ Asc("name").
+ Cols("name").
+ Find(&unames)
+ return unames, err
+}
+
+// GetUserIDsByNames returns a slice of ids corresponds to names.
+func GetUserIDsByNames(names []string, ignoreNonExistent bool) ([]int64, error) {
+ ids := make([]int64, 0, len(names))
+ for _, name := range names {
+ u, err := GetUserByName(name)
+ if err != nil {
+ if ignoreNonExistent {
+ continue
+ } else {
+ return nil, err
+ }
+ }
+ ids = append(ids, u.ID)
+ }
+ return ids, nil
+}
+
+// GetUsersBySource returns a list of Users for a login source
+func GetUsersBySource(s *login.Source) ([]*User, error) {
+ var users []*User
+ err := db.GetEngine(db.DefaultContext).Where("login_type = ? AND login_source = ?", s.Type, s.ID).Find(&users)
+ return users, err
+}
+
+// UserCommit represents a commit with validation of user.
+type UserCommit struct { //revive:disable-line:exported
+ User *User
+ *git.Commit
+}
+
+// ValidateCommitWithEmail check if author's e-mail of commit is corresponding to a user.
+func ValidateCommitWithEmail(c *git.Commit) *User {
+ if c.Author == nil {
+ return nil
+ }
+ u, err := GetUserByEmail(c.Author.Email)
+ if err != nil {
+ return nil
+ }
+ return u
+}
+
+// ValidateCommitsWithEmails checks if authors' e-mails of commits are corresponding to users.
+func ValidateCommitsWithEmails(oldCommits []*git.Commit) []*UserCommit {
+ var (
+ emails = make(map[string]*User)
+ newCommits = make([]*UserCommit, 0, len(oldCommits))
+ )
+ for _, c := range oldCommits {
+ var u *User
+ if c.Author != nil {
+ if v, ok := emails[c.Author.Email]; !ok {
+ u, _ = GetUserByEmail(c.Author.Email)
+ emails[c.Author.Email] = u
+ } else {
+ u = v
+ }
+ }
+
+ newCommits = append(newCommits, &UserCommit{
+ User: u,
+ Commit: c,
+ })
+ }
+ return newCommits
+}
+
+// GetUserByEmail returns the user object by given e-mail if exists.
+func GetUserByEmail(email string) (*User, error) {
+ return GetUserByEmailContext(db.DefaultContext, email)
+}
+
+// GetUserByEmailContext returns the user object by given e-mail if exists with db context
+func GetUserByEmailContext(ctx context.Context, email string) (*User, error) {
+ if len(email) == 0 {
+ return nil, ErrUserNotExist{0, email, 0}
+ }
+
+ email = strings.ToLower(email)
+ // First try to find the user by primary email
+ user := &User{Email: email}
+ has, err := db.GetEngine(ctx).Get(user)
+ if err != nil {
+ return nil, err
+ }
+ if has {
+ return user, nil
+ }
+
+ // Otherwise, check in alternative list for activated email addresses
+ emailAddress := &EmailAddress{Email: email, IsActivated: true}
+ has, err = db.GetEngine(ctx).Get(emailAddress)
+ if err != nil {
+ return nil, err
+ }
+ if has {
+ return GetUserByIDCtx(ctx, emailAddress.UID)
+ }
+
+ // Finally, if email address is the protected email address:
+ if strings.HasSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) {
+ username := strings.TrimSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress))
+ user := &User{}
+ has, err := db.GetEngine(ctx).Where("lower_name=?", username).Get(user)
+ if err != nil {
+ return nil, err
+ }
+ if has {
+ return user, nil
+ }
+ }
+
+ return nil, ErrUserNotExist{0, email, 0}
+}
+
+// GetUser checks if a user already exists
+func GetUser(user *User) (bool, error) {
+ return db.GetEngine(db.DefaultContext).Get(user)
+}
+
+// GetUserByOpenID returns the user object by given OpenID if exists.
+func GetUserByOpenID(uri string) (*User, error) {
+ if len(uri) == 0 {
+ return nil, ErrUserNotExist{0, uri, 0}
+ }
+
+ uri, err := openid.Normalize(uri)
+ if err != nil {
+ return nil, err
+ }
+
+ log.Trace("Normalized OpenID URI: " + uri)
+
+ // Otherwise, check in openid table
+ oid := &UserOpenID{}
+ has, err := db.GetEngine(db.DefaultContext).Where("uri=?", uri).Get(oid)
+ if err != nil {
+ return nil, err
+ }
+ if has {
+ return GetUserByID(oid.UID)
+ }
+
+ return nil, ErrUserNotExist{0, uri, 0}
+}
+
+// GetAdminUser returns the first administrator
+func GetAdminUser() (*User, error) {
+ var admin User
+ has, err := db.GetEngine(db.DefaultContext).Where("is_admin=?", true).Get(&admin)
+ if err != nil {
+ return nil, err
+ } else if !has {
+ return nil, ErrUserNotExist{}
+ }
+
+ return &admin, nil
+}
diff --git a/models/user/user_test.go b/models/user/user_test.go
new file mode 100644
index 0000000000..ac49852254
--- /dev/null
+++ b/models/user/user_test.go
@@ -0,0 +1,355 @@
+// Copyright 2017 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package user
+
+import (
+ "math/rand"
+ "strings"
+ "testing"
+
+ "code.gitea.io/gitea/models/db"
+ "code.gitea.io/gitea/models/login"
+ "code.gitea.io/gitea/models/unittest"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/util"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestOAuth2Application_LoadUser(t *testing.T) {
+ assert.NoError(t, unittest.PrepareTestDatabase())
+ app := unittest.AssertExistsAndLoadBean(t, &login.OAuth2Application{ID: 1}).(*login.OAuth2Application)
+ user, err := GetUserByID(app.UID)
+ assert.NoError(t, err)
+ assert.NotNil(t, user)
+}
+
+func TestGetUserEmailsByNames(t *testing.T) {
+ assert.NoError(t, unittest.PrepareTestDatabase())
+
+ // ignore none active user email
+ assert.Equal(t, []string{"user8@example.com"}, GetUserEmailsByNames([]string{"user8", "user9"}))
+ assert.Equal(t, []string{"user8@example.com", "user5@example.com"}, GetUserEmailsByNames([]string{"user8", "user5"}))
+
+ assert.Equal(t, []string{"user8@example.com"}, GetUserEmailsByNames([]string{"user8", "user7"}))
+}
+
+func TestCanCreateOrganization(t *testing.T) {
+ assert.NoError(t, unittest.PrepareTestDatabase())
+
+ admin := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
+ assert.True(t, admin.CanCreateOrganization())
+
+ user := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ assert.True(t, user.CanCreateOrganization())
+ // Disable user create organization permission.
+ user.AllowCreateOrganization = false
+ assert.False(t, user.CanCreateOrganization())
+
+ setting.Admin.DisableRegularOrgCreation = true
+ user.AllowCreateOrganization = true
+ assert.True(t, admin.CanCreateOrganization())
+ assert.False(t, user.CanCreateOrganization())
+}
+
+func TestSearchUsers(t *testing.T) {
+ assert.NoError(t, unittest.PrepareTestDatabase())
+ testSuccess := func(opts *SearchUserOptions, expectedUserOrOrgIDs []int64) {
+ users, _, err := SearchUsers(opts)
+ assert.NoError(t, err)
+ if assert.Len(t, users, len(expectedUserOrOrgIDs), opts) {
+ for i, expectedID := range expectedUserOrOrgIDs {
+ assert.EqualValues(t, expectedID, users[i].ID)
+ }
+ }
+ }
+
+ // test orgs
+ testOrgSuccess := func(opts *SearchUserOptions, expectedOrgIDs []int64) {
+ opts.Type = UserTypeOrganization
+ testSuccess(opts, expectedOrgIDs)
+ }
+
+ testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1, PageSize: 2}},
+ []int64{3, 6})
+
+ testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 2, PageSize: 2}},
+ []int64{7, 17})
+
+ testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 3, PageSize: 2}},
+ []int64{19, 25})
+
+ testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 4, PageSize: 2}},
+ []int64{26})
+
+ testOrgSuccess(&SearchUserOptions{ListOptions: db.ListOptions{Page: 5, PageSize: 2}},
+ []int64{})
+
+ // test users
+ testUserSuccess := func(opts *SearchUserOptions, expectedUserIDs []int64) {
+ opts.Type = UserTypeIndividual
+ testSuccess(opts, expectedUserIDs)
+ }
+
+ testUserSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}},
+ []int64{1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32})
+
+ testUserSuccess(&SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolFalse},
+ []int64{9})
+
+ testUserSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue},
+ []int64{1, 2, 4, 5, 8, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 28, 29, 30, 32})
+
+ testUserSuccess(&SearchUserOptions{Keyword: "user1", OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue},
+ []int64{1, 10, 11, 12, 13, 14, 15, 16, 18})
+
+ // order by name asc default
+ testUserSuccess(&SearchUserOptions{Keyword: "user1", ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue},
+ []int64{1, 10, 11, 12, 13, 14, 15, 16, 18})
+
+ testUserSuccess(&SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsAdmin: util.OptionalBoolTrue},
+ []int64{1})
+
+ testUserSuccess(&SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsRestricted: util.OptionalBoolTrue},
+ []int64{29, 30})
+
+ testUserSuccess(&SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsProhibitLogin: util.OptionalBoolTrue},
+ []int64{30})
+
+ testUserSuccess(&SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsTwoFactorEnabled: util.OptionalBoolTrue},
+ []int64{24})
+}
+
+func TestEmailNotificationPreferences(t *testing.T) {
+ assert.NoError(t, unittest.PrepareTestDatabase())
+
+ for _, test := range []struct {
+ expected string
+ userID int64
+ }{
+ {EmailNotificationsEnabled, 1},
+ {EmailNotificationsEnabled, 2},
+ {EmailNotificationsOnMention, 3},
+ {EmailNotificationsOnMention, 4},
+ {EmailNotificationsEnabled, 5},
+ {EmailNotificationsEnabled, 6},
+ {EmailNotificationsDisabled, 7},
+ {EmailNotificationsEnabled, 8},
+ {EmailNotificationsOnMention, 9},
+ } {
+ user := unittest.AssertExistsAndLoadBean(t, &User{ID: test.userID}).(*User)
+ assert.Equal(t, test.expected, user.EmailNotifications())
+
+ // Try all possible settings
+ assert.NoError(t, SetEmailNotifications(user, EmailNotificationsEnabled))
+ assert.Equal(t, EmailNotificationsEnabled, user.EmailNotifications())
+
+ assert.NoError(t, SetEmailNotifications(user, EmailNotificationsOnMention))
+ assert.Equal(t, EmailNotificationsOnMention, user.EmailNotifications())
+
+ assert.NoError(t, SetEmailNotifications(user, EmailNotificationsDisabled))
+ assert.Equal(t, EmailNotificationsDisabled, user.EmailNotifications())
+ }
+}
+
+func TestHashPasswordDeterministic(t *testing.T) {
+ b := make([]byte, 16)
+ u := &User{}
+ algos := []string{"argon2", "pbkdf2", "scrypt", "bcrypt"}
+ for j := 0; j < len(algos); j++ {
+ u.PasswdHashAlgo = algos[j]
+ for i := 0; i < 50; i++ {
+ // generate a random password
+ rand.Read(b)
+ pass := string(b)
+
+ // save the current password in the user - hash it and store the result
+ u.SetPassword(pass)
+ r1 := u.Passwd
+
+ // run again
+ u.SetPassword(pass)
+ r2 := u.Passwd
+
+ assert.NotEqual(t, r1, r2)
+ assert.True(t, u.ValidatePassword(pass))
+ }
+ }
+}
+
+func BenchmarkHashPassword(b *testing.B) {
+ // BenchmarkHashPassword ensures that it takes a reasonable amount of time
+ // to hash a password - in order to protect from brute-force attacks.
+ pass := "password1337"
+ u := &User{Passwd: pass}
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ u.SetPassword(pass)
+ }
+}
+
+func TestNewGitSig(t *testing.T) {
+ users := make([]*User, 0, 20)
+ err := db.GetEngine(db.DefaultContext).Find(&users)
+ assert.NoError(t, err)
+
+ for _, user := range users {
+ sig := user.NewGitSig()
+ assert.NotContains(t, sig.Name, "<")
+ assert.NotContains(t, sig.Name, ">")
+ assert.NotContains(t, sig.Name, "\n")
+ assert.NotEqual(t, len(strings.TrimSpace(sig.Name)), 0)
+ }
+}
+
+func TestDisplayName(t *testing.T) {
+ users := make([]*User, 0, 20)
+ err := db.GetEngine(db.DefaultContext).Find(&users)
+ assert.NoError(t, err)
+
+ for _, user := range users {
+ displayName := user.DisplayName()
+ assert.Equal(t, strings.TrimSpace(displayName), displayName)
+ if len(strings.TrimSpace(user.FullName)) == 0 {
+ assert.Equal(t, user.Name, displayName)
+ }
+ assert.NotEqual(t, len(strings.TrimSpace(displayName)), 0)
+ }
+}
+
+func TestCreateUserInvalidEmail(t *testing.T) {
+ user := &User{
+ Name: "GiteaBot",
+ Email: "GiteaBot@gitea.io\r\n",
+ Passwd: ";p['////..-++']",
+ IsAdmin: false,
+ Theme: setting.UI.DefaultTheme,
+ MustChangePassword: false,
+ }
+
+ err := CreateUser(user)
+ assert.Error(t, err)
+ assert.True(t, IsErrEmailInvalid(err))
+}
+
+func TestGetUserIDsByNames(t *testing.T) {
+ assert.NoError(t, unittest.PrepareTestDatabase())
+
+ // ignore non existing
+ IDs, err := GetUserIDsByNames([]string{"user1", "user2", "none_existing_user"}, true)
+ assert.NoError(t, err)
+ assert.Equal(t, []int64{1, 2}, IDs)
+
+ // ignore non existing
+ IDs, err = GetUserIDsByNames([]string{"user1", "do_not_exist"}, false)
+ assert.Error(t, err)
+ assert.Equal(t, []int64(nil), IDs)
+}
+
+func TestGetMaileableUsersByIDs(t *testing.T) {
+ assert.NoError(t, unittest.PrepareTestDatabase())
+
+ results, err := GetMaileableUsersByIDs([]int64{1, 4}, false)
+ assert.NoError(t, err)
+ assert.Len(t, results, 1)
+ if len(results) > 1 {
+ assert.Equal(t, results[0].ID, 1)
+ }
+
+ results, err = GetMaileableUsersByIDs([]int64{1, 4}, true)
+ assert.NoError(t, err)
+ assert.Len(t, results, 2)
+ if len(results) > 2 {
+ assert.Equal(t, results[0].ID, 1)
+ assert.Equal(t, results[1].ID, 4)
+ }
+}
+
+func TestUpdateUser(t *testing.T) {
+ assert.NoError(t, unittest.PrepareTestDatabase())
+ user := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+
+ user.KeepActivityPrivate = true
+ assert.NoError(t, UpdateUser(user))
+ user = unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ assert.True(t, user.KeepActivityPrivate)
+
+ setting.Service.AllowedUserVisibilityModesSlice = []bool{true, false, false}
+ user.KeepActivityPrivate = false
+ user.Visibility = structs.VisibleTypePrivate
+ assert.Error(t, UpdateUser(user))
+ user = unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ assert.True(t, user.KeepActivityPrivate)
+
+ user.Email = "no mail@mail.org"
+ assert.Error(t, UpdateUser(user))
+}
+
+func TestNewUserRedirect(t *testing.T) {
+ // redirect to a completely new name
+ assert.NoError(t, unittest.PrepareTestDatabase())
+
+ user := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
+ assert.NoError(t, NewUserRedirect(db.DefaultContext, user.ID, user.Name, "newusername"))
+
+ unittest.AssertExistsAndLoadBean(t, &Redirect{
+ LowerName: user.LowerName,
+ RedirectUserID: user.ID,
+ })
+ unittest.AssertExistsAndLoadBean(t, &Redirect{
+ LowerName: "olduser1",
+ RedirectUserID: user.ID,
+ })
+}
+
+func TestNewUserRedirect2(t *testing.T) {
+ // redirect to previously used name
+ assert.NoError(t, unittest.PrepareTestDatabase())
+
+ user := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
+ assert.NoError(t, NewUserRedirect(db.DefaultContext, user.ID, user.Name, "olduser1"))
+
+ unittest.AssertExistsAndLoadBean(t, &Redirect{
+ LowerName: user.LowerName,
+ RedirectUserID: user.ID,
+ })
+ unittest.AssertNotExistsBean(t, &Redirect{
+ LowerName: "olduser1",
+ RedirectUserID: user.ID,
+ })
+}
+
+func TestNewUserRedirect3(t *testing.T) {
+ // redirect for a previously-unredirected user
+ assert.NoError(t, unittest.PrepareTestDatabase())
+
+ user := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ assert.NoError(t, NewUserRedirect(db.DefaultContext, user.ID, user.Name, "newusername"))
+
+ unittest.AssertExistsAndLoadBean(t, &Redirect{
+ LowerName: user.LowerName,
+ RedirectUserID: user.ID,
+ })
+}
+
+func TestGetUserByOpenID(t *testing.T) {
+ assert.NoError(t, unittest.PrepareTestDatabase())
+
+ _, err := GetUserByOpenID("https://unknown")
+ if assert.Error(t, err) {
+ assert.True(t, IsErrUserNotExist(err))
+ }
+
+ user, err := GetUserByOpenID("https://user1.domain1.tld")
+ if assert.NoError(t, err) {
+ assert.Equal(t, int64(1), user.ID)
+ }
+
+ user, err = GetUserByOpenID("https://domain1.tld/user2/")
+ if assert.NoError(t, err) {
+ assert.Equal(t, int64(2), user.ID)
+ }
+}
diff --git a/models/user_email.go b/models/user_email.go
index 8c5fbf6d6a..528ebb0540 100644
--- a/models/user_email.go
+++ b/models/user_email.go
@@ -31,18 +31,18 @@ func ActivateEmail(email *user_model.EmailAddress) error {
}
func updateActivation(e db.Engine, email *user_model.EmailAddress, activate bool) error {
- user, err := getUserByID(e, email.UID)
+ user, err := user_model.GetUserByIDEngine(e, email.UID)
if err != nil {
return err
}
- if user.Rands, err = GetUserSalt(); err != nil {
+ if user.Rands, err = user_model.GetUserSalt(); err != nil {
return err
}
email.IsActivated = activate
if _, err := e.ID(email.ID).Cols("is_activated").Update(email); err != nil {
return err
}
- return updateUserCols(e, user, "rands")
+ return user_model.UpdateUserColsEngine(e, user, "rands")
}
// MakeEmailPrimary sets primary email address of given user.
@@ -58,12 +58,16 @@ func MakeEmailPrimary(email *user_model.EmailAddress) error {
return user_model.ErrEmailNotActivated
}
- user := &User{}
+ user := &user_model.User{}
has, err = db.GetEngine(db.DefaultContext).ID(email.UID).Get(user)
if err != nil {
return err
} else if !has {
- return ErrUserNotExist{email.UID, "", 0}
+ return user_model.ErrUserNotExist{
+ UID: email.UID,
+ Name: "",
+ KeyID: 0,
+ }
}
ctx, committer, err := db.TxContext()
@@ -99,7 +103,7 @@ func MakeEmailPrimary(email *user_model.EmailAddress) error {
func VerifyActiveEmailCode(code, email string) *user_model.EmailAddress {
minutes := setting.Service.ActiveCodeLives
- if user := getVerifyUser(code); user != nil {
+ if user := user_model.GetVerifyUser(code); user != nil {
// time limit code
prefix := code[:base.TimeLimitCodeLength]
data := fmt.Sprintf("%d%s%s%s%s", user.ID, email, user.LowerName, user.Passwd, user.Rands)
@@ -152,7 +156,7 @@ type SearchEmailResult struct {
// SearchEmails takes options i.e. keyword and part of email name to search,
// it returns results in given range and number of total results.
func SearchEmails(opts *SearchEmailOptions) ([]*SearchEmailResult, int64, error) {
- var cond builder.Cond = builder.Eq{"`user`.`type`": UserTypeIndividual}
+ var cond builder.Cond = builder.Eq{"`user`.`type`": user_model.UserTypeIndividual}
if len(opts.Keyword) > 0 {
likeStr := "%" + strings.ToLower(opts.Keyword) + "%"
cond = cond.And(builder.Or(
@@ -236,7 +240,7 @@ func ActivateUserEmail(userID int64, email string, activate bool) (err error) {
// Activate/deactivate a user's primary email address and account
if addr.IsPrimary {
- user := User{ID: userID, Email: email}
+ user := user_model.User{ID: userID, Email: email}
if has, err := sess.Get(&user); err != nil {
return err
} else if !has {
@@ -245,10 +249,10 @@ func ActivateUserEmail(userID int64, email string, activate bool) (err error) {
// The user's activation state should be synchronized with the primary email
if user.IsActive != activate {
user.IsActive = activate
- if user.Rands, err = GetUserSalt(); err != nil {
+ if user.Rands, err = user_model.GetUserSalt(); err != nil {
return fmt.Errorf("unable to generate salt: %v", err)
}
- if err = updateUserCols(sess, &user, "is_active", "rands"); err != nil {
+ if err = user_model.UpdateUserColsEngine(sess, &user, "is_active", "rands"); err != nil {
return fmt.Errorf("unable to updateUserCols() for user ID: %d: %v", userID, err)
}
}
diff --git a/models/user_email_test.go b/models/user_email_test.go
index bed6a18867..a91e24d363 100644
--- a/models/user_email_test.go
+++ b/models/user_email_test.go
@@ -37,7 +37,7 @@ func TestMakeEmailPrimary(t *testing.T) {
}
err = MakeEmailPrimary(email)
assert.Error(t, err)
- assert.True(t, IsErrUserNotExist(err))
+ assert.True(t, user_model.IsErrUserNotExist(err))
email = &user_model.EmailAddress{
Email: "user101@example.com",
@@ -45,7 +45,7 @@ func TestMakeEmailPrimary(t *testing.T) {
err = MakeEmailPrimary(email)
assert.NoError(t, err)
- user, _ := GetUserByID(int64(10))
+ user, _ := user_model.GetUserByID(int64(10))
assert.Equal(t, "user101@example.com", user.Email)
}
diff --git a/models/user_heatmap.go b/models/user_heatmap.go
index 3e94a6f9b7..f331a0c16b 100644
--- a/models/user_heatmap.go
+++ b/models/user_heatmap.go
@@ -6,6 +6,7 @@ package models
import (
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
)
@@ -17,16 +18,16 @@ type UserHeatmapData struct {
}
// GetUserHeatmapDataByUser returns an array of UserHeatmapData
-func GetUserHeatmapDataByUser(user, doer *User) ([]*UserHeatmapData, error) {
+func GetUserHeatmapDataByUser(user, doer *user_model.User) ([]*UserHeatmapData, error) {
return getUserHeatmapData(user, nil, doer)
}
// GetUserHeatmapDataByUserTeam returns an array of UserHeatmapData
-func GetUserHeatmapDataByUserTeam(user *User, team *Team, doer *User) ([]*UserHeatmapData, error) {
+func GetUserHeatmapDataByUserTeam(user *user_model.User, team *Team, doer *user_model.User) ([]*UserHeatmapData, error) {
return getUserHeatmapData(user, team, doer)
}
-func getUserHeatmapData(user *User, team *Team, doer *User) ([]*UserHeatmapData, error) {
+func getUserHeatmapData(user *user_model.User, team *Team, doer *user_model.User) ([]*UserHeatmapData, error) {
hdata := make([]*UserHeatmapData, 0)
if !activityReadable(user, doer) {
diff --git a/models/user_heatmap_test.go b/models/user_heatmap_test.go
index 2abbbfc6f3..7d2997648d 100644
--- a/models/user_heatmap_test.go
+++ b/models/user_heatmap_test.go
@@ -10,6 +10,7 @@ import (
"time"
"code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/timeutil"
@@ -46,9 +47,9 @@ func TestGetUserHeatmapDataByUser(t *testing.T) {
defer timeutil.Unset()
for i, tc := range testCases {
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: tc.userID}).(*User)
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: tc.userID}).(*user_model.User)
- doer := &User{ID: tc.doerID}
+ doer := &user_model.User{ID: tc.doerID}
_, err := unittest.LoadBeanIfExists(doer)
assert.NoError(t, err)
if tc.doerID == 0 {
diff --git a/models/user_test.go b/models/user_test.go
index cfbd849640..d3c7718d69 100644
--- a/models/user_test.go
+++ b/models/user_test.go
@@ -6,27 +6,42 @@ package models
import (
"fmt"
- "math/rand"
- "strings"
"testing"
- "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/login"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
- "code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/structs"
- "code.gitea.io/gitea/modules/util"
"github.com/stretchr/testify/assert"
)
-func TestOAuth2Application_LoadUser(t *testing.T) {
+func TestFollowUser(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- app := unittest.AssertExistsAndLoadBean(t, &login.OAuth2Application{ID: 1}).(*login.OAuth2Application)
- user, err := GetUserByID(app.UID)
- assert.NoError(t, err)
- assert.NotNil(t, user)
+
+ testSuccess := func(followerID, followedID int64) {
+ assert.NoError(t, user_model.FollowUser(followerID, followedID))
+ unittest.AssertExistsAndLoadBean(t, &user_model.Follow{UserID: followerID, FollowID: followedID})
+ }
+ testSuccess(4, 2)
+ testSuccess(5, 2)
+
+ assert.NoError(t, user_model.FollowUser(2, 2))
+
+ unittest.CheckConsistencyFor(t, &user_model.User{})
+}
+
+func TestUnfollowUser(t *testing.T) {
+ assert.NoError(t, unittest.PrepareTestDatabase())
+
+ testSuccess := func(followerID, followedID int64) {
+ assert.NoError(t, user_model.UnfollowUser(followerID, followedID))
+ unittest.AssertNotExistsBean(t, &user_model.Follow{UserID: followerID, FollowID: followedID})
+ }
+ testSuccess(4, 2)
+ testSuccess(5, 2)
+ testSuccess(2, 2)
+
+ unittest.CheckConsistencyFor(t, &user_model.User{})
}
func TestUserIsPublicMember(t *testing.T) {
@@ -50,7 +65,7 @@ func TestUserIsPublicMember(t *testing.T) {
}
func testUserIsPublicMember(t *testing.T, uid, orgID int64, expected bool) {
- user, err := GetUserByID(uid)
+ user, err := user_model.GetUserByID(uid)
assert.NoError(t, err)
is, err := IsPublicMembership(orgID, user.ID)
assert.NoError(t, err)
@@ -78,280 +93,39 @@ func TestIsUserOrgOwner(t *testing.T) {
}
func testIsUserOrgOwner(t *testing.T, uid, orgID int64, expected bool) {
- user, err := GetUserByID(uid)
+ user, err := user_model.GetUserByID(uid)
assert.NoError(t, err)
is, err := IsOrganizationOwner(orgID, user.ID)
assert.NoError(t, err)
assert.Equal(t, expected, is)
}
-func TestGetUserEmailsByNames(t *testing.T) {
- assert.NoError(t, unittest.PrepareTestDatabase())
-
- // ignore none active user email
- assert.Equal(t, []string{"user8@example.com"}, GetUserEmailsByNames([]string{"user8", "user9"}))
- assert.Equal(t, []string{"user8@example.com", "user5@example.com"}, GetUserEmailsByNames([]string{"user8", "user5"}))
-
- assert.Equal(t, []string{"user8@example.com"}, GetUserEmailsByNames([]string{"user8", "user7"}))
-}
-
-func TestCanCreateOrganization(t *testing.T) {
- assert.NoError(t, unittest.PrepareTestDatabase())
-
- admin := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
- assert.True(t, admin.CanCreateOrganization())
-
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
- assert.True(t, user.CanCreateOrganization())
- // Disable user create organization permission.
- user.AllowCreateOrganization = false
- assert.False(t, user.CanCreateOrganization())
-
- setting.Admin.DisableRegularOrgCreation = true
- user.AllowCreateOrganization = true
- assert.True(t, admin.CanCreateOrganization())
- assert.False(t, user.CanCreateOrganization())
-}
-
-func TestSearchUsers(t *testing.T) {
- assert.NoError(t, unittest.PrepareTestDatabase())
- testSuccess := func(opts *SearchUserOptions, expectedUserOrOrgIDs []int64) {
- users, _, err := SearchUsers(opts)
- assert.NoError(t, err)
- if assert.Len(t, users, len(expectedUserOrOrgIDs)) {
- for i, expectedID := range expectedUserOrOrgIDs {
- assert.EqualValues(t, expectedID, users[i].ID)
- }
- }
- }
-
- // test orgs
- testOrgSuccess := func(opts *SearchUserOptions, expectedOrgIDs []int64) {
- opts.Type = UserTypeOrganization
- testSuccess(opts, expectedOrgIDs)
- }
-
- testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1, PageSize: 2}},
- []int64{3, 6})
-
- testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 2, PageSize: 2}},
- []int64{7, 17})
-
- testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 3, PageSize: 2}},
- []int64{19, 25})
-
- testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 4, PageSize: 2}},
- []int64{26})
-
- testOrgSuccess(&SearchUserOptions{ListOptions: db.ListOptions{Page: 5, PageSize: 2}},
- []int64{})
-
- // test users
- testUserSuccess := func(opts *SearchUserOptions, expectedUserIDs []int64) {
- opts.Type = UserTypeIndividual
- testSuccess(opts, expectedUserIDs)
- }
-
- testUserSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}},
- []int64{1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32})
-
- testUserSuccess(&SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolFalse},
- []int64{9})
-
- testUserSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue},
- []int64{1, 2, 4, 5, 8, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 28, 29, 30, 32})
-
- testUserSuccess(&SearchUserOptions{Keyword: "user1", OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue},
- []int64{1, 10, 11, 12, 13, 14, 15, 16, 18})
-
- // order by name asc default
- testUserSuccess(&SearchUserOptions{Keyword: "user1", ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue},
- []int64{1, 10, 11, 12, 13, 14, 15, 16, 18})
-
- testUserSuccess(&SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsAdmin: util.OptionalBoolTrue},
- []int64{1})
-
- testUserSuccess(&SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsRestricted: util.OptionalBoolTrue},
- []int64{29, 30})
-
- testUserSuccess(&SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsProhibitLogin: util.OptionalBoolTrue},
- []int64{30})
-
- testUserSuccess(&SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsTwoFactorEnabled: util.OptionalBoolTrue},
- []int64{24})
-}
-
-func TestEmailNotificationPreferences(t *testing.T) {
- assert.NoError(t, unittest.PrepareTestDatabase())
-
- for _, test := range []struct {
- expected string
- userID int64
- }{
- {EmailNotificationsEnabled, 1},
- {EmailNotificationsEnabled, 2},
- {EmailNotificationsOnMention, 3},
- {EmailNotificationsOnMention, 4},
- {EmailNotificationsEnabled, 5},
- {EmailNotificationsEnabled, 6},
- {EmailNotificationsDisabled, 7},
- {EmailNotificationsEnabled, 8},
- {EmailNotificationsOnMention, 9},
- } {
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: test.userID}).(*User)
- assert.Equal(t, test.expected, user.EmailNotifications())
-
- // Try all possible settings
- assert.NoError(t, SetEmailNotifications(user, EmailNotificationsEnabled))
- assert.Equal(t, EmailNotificationsEnabled, user.EmailNotifications())
-
- assert.NoError(t, SetEmailNotifications(user, EmailNotificationsOnMention))
- assert.Equal(t, EmailNotificationsOnMention, user.EmailNotifications())
-
- assert.NoError(t, SetEmailNotifications(user, EmailNotificationsDisabled))
- assert.Equal(t, EmailNotificationsDisabled, user.EmailNotifications())
- }
-}
-
-func TestHashPasswordDeterministic(t *testing.T) {
- b := make([]byte, 16)
- u := &User{}
- algos := []string{"argon2", "pbkdf2", "scrypt", "bcrypt"}
- for j := 0; j < len(algos); j++ {
- u.PasswdHashAlgo = algos[j]
- for i := 0; i < 50; i++ {
- // generate a random password
- rand.Read(b)
- pass := string(b)
-
- // save the current password in the user - hash it and store the result
- u.SetPassword(pass)
- r1 := u.Passwd
-
- // run again
- u.SetPassword(pass)
- r2 := u.Passwd
-
- assert.NotEqual(t, r1, r2)
- assert.True(t, u.ValidatePassword(pass))
- }
- }
-}
-
-func BenchmarkHashPassword(b *testing.B) {
- // BenchmarkHashPassword ensures that it takes a reasonable amount of time
- // to hash a password - in order to protect from brute-force attacks.
- pass := "password1337"
- u := &User{Passwd: pass}
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- u.SetPassword(pass)
- }
-}
-
func TestGetOrgRepositoryIDs(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- user2 := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
- user4 := unittest.AssertExistsAndLoadBean(t, &User{ID: 4}).(*User)
- user5 := unittest.AssertExistsAndLoadBean(t, &User{ID: 5}).(*User)
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
+ user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User)
+ user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User)
- accessibleRepos, err := user2.GetOrgRepositoryIDs()
+ accessibleRepos, err := GetOrgRepositoryIDs(user2)
assert.NoError(t, err)
// User 2's team has access to private repos 3, 5, repo 32 is a public repo of the organization
assert.Equal(t, []int64{3, 5, 23, 24, 32}, accessibleRepos)
- accessibleRepos, err = user4.GetOrgRepositoryIDs()
+ accessibleRepos, err = GetOrgRepositoryIDs(user4)
assert.NoError(t, err)
// User 4's team has access to private repo 3, repo 32 is a public repo of the organization
assert.Equal(t, []int64{3, 32}, accessibleRepos)
- accessibleRepos, err = user5.GetOrgRepositoryIDs()
+ accessibleRepos, err = GetOrgRepositoryIDs(user5)
assert.NoError(t, err)
// User 5's team has no access to any repo
assert.Len(t, accessibleRepos, 0)
}
-func TestNewGitSig(t *testing.T) {
- users := make([]*User, 0, 20)
- err := db.GetEngine(db.DefaultContext).Find(&users)
- assert.NoError(t, err)
-
- for _, user := range users {
- sig := user.NewGitSig()
- assert.NotContains(t, sig.Name, "<")
- assert.NotContains(t, sig.Name, ">")
- assert.NotContains(t, sig.Name, "\n")
- assert.NotEqual(t, len(strings.TrimSpace(sig.Name)), 0)
- }
-}
-
-func TestDisplayName(t *testing.T) {
- users := make([]*User, 0, 20)
- err := db.GetEngine(db.DefaultContext).Find(&users)
- assert.NoError(t, err)
-
- for _, user := range users {
- displayName := user.DisplayName()
- assert.Equal(t, strings.TrimSpace(displayName), displayName)
- if len(strings.TrimSpace(user.FullName)) == 0 {
- assert.Equal(t, user.Name, displayName)
- }
- assert.NotEqual(t, len(strings.TrimSpace(displayName)), 0)
- }
-}
-
-func TestCreateUserInvalidEmail(t *testing.T) {
- user := &User{
- Name: "GiteaBot",
- Email: "GiteaBot@gitea.io\r\n",
- Passwd: ";p['////..-++']",
- IsAdmin: false,
- Theme: setting.UI.DefaultTheme,
- MustChangePassword: false,
- }
-
- err := CreateUser(user)
- assert.Error(t, err)
- assert.True(t, user_model.IsErrEmailInvalid(err))
-}
-
-func TestGetUserIDsByNames(t *testing.T) {
- assert.NoError(t, unittest.PrepareTestDatabase())
-
- // ignore non existing
- IDs, err := GetUserIDsByNames([]string{"user1", "user2", "none_existing_user"}, true)
- assert.NoError(t, err)
- assert.Equal(t, []int64{1, 2}, IDs)
-
- // ignore non existing
- IDs, err = GetUserIDsByNames([]string{"user1", "do_not_exist"}, false)
- assert.Error(t, err)
- assert.Equal(t, []int64(nil), IDs)
-}
-
-func TestGetMaileableUsersByIDs(t *testing.T) {
- assert.NoError(t, unittest.PrepareTestDatabase())
-
- results, err := GetMaileableUsersByIDs([]int64{1, 4}, false)
- assert.NoError(t, err)
- assert.Len(t, results, 1)
- if len(results) > 1 {
- assert.Equal(t, results[0].ID, 1)
- }
-
- results, err = GetMaileableUsersByIDs([]int64{1, 4}, true)
- assert.NoError(t, err)
- assert.Len(t, results, 2)
- if len(results) > 2 {
- assert.Equal(t, results[0].ID, 1)
- assert.Equal(t, results[1].ID, 4)
- }
-}
-
func TestAddLdapSSHPublicKeys(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
s := &login.Source{ID: 1}
testCases := []struct {
@@ -415,118 +189,3 @@ ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ib
}
}
}
-
-func TestUpdateUser(t *testing.T) {
- assert.NoError(t, unittest.PrepareTestDatabase())
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
-
- user.KeepActivityPrivate = true
- assert.NoError(t, UpdateUser(user))
- user = unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
- assert.True(t, user.KeepActivityPrivate)
-
- setting.Service.AllowedUserVisibilityModesSlice = []bool{true, false, false}
- user.KeepActivityPrivate = false
- user.Visibility = structs.VisibleTypePrivate
- assert.Error(t, UpdateUser(user))
- user = unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
- assert.True(t, user.KeepActivityPrivate)
-
- user.Email = "no mail@mail.org"
- assert.Error(t, UpdateUser(user))
-}
-
-func TestNewUserRedirect(t *testing.T) {
- // redirect to a completely new name
- assert.NoError(t, unittest.PrepareTestDatabase())
-
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
- assert.NoError(t, user_model.NewUserRedirect(db.DefaultContext, user.ID, user.Name, "newusername"))
-
- unittest.AssertExistsAndLoadBean(t, &user_model.Redirect{
- LowerName: user.LowerName,
- RedirectUserID: user.ID,
- })
- unittest.AssertExistsAndLoadBean(t, &user_model.Redirect{
- LowerName: "olduser1",
- RedirectUserID: user.ID,
- })
-}
-
-func TestNewUserRedirect2(t *testing.T) {
- // redirect to previously used name
- assert.NoError(t, unittest.PrepareTestDatabase())
-
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
- assert.NoError(t, user_model.NewUserRedirect(db.DefaultContext, user.ID, user.Name, "olduser1"))
-
- unittest.AssertExistsAndLoadBean(t, &user_model.Redirect{
- LowerName: user.LowerName,
- RedirectUserID: user.ID,
- })
- unittest.AssertNotExistsBean(t, &user_model.Redirect{
- LowerName: "olduser1",
- RedirectUserID: user.ID,
- })
-}
-
-func TestNewUserRedirect3(t *testing.T) {
- // redirect for a previously-unredirected user
- assert.NoError(t, unittest.PrepareTestDatabase())
-
- user := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
- assert.NoError(t, user_model.NewUserRedirect(db.DefaultContext, user.ID, user.Name, "newusername"))
-
- unittest.AssertExistsAndLoadBean(t, &user_model.Redirect{
- LowerName: user.LowerName,
- RedirectUserID: user.ID,
- })
-}
-
-func TestFollowUser(t *testing.T) {
- assert.NoError(t, unittest.PrepareTestDatabase())
-
- testSuccess := func(followerID, followedID int64) {
- assert.NoError(t, user_model.FollowUser(followerID, followedID))
- unittest.AssertExistsAndLoadBean(t, &user_model.Follow{UserID: followerID, FollowID: followedID})
- }
- testSuccess(4, 2)
- testSuccess(5, 2)
-
- assert.NoError(t, user_model.FollowUser(2, 2))
-
- unittest.CheckConsistencyFor(t, &User{})
-}
-
-func TestUnfollowUser(t *testing.T) {
- assert.NoError(t, unittest.PrepareTestDatabase())
-
- testSuccess := func(followerID, followedID int64) {
- assert.NoError(t, user_model.UnfollowUser(followerID, followedID))
- unittest.AssertNotExistsBean(t, &user_model.Follow{UserID: followerID, FollowID: followedID})
- }
- testSuccess(4, 2)
- testSuccess(5, 2)
- testSuccess(2, 2)
-
- unittest.CheckConsistencyFor(t, &User{})
-}
-
-func TestGetUserByOpenID(t *testing.T) {
- assert.NoError(t, unittest.PrepareTestDatabase())
-
- _, err := GetUserByOpenID("https://unknown")
- if assert.Error(t, err) {
- assert.True(t, IsErrUserNotExist(err))
- }
-
- user, err := GetUserByOpenID("https://user1.domain1.tld")
- if assert.NoError(t, err) {
- assert.Equal(t, int64(1), user.ID)
- }
-
- user, err = GetUserByOpenID("https://domain1.tld/user2/")
- if assert.NoError(t, err) {
- assert.Equal(t, int64(2), user.ID)
- }
-}
diff --git a/models/userlist.go b/models/userlist.go
index aebdb4f48c..ae39de3da4 100644
--- a/models/userlist.go
+++ b/models/userlist.go
@@ -9,12 +9,13 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/login"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
)
// UserList is a list of user.
// This type provide valuable methods to retrieve information for a group of users efficiently.
-type UserList []*User
+type UserList []*user_model.User
func (users UserList) getUserIDs() []int64 {
userIDs := make([]int64, len(users))
@@ -95,3 +96,15 @@ func (users UserList) loadTwoFactorStatus(e db.Engine) (map[int64]*login.TwoFact
}
return tokenMaps, nil
}
+
+// GetUsersByIDs returns all resolved users from a list of Ids.
+func GetUsersByIDs(ids []int64) (UserList, error) {
+ ous := make([]*user_model.User, 0, len(ids))
+ if len(ids) == 0 {
+ return ous, nil
+ }
+ err := db.GetEngine(db.DefaultContext).In("id", ids).
+ Asc("name").
+ Find(&ous)
+ return ous, err
+}
diff --git a/models/wiki.go b/models/wiki.go
index beab48d45a..f80696542e 100644
--- a/models/wiki.go
+++ b/models/wiki.go
@@ -9,6 +9,7 @@ import (
"path/filepath"
"strings"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/util"
)
@@ -20,7 +21,7 @@ func (repo *Repository) WikiCloneLink() *CloneLink {
// WikiPath returns wiki data path by given user and repository name.
func WikiPath(userName, repoName string) string {
- return filepath.Join(UserPath(userName), strings.ToLower(repoName)+".wiki.git")
+ return filepath.Join(user_model.UserPath(userName), strings.ToLower(repoName)+".wiki.git")
}
// WikiPath returns wiki data path for given repository.