Skip to content

Commit fde02d1

Browse files
committed
Merge remote-tracking branch 'giteaofficial/main'
* giteaofficial/main: [skip ci] Updated translations via Crowdin Only use prev and next buttons for pagination on user dashboard (go-gitea#33981) update jwt and redis packages (go-gitea#33984) [skip ci] Updated translations via Crowdin Improve oauth2 error handling (go-gitea#33969) [skip ci] Updated translations via Crowdin Cover `go.mod` and `go.sum` in `.editorconfig` (go-gitea#33960) Drop timeout for requests made to the internal hook api (go-gitea#33947) Fix file name could not be searched if the file was not a text file when using the Bleve indexer (go-gitea#33959) Fix oauth2 auth and UI (go-gitea#33961) Allow filtering issues by any assignee (go-gitea#33343) Optimize total count of feed when loading activities in user dashboard. (go-gitea#33841) Extract code to their own functions for push update (go-gitea#33944) Optimize heatmap query (go-gitea#33853)
2 parents c64dc37 + 08510ad commit fde02d1

Some content is hidden

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

69 files changed

+570
-357
lines changed

.editorconfig

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ insert_final_newline = true
1212
[*.{go,tmpl,html}]
1313
indent_style = tab
1414

15+
[go.*]
16+
indent_style = tab
17+
1518
[templates/custom/*.tmpl]
1619
insert_final_newline = false
1720

go.mod

+3-3
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ require (
6464
github.com/gobwas/glob v0.2.3
6565
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f
6666
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
67-
github.com/golang-jwt/jwt/v5 v5.2.1
67+
github.com/golang-jwt/jwt/v5 v5.2.2
6868
github.com/google/go-github/v61 v61.0.0
6969
github.com/google/licenseclassifier/v2 v2.0.0
7070
github.com/google/pprof v0.0.0-20250208200701-d0013a598941
@@ -99,7 +99,7 @@ require (
9999
github.com/pquerna/otp v1.4.0
100100
github.com/prometheus/client_golang v1.21.0
101101
github.com/quasoft/websspi v1.1.2
102-
github.com/redis/go-redis/v9 v9.7.0
102+
github.com/redis/go-redis/v9 v9.7.3
103103
github.com/robfig/cron/v3 v3.0.1
104104
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1
105105
github.com/sassoftware/go-rpmutils v0.4.0
@@ -215,7 +215,7 @@ require (
215215
github.com/go-openapi/validate v0.24.0 // indirect
216216
github.com/go-webauthn/x v0.1.16 // indirect
217217
github.com/goccy/go-json v0.10.5 // indirect
218-
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
218+
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
219219
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
220220
github.com/golang-sql/sqlexp v0.1.0 // indirect
221221
github.com/golang/geo v0.0.0-20230421003525-6adc56603217 // indirect

go.sum

+6-5
Original file line numberDiff line numberDiff line change
@@ -374,10 +374,11 @@ github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7w
374374
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14=
375375
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 h1:UjoPNDAQ5JPCjlxoJd6K8ALZqSDDhk2ymieAZOVaDg0=
376376
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU=
377-
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
378377
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
379-
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
380-
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
378+
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
379+
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
380+
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
381+
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
381382
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
382383
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
383384
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
@@ -655,8 +656,8 @@ github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoG
655656
github.com/quasoft/websspi v1.1.2 h1:/mA4w0LxWlE3novvsoEL6BBA1WnjJATbjkh1kFrTidw=
656657
github.com/quasoft/websspi v1.1.2/go.mod h1:HmVdl939dQ0WIXZhyik+ARdI03M6bQzaSEKcgpFmewk=
657658
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
658-
github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
659-
github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
659+
github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
660+
github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
660661
github.com/redis/rueidis v1.0.19 h1:s65oWtotzlIFN8eMPhyYwxlwLR1lUdhza2KtWprKYSo=
661662
github.com/redis/rueidis v1.0.19/go.mod h1:8B+r5wdnjwK3lTFml5VtxjzGOQAC+5UmujoD12pDrEo=
662663
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=

models/activities/action.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,10 @@ func (a *Action) TableIndices() []*schemas.Index {
172172
cuIndex := schemas.NewIndex("c_u", schemas.IndexType)
173173
cuIndex.AddColumn("user_id", "is_deleted")
174174

175-
indices := []*schemas.Index{actUserIndex, repoIndex, cudIndex, cuIndex}
175+
actUserUserIndex := schemas.NewIndex("au_c_u", schemas.IndexType)
176+
actUserUserIndex.AddColumn("act_user_id", "created_unix", "user_id")
177+
178+
indices := []*schemas.Index{actUserIndex, repoIndex, cudIndex, cuIndex, actUserUserIndex}
176179

177180
return indices
178181
}
@@ -442,6 +445,7 @@ type GetFeedsOptions struct {
442445
OnlyPerformedBy bool // only actions performed by requested user
443446
IncludeDeleted bool // include deleted actions
444447
Date string // the day we want activity for: YYYY-MM-DD
448+
DontCount bool // do counting in GetFeeds
445449
}
446450

447451
// ActivityReadable return whether doer can read activities of user

models/activities/action_list.go

+18-6
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,11 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
243243
sess := db.GetEngine(ctx).Where(cond)
244244
sess = db.SetSessionPagination(sess, &opts)
245245

246-
count, err = sess.Desc("`action`.created_unix").FindAndCount(&actions)
246+
if opts.DontCount {
247+
err = sess.Desc("`action`.created_unix").Find(&actions)
248+
} else {
249+
count, err = sess.Desc("`action`.created_unix").FindAndCount(&actions)
250+
}
247251
if err != nil {
248252
return nil, 0, fmt.Errorf("FindAndCount: %w", err)
249253
}
@@ -257,11 +261,13 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
257261
return nil, 0, fmt.Errorf("Find(actionsIDs): %w", err)
258262
}
259263

260-
count, err = db.GetEngine(ctx).Where(cond).
261-
Table("action").
262-
Cols("`action`.id").Count()
263-
if err != nil {
264-
return nil, 0, fmt.Errorf("Count: %w", err)
264+
if !opts.DontCount {
265+
count, err = db.GetEngine(ctx).Where(cond).
266+
Table("action").
267+
Cols("`action`.id").Count()
268+
if err != nil {
269+
return nil, 0, fmt.Errorf("Count: %w", err)
270+
}
265271
}
266272

267273
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
275281

276282
return actions, count, nil
277283
}
284+
285+
func CountUserFeeds(ctx context.Context, userID int64) (int64, error) {
286+
return db.GetEngine(ctx).Where("user_id = ?", userID).
287+
And("is_deleted = ?", false).
288+
Count(&Action{})
289+
}

models/db/search.go

-4
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,3 @@ const (
2929
// NoConditionID means a condition to filter the records which don't match any id.
3030
// eg: "milestone_id=-1" means "find the items without any milestone.
3131
const NoConditionID int64 = -1
32-
33-
// NonExistingID means a condition to match no result (eg: a non-existing user)
34-
// It doesn't use -1 or -2 because they are used as builtin users.
35-
const NonExistingID int64 = -1000000

models/issues/issue_search.go

+15-16
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ type IssuesOptions struct { //nolint
2727
RepoIDs []int64 // overwrites RepoCond if the length is not 0
2828
AllPublic bool // include also all public repositories
2929
RepoCond builder.Cond
30-
AssigneeID optional.Option[int64]
31-
PosterID optional.Option[int64]
30+
AssigneeID string // "(none)" or "(any)" or a user ID
31+
PosterID string // "(none)" or "(any)" or a user ID
3232
MentionedID int64
3333
ReviewRequestedID int64
3434
ReviewedID int64
@@ -356,26 +356,25 @@ func issuePullAccessibleRepoCond(repoIDstr string, userID int64, owner *user_mod
356356
return cond
357357
}
358358

359-
func applyAssigneeCondition(sess *xorm.Session, assigneeID optional.Option[int64]) {
359+
func applyAssigneeCondition(sess *xorm.Session, assigneeID string) {
360360
// old logic: 0 is also treated as "not filtering assignee", because the "assignee" was read as FormInt64
361-
if !assigneeID.Has() || assigneeID.Value() == 0 {
362-
return
363-
}
364-
if assigneeID.Value() == db.NoConditionID {
361+
if assigneeID == "(none)" {
365362
sess.Where("issue.id NOT IN (SELECT issue_id FROM issue_assignees)")
366-
} else {
363+
} else if assigneeID == "(any)" {
364+
sess.Where("issue.id IN (SELECT issue_id FROM issue_assignees)")
365+
} else if assigneeIDInt64, _ := strconv.ParseInt(assigneeID, 10, 64); assigneeIDInt64 > 0 {
367366
sess.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
368-
And("issue_assignees.assignee_id = ?", assigneeID.Value())
367+
And("issue_assignees.assignee_id = ?", assigneeIDInt64)
369368
}
370369
}
371370

372-
func applyPosterCondition(sess *xorm.Session, posterID optional.Option[int64]) {
373-
if !posterID.Has() {
374-
return
375-
}
376-
// poster doesn't need to support db.NoConditionID(-1), so just use the value as-is
377-
if posterID.Has() {
378-
sess.And("issue.poster_id=?", posterID.Value())
371+
func applyPosterCondition(sess *xorm.Session, posterID string) {
372+
// Actually every issue has a poster.
373+
// The "(none)" is for internal usage only: when doer tries to search non-existing user as poster, use "(none)" to return empty result.
374+
if posterID == "(none)" {
375+
sess.And("issue.poster_id=0")
376+
} else if posterIDInt64, _ := strconv.ParseInt(posterID, 10, 64); posterIDInt64 > 0 {
377+
sess.And("issue.poster_id=?", posterIDInt64)
379378
}
380379
}
381380

models/issues/issue_test.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515
repo_model "code.gitea.io/gitea/models/repo"
1616
"code.gitea.io/gitea/models/unittest"
1717
user_model "code.gitea.io/gitea/models/user"
18-
"code.gitea.io/gitea/modules/optional"
1918
"code.gitea.io/gitea/modules/setting"
2019

2120
"github.com/stretchr/testify/assert"
@@ -155,7 +154,7 @@ func TestIssues(t *testing.T) {
155154
}{
156155
{
157156
issues_model.IssuesOptions{
158-
AssigneeID: optional.Some(int64(1)),
157+
AssigneeID: "1",
159158
SortType: "oldest",
160159
},
161160
[]int64{1, 6},

models/migrations/migrations.go

+1
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ func prepareMigrationTasks() []*migration {
377377
newMigration(314, "Update OwnerID as zero for repository level action tables", v1_24.UpdateOwnerIDOfRepoLevelActionsTables),
378378
newMigration(315, "Add Ephemeral to ActionRunner", v1_24.AddEphemeralToActionRunner),
379379
newMigration(316, "Add description for secrets and variables", v1_24.AddDescriptionForSecretsAndVariables),
380+
newMigration(317, "Add new index for action for heatmap", v1_24.AddNewIndexForUserDashboard),
380381
}
381382
return preparedMigrations
382383
}

models/migrations/v1_24/v317.go

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright 2025 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package v1_24 //nolint
5+
6+
import (
7+
"code.gitea.io/gitea/modules/timeutil"
8+
9+
"xorm.io/xorm"
10+
"xorm.io/xorm/schemas"
11+
)
12+
13+
type improveActionTableIndicesAction struct {
14+
ID int64 `xorm:"pk autoincr"`
15+
UserID int64 `xorm:"INDEX"` // Receiver user id.
16+
OpType int
17+
ActUserID int64 // Action user id.
18+
RepoID int64
19+
CommentID int64 `xorm:"INDEX"`
20+
IsDeleted bool `xorm:"NOT NULL DEFAULT false"`
21+
RefName string
22+
IsPrivate bool `xorm:"NOT NULL DEFAULT false"`
23+
Content string `xorm:"TEXT"`
24+
CreatedUnix timeutil.TimeStamp `xorm:"created"`
25+
}
26+
27+
// TableName sets the name of this table
28+
func (*improveActionTableIndicesAction) TableName() string {
29+
return "action"
30+
}
31+
32+
// TableIndices implements xorm's TableIndices interface
33+
func (a *improveActionTableIndicesAction) TableIndices() []*schemas.Index {
34+
repoIndex := schemas.NewIndex("r_u_d", schemas.IndexType)
35+
repoIndex.AddColumn("repo_id", "user_id", "is_deleted")
36+
37+
actUserIndex := schemas.NewIndex("au_r_c_u_d", schemas.IndexType)
38+
actUserIndex.AddColumn("act_user_id", "repo_id", "created_unix", "user_id", "is_deleted")
39+
40+
cudIndex := schemas.NewIndex("c_u_d", schemas.IndexType)
41+
cudIndex.AddColumn("created_unix", "user_id", "is_deleted")
42+
43+
cuIndex := schemas.NewIndex("c_u", schemas.IndexType)
44+
cuIndex.AddColumn("user_id", "is_deleted")
45+
46+
actUserUserIndex := schemas.NewIndex("au_c_u", schemas.IndexType)
47+
actUserUserIndex.AddColumn("act_user_id", "created_unix", "user_id")
48+
49+
indices := []*schemas.Index{actUserIndex, repoIndex, cudIndex, cuIndex, actUserUserIndex}
50+
51+
return indices
52+
}
53+
54+
func AddNewIndexForUserDashboard(x *xorm.Engine) error {
55+
return x.Sync(new(improveActionTableIndicesAction))
56+
}

modules/indexer/code/bleve/bleve.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@ func (b *Indexer) addUpdate(ctx context.Context, batchWriter git.WriteCloserErro
191191
return err
192192
} else if !typesniffer.DetectContentType(fileContents).IsText() {
193193
// FIXME: UTF-16 files will probably fail here
194-
return nil
194+
// Even if the file is not recognized as a "text file", we could still put its name into the indexers to make the filename become searchable, while leave the content to empty.
195+
fileContents = nil
195196
}
196197

197198
if _, err = batchReader.Discard(1); err != nil {

modules/indexer/issues/bleve/bleve.go

+14-4
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ package bleve
55

66
import (
77
"context"
8+
"strconv"
89

910
"code.gitea.io/gitea/modules/indexer"
1011
indexer_internal "code.gitea.io/gitea/modules/indexer/internal"
1112
inner_bleve "code.gitea.io/gitea/modules/indexer/internal/bleve"
1213
"code.gitea.io/gitea/modules/indexer/issues/internal"
14+
"code.gitea.io/gitea/modules/optional"
1315
"code.gitea.io/gitea/modules/util"
1416

1517
"github.com/blevesearch/bleve/v2"
@@ -246,12 +248,20 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
246248
queries = append(queries, inner_bleve.NumericEqualityQuery(options.ProjectColumnID.Value(), "project_board_id"))
247249
}
248250

249-
if options.PosterID.Has() {
250-
queries = append(queries, inner_bleve.NumericEqualityQuery(options.PosterID.Value(), "poster_id"))
251+
if options.PosterID != "" {
252+
// "(none)" becomes 0, it means no poster
253+
posterIDInt64, _ := strconv.ParseInt(options.PosterID, 10, 64)
254+
queries = append(queries, inner_bleve.NumericEqualityQuery(posterIDInt64, "poster_id"))
251255
}
252256

253-
if options.AssigneeID.Has() {
254-
queries = append(queries, inner_bleve.NumericEqualityQuery(options.AssigneeID.Value(), "assignee_id"))
257+
if options.AssigneeID != "" {
258+
if options.AssigneeID == "(any)" {
259+
queries = append(queries, inner_bleve.NumericRangeInclusiveQuery(optional.Some[int64](1), optional.None[int64](), "assignee_id"))
260+
} else {
261+
// "(none)" becomes 0, it means no assignee
262+
assigneeIDInt64, _ := strconv.ParseInt(options.AssigneeID, 10, 64)
263+
queries = append(queries, inner_bleve.NumericEqualityQuery(assigneeIDInt64, "assignee_id"))
264+
}
255265
}
256266

257267
if options.MentionID.Has() {

modules/indexer/issues/db/options.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func ToDBOptions(ctx context.Context, options *internal.SearchOptions) (*issue_m
5454
RepoIDs: options.RepoIDs,
5555
AllPublic: options.AllPublic,
5656
RepoCond: nil,
57-
AssigneeID: optional.Some(convertID(options.AssigneeID)),
57+
AssigneeID: options.AssigneeID,
5858
PosterID: options.PosterID,
5959
MentionedID: convertID(options.MentionID),
6060
ReviewRequestedID: convertID(options.ReviewRequestedID),

modules/indexer/issues/dboptions.go

+1-5
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,7 @@ func ToSearchOptions(keyword string, opts *issues_model.IssuesOptions) *SearchOp
4545
searchOpt.ProjectID = optional.Some[int64](0) // Those issues with no project(projectid==0)
4646
}
4747

48-
if opts.AssigneeID.Value() == db.NoConditionID {
49-
searchOpt.AssigneeID = optional.Some[int64](0) // FIXME: this is inconsistent from other places, 0 means "no assignee"
50-
} else if opts.AssigneeID.Value() != 0 {
51-
searchOpt.AssigneeID = opts.AssigneeID
52-
}
48+
searchOpt.AssigneeID = opts.AssigneeID
5349

5450
// See the comment of issues_model.SearchOptions for the reason why we need to convert
5551
convertID := func(id int64) optional.Option[int64] {

modules/indexer/issues/elasticsearch/elasticsearch.go

+14-4
Original file line numberDiff line numberDiff line change
@@ -212,12 +212,22 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
212212
query.Must(elastic.NewTermQuery("project_board_id", options.ProjectColumnID.Value()))
213213
}
214214

215-
if options.PosterID.Has() {
216-
query.Must(elastic.NewTermQuery("poster_id", options.PosterID.Value()))
215+
if options.PosterID != "" {
216+
// "(none)" becomes 0, it means no poster
217+
posterIDInt64, _ := strconv.ParseInt(options.PosterID, 10, 64)
218+
query.Must(elastic.NewTermQuery("poster_id", posterIDInt64))
217219
}
218220

219-
if options.AssigneeID.Has() {
220-
query.Must(elastic.NewTermQuery("assignee_id", options.AssigneeID.Value()))
221+
if options.AssigneeID != "" {
222+
if options.AssigneeID == "(any)" {
223+
q := elastic.NewRangeQuery("assignee_id")
224+
q.Gte(1)
225+
query.Must(q)
226+
} else {
227+
// "(none)" becomes 0, it means no assignee
228+
assigneeIDInt64, _ := strconv.ParseInt(options.AssigneeID, 10, 64)
229+
query.Must(elastic.NewTermQuery("assignee_id", assigneeIDInt64))
230+
}
221231
}
222232

223233
if options.MentionID.Has() {

0 commit comments

Comments
 (0)