diff options
Diffstat (limited to 'models')
-rw-r--r-- | models/activities/action.go | 6 | ||||
-rw-r--r-- | models/activities/action_list.go | 24 | ||||
-rw-r--r-- | models/db/search.go | 4 | ||||
-rw-r--r-- | models/issues/issue_search.go | 31 | ||||
-rw-r--r-- | models/issues/issue_test.go | 3 | ||||
-rw-r--r-- | models/migrations/migrations.go | 1 | ||||
-rw-r--r-- | models/migrations/v1_24/v317.go | 56 | ||||
-rw-r--r-- | models/repo/repo.go | 20 | ||||
-rw-r--r-- | models/repo/upload.go | 6 | ||||
-rw-r--r-- | models/user/user_system.go | 10 |
10 files changed, 120 insertions, 41 deletions
diff --git a/models/activities/action.go b/models/activities/action.go index c16c49c0ac..c89ba3e14e 100644 --- a/models/activities/action.go +++ b/models/activities/action.go @@ -172,7 +172,10 @@ func (a *Action) TableIndices() []*schemas.Index { cuIndex := schemas.NewIndex("c_u", schemas.IndexType) cuIndex.AddColumn("user_id", "is_deleted") - indices := []*schemas.Index{actUserIndex, repoIndex, cudIndex, cuIndex} + actUserUserIndex := schemas.NewIndex("au_c_u", schemas.IndexType) + actUserUserIndex.AddColumn("act_user_id", "created_unix", "user_id") + + indices := []*schemas.Index{actUserIndex, repoIndex, cudIndex, cuIndex, actUserUserIndex} return indices } @@ -442,6 +445,7 @@ type GetFeedsOptions struct { OnlyPerformedBy bool // only actions performed by requested user IncludeDeleted bool // include deleted actions Date string // the day we want activity for: YYYY-MM-DD + DontCount bool // do counting in GetFeeds } // ActivityReadable return whether doer can read activities of user diff --git a/models/activities/action_list.go b/models/activities/action_list.go index f7ea48f03e..6789ebcb99 100644 --- a/models/activities/action_list.go +++ b/models/activities/action_list.go @@ -243,7 +243,11 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err sess := db.GetEngine(ctx).Where(cond) sess = db.SetSessionPagination(sess, &opts) - count, err = sess.Desc("`action`.created_unix").FindAndCount(&actions) + if opts.DontCount { + err = sess.Desc("`action`.created_unix").Find(&actions) + } else { + count, err = sess.Desc("`action`.created_unix").FindAndCount(&actions) + } if err != nil { return nil, 0, fmt.Errorf("FindAndCount: %w", err) } @@ -257,11 +261,13 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err return nil, 0, fmt.Errorf("Find(actionsIDs): %w", err) } - count, err = db.GetEngine(ctx).Where(cond). - Table("action"). - Cols("`action`.id").Count() - if err != nil { - return nil, 0, fmt.Errorf("Count: %w", err) + if !opts.DontCount { + count, err = db.GetEngine(ctx).Where(cond). + Table("action"). + Cols("`action`.id").Count() + if err != nil { + return nil, 0, fmt.Errorf("Count: %w", err) + } } if err := db.GetEngine(ctx).In("`action`.id", actionIDs).Desc("`action`.created_unix").Find(&actions); err != nil { @@ -275,3 +281,9 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err return actions, count, nil } + +func CountUserFeeds(ctx context.Context, userID int64) (int64, error) { + return db.GetEngine(ctx).Where("user_id = ?", userID). + And("is_deleted = ?", false). + Count(&Action{}) +} diff --git a/models/db/search.go b/models/db/search.go index e0a1b6bde9..44d54f21fc 100644 --- a/models/db/search.go +++ b/models/db/search.go @@ -29,7 +29,3 @@ const ( // NoConditionID means a condition to filter the records which don't match any id. // eg: "milestone_id=-1" means "find the items without any milestone. const NoConditionID int64 = -1 - -// NonExistingID means a condition to match no result (eg: a non-existing user) -// It doesn't use -1 or -2 because they are used as builtin users. -const NonExistingID int64 = -1000000 diff --git a/models/issues/issue_search.go b/models/issues/issue_search.go index 694b918755..737b69f154 100644 --- a/models/issues/issue_search.go +++ b/models/issues/issue_search.go @@ -27,8 +27,8 @@ type IssuesOptions struct { //nolint RepoIDs []int64 // overwrites RepoCond if the length is not 0 AllPublic bool // include also all public repositories RepoCond builder.Cond - AssigneeID optional.Option[int64] - PosterID optional.Option[int64] + AssigneeID string // "(none)" or "(any)" or a user ID + PosterID string // "(none)" or "(any)" or a user ID MentionedID int64 ReviewRequestedID int64 ReviewedID int64 @@ -356,26 +356,25 @@ func issuePullAccessibleRepoCond(repoIDstr string, userID int64, owner *user_mod return cond } -func applyAssigneeCondition(sess *xorm.Session, assigneeID optional.Option[int64]) { +func applyAssigneeCondition(sess *xorm.Session, assigneeID string) { // old logic: 0 is also treated as "not filtering assignee", because the "assignee" was read as FormInt64 - if !assigneeID.Has() || assigneeID.Value() == 0 { - return - } - if assigneeID.Value() == db.NoConditionID { + if assigneeID == "(none)" { sess.Where("issue.id NOT IN (SELECT issue_id FROM issue_assignees)") - } else { + } else if assigneeID == "(any)" { + sess.Where("issue.id IN (SELECT issue_id FROM issue_assignees)") + } else if assigneeIDInt64, _ := strconv.ParseInt(assigneeID, 10, 64); assigneeIDInt64 > 0 { sess.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id"). - And("issue_assignees.assignee_id = ?", assigneeID.Value()) + And("issue_assignees.assignee_id = ?", assigneeIDInt64) } } -func applyPosterCondition(sess *xorm.Session, posterID optional.Option[int64]) { - if !posterID.Has() { - return - } - // poster doesn't need to support db.NoConditionID(-1), so just use the value as-is - if posterID.Has() { - sess.And("issue.poster_id=?", posterID.Value()) +func applyPosterCondition(sess *xorm.Session, posterID string) { + // Actually every issue has a poster. + // The "(none)" is for internal usage only: when doer tries to search non-existing user as poster, use "(none)" to return empty result. + if posterID == "(none)" { + sess.And("issue.poster_id=0") + } else if posterIDInt64, _ := strconv.ParseInt(posterID, 10, 64); posterIDInt64 > 0 { + sess.And("issue.poster_id=?", posterIDInt64) } } diff --git a/models/issues/issue_test.go b/models/issues/issue_test.go index 3f76a81bb6..c32aa26b2b 100644 --- a/models/issues/issue_test.go +++ b/models/issues/issue_test.go @@ -15,7 +15,6 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" "github.com/stretchr/testify/assert" @@ -155,7 +154,7 @@ func TestIssues(t *testing.T) { }{ { issues_model.IssuesOptions{ - AssigneeID: optional.Some(int64(1)), + AssigneeID: "1", SortType: "oldest", }, []int64{1, 6}, diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 297c50a267..572738013f 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -377,6 +377,7 @@ func prepareMigrationTasks() []*migration { newMigration(314, "Update OwnerID as zero for repository level action tables", v1_24.UpdateOwnerIDOfRepoLevelActionsTables), newMigration(315, "Add Ephemeral to ActionRunner", v1_24.AddEphemeralToActionRunner), newMigration(316, "Add description for secrets and variables", v1_24.AddDescriptionForSecretsAndVariables), + newMigration(317, "Add new index for action for heatmap", v1_24.AddNewIndexForUserDashboard), } return preparedMigrations } diff --git a/models/migrations/v1_24/v317.go b/models/migrations/v1_24/v317.go new file mode 100644 index 0000000000..3da5a4a078 --- /dev/null +++ b/models/migrations/v1_24/v317.go @@ -0,0 +1,56 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_24 //nolint + +import ( + "code.gitea.io/gitea/modules/timeutil" + + "xorm.io/xorm" + "xorm.io/xorm/schemas" +) + +type improveActionTableIndicesAction struct { + ID int64 `xorm:"pk autoincr"` + UserID int64 `xorm:"INDEX"` // Receiver user id. + OpType int + ActUserID int64 // Action user id. + RepoID int64 + CommentID int64 `xorm:"INDEX"` + IsDeleted bool `xorm:"NOT NULL DEFAULT false"` + RefName string + IsPrivate bool `xorm:"NOT NULL DEFAULT false"` + Content string `xorm:"TEXT"` + CreatedUnix timeutil.TimeStamp `xorm:"created"` +} + +// TableName sets the name of this table +func (*improveActionTableIndicesAction) TableName() string { + return "action" +} + +// TableIndices implements xorm's TableIndices interface +func (a *improveActionTableIndicesAction) TableIndices() []*schemas.Index { + repoIndex := schemas.NewIndex("r_u_d", schemas.IndexType) + repoIndex.AddColumn("repo_id", "user_id", "is_deleted") + + actUserIndex := schemas.NewIndex("au_r_c_u_d", schemas.IndexType) + actUserIndex.AddColumn("act_user_id", "repo_id", "created_unix", "user_id", "is_deleted") + + cudIndex := schemas.NewIndex("c_u_d", schemas.IndexType) + cudIndex.AddColumn("created_unix", "user_id", "is_deleted") + + cuIndex := schemas.NewIndex("c_u", schemas.IndexType) + cuIndex.AddColumn("user_id", "is_deleted") + + actUserUserIndex := schemas.NewIndex("au_c_u", schemas.IndexType) + actUserUserIndex.AddColumn("act_user_id", "created_unix", "user_id") + + indices := []*schemas.Index{actUserIndex, repoIndex, cudIndex, cuIndex, actUserUserIndex} + + return indices +} + +func AddNewIndexForUserDashboard(x *xorm.Engine) error { + return x.Sync(new(improveActionTableIndicesAction)) +} diff --git a/models/repo/repo.go b/models/repo/repo.go index 13473699f3..a8732f60bf 100644 --- a/models/repo/repo.go +++ b/models/repo/repo.go @@ -215,12 +215,24 @@ func init() { db.RegisterModel(new(Repository)) } -func (repo *Repository) GetName() string { - return repo.Name +func RelativePath(ownerName, repoName string) string { + return strings.ToLower(ownerName) + "/" + strings.ToLower(repoName) + ".git" } -func (repo *Repository) GetOwnerName() string { - return repo.OwnerName +// RelativePath should be an unix style path like username/reponame.git +func (repo *Repository) RelativePath() string { + return RelativePath(repo.OwnerName, repo.Name) +} + +type StorageRepo string + +// RelativePath should be an unix style path like username/reponame.git +func (sr StorageRepo) RelativePath() string { + return string(sr) +} + +func (repo *Repository) WikiStorageRepo() StorageRepo { + return StorageRepo(strings.ToLower(repo.OwnerName) + "/" + strings.ToLower(repo.Name) + ".wiki.git") } // SanitizedOriginalURL returns a sanitized OriginalURL diff --git a/models/repo/upload.go b/models/repo/upload.go index 18834f6b83..cae11df96a 100644 --- a/models/repo/upload.go +++ b/models/repo/upload.go @@ -10,7 +10,7 @@ import ( "io" "mime/multipart" "os" - "path" + "path/filepath" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/log" @@ -53,7 +53,7 @@ func init() { // UploadLocalPath returns where uploads is stored in local file system based on given UUID. func UploadLocalPath(uuid string) string { - return path.Join(setting.Repository.Upload.TempPath, uuid[0:1], uuid[1:2], uuid) + return filepath.Join(setting.Repository.Upload.TempPath, uuid[0:1], uuid[1:2], uuid) } // LocalPath returns where uploads are temporarily stored in local file system. @@ -69,7 +69,7 @@ func NewUpload(ctx context.Context, name string, buf []byte, file multipart.File } localPath := upload.LocalPath() - if err = os.MkdirAll(path.Dir(localPath), os.ModePerm); err != nil { + if err = os.MkdirAll(filepath.Dir(localPath), os.ModePerm); err != nil { return nil, fmt.Errorf("MkdirAll: %w", err) } diff --git a/models/user/user_system.go b/models/user/user_system.go index 6fbfd9e69e..e07274d291 100644 --- a/models/user/user_system.go +++ b/models/user/user_system.go @@ -10,8 +10,8 @@ import ( ) const ( - GhostUserID = -1 - GhostUserName = "Ghost" + GhostUserID int64 = -1 + GhostUserName = "Ghost" ) // NewGhostUser creates and returns a fake user for someone has deleted their account. @@ -36,9 +36,9 @@ func (u *User) IsGhost() bool { } const ( - ActionsUserID = -2 - ActionsUserName = "gitea-actions" - ActionsUserEmail = "teabot@gitea.io" + ActionsUserID int64 = -2 + ActionsUserName = "gitea-actions" + ActionsUserEmail = "teabot@gitea.io" ) func IsGiteaActionsUserName(name string) bool { |