mirror of
https://github.com/go-gitea/gitea.git
synced 2025-11-14 23:26:46 +01:00
Merge branch 'main' into admin-ip-info
This commit is contained in:
commit
2a49d34521
@ -12,6 +12,9 @@ insert_final_newline = true
|
||||
[*.{go,tmpl,html}]
|
||||
indent_style = tab
|
||||
|
||||
[go.*]
|
||||
indent_style = tab
|
||||
|
||||
[templates/custom/*.tmpl]
|
||||
insert_final_newline = false
|
||||
|
||||
|
||||
6
go.mod
6
go.mod
@ -64,7 +64,7 @@ require (
|
||||
github.com/gobwas/glob v0.2.3
|
||||
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f
|
||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2
|
||||
github.com/google/go-github/v61 v61.0.0
|
||||
github.com/google/licenseclassifier/v2 v2.0.0
|
||||
github.com/google/pprof v0.0.0-20250208200701-d0013a598941
|
||||
@ -99,7 +99,7 @@ require (
|
||||
github.com/pquerna/otp v1.4.0
|
||||
github.com/prometheus/client_golang v1.21.0
|
||||
github.com/quasoft/websspi v1.1.2
|
||||
github.com/redis/go-redis/v9 v9.7.0
|
||||
github.com/redis/go-redis/v9 v9.7.3
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1
|
||||
github.com/sassoftware/go-rpmutils v0.4.0
|
||||
@ -215,7 +215,7 @@ require (
|
||||
github.com/go-openapi/validate v0.24.0 // indirect
|
||||
github.com/go-webauthn/x v0.1.16 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
||||
github.com/golang/geo v0.0.0-20230421003525-6adc56603217 // indirect
|
||||
|
||||
11
go.sum
11
go.sum
@ -374,10 +374,11 @@ github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7w
|
||||
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14=
|
||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 h1:UjoPNDAQ5JPCjlxoJd6K8ALZqSDDhk2ymieAZOVaDg0=
|
||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
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
|
||||
github.com/quasoft/websspi v1.1.2 h1:/mA4w0LxWlE3novvsoEL6BBA1WnjJATbjkh1kFrTidw=
|
||||
github.com/quasoft/websspi v1.1.2/go.mod h1:HmVdl939dQ0WIXZhyik+ARdI03M6bQzaSEKcgpFmewk=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
|
||||
github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
|
||||
github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
|
||||
github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
|
||||
github.com/redis/rueidis v1.0.19 h1:s65oWtotzlIFN8eMPhyYwxlwLR1lUdhza2KtWprKYSo=
|
||||
github.com/redis/rueidis v1.0.19/go.mod h1:8B+r5wdnjwK3lTFml5VtxjzGOQAC+5UmujoD12pDrEo=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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},
|
||||
|
||||
@ -191,7 +191,8 @@ func (b *Indexer) addUpdate(ctx context.Context, batchWriter git.WriteCloserErro
|
||||
return err
|
||||
} else if !typesniffer.DetectContentType(fileContents).IsText() {
|
||||
// FIXME: UTF-16 files will probably fail here
|
||||
return nil
|
||||
// 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.
|
||||
fileContents = nil
|
||||
}
|
||||
|
||||
if _, err = batchReader.Discard(1); err != nil {
|
||||
|
||||
@ -5,11 +5,13 @@ package bleve
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"code.gitea.io/gitea/modules/indexer"
|
||||
indexer_internal "code.gitea.io/gitea/modules/indexer/internal"
|
||||
inner_bleve "code.gitea.io/gitea/modules/indexer/internal/bleve"
|
||||
"code.gitea.io/gitea/modules/indexer/issues/internal"
|
||||
"code.gitea.io/gitea/modules/optional"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/blevesearch/bleve/v2"
|
||||
@ -246,12 +248,20 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
|
||||
queries = append(queries, inner_bleve.NumericEqualityQuery(options.ProjectColumnID.Value(), "project_board_id"))
|
||||
}
|
||||
|
||||
if options.PosterID.Has() {
|
||||
queries = append(queries, inner_bleve.NumericEqualityQuery(options.PosterID.Value(), "poster_id"))
|
||||
if options.PosterID != "" {
|
||||
// "(none)" becomes 0, it means no poster
|
||||
posterIDInt64, _ := strconv.ParseInt(options.PosterID, 10, 64)
|
||||
queries = append(queries, inner_bleve.NumericEqualityQuery(posterIDInt64, "poster_id"))
|
||||
}
|
||||
|
||||
if options.AssigneeID.Has() {
|
||||
queries = append(queries, inner_bleve.NumericEqualityQuery(options.AssigneeID.Value(), "assignee_id"))
|
||||
if options.AssigneeID != "" {
|
||||
if options.AssigneeID == "(any)" {
|
||||
queries = append(queries, inner_bleve.NumericRangeInclusiveQuery(optional.Some[int64](1), optional.None[int64](), "assignee_id"))
|
||||
} else {
|
||||
// "(none)" becomes 0, it means no assignee
|
||||
assigneeIDInt64, _ := strconv.ParseInt(options.AssigneeID, 10, 64)
|
||||
queries = append(queries, inner_bleve.NumericEqualityQuery(assigneeIDInt64, "assignee_id"))
|
||||
}
|
||||
}
|
||||
|
||||
if options.MentionID.Has() {
|
||||
|
||||
@ -54,7 +54,7 @@ func ToDBOptions(ctx context.Context, options *internal.SearchOptions) (*issue_m
|
||||
RepoIDs: options.RepoIDs,
|
||||
AllPublic: options.AllPublic,
|
||||
RepoCond: nil,
|
||||
AssigneeID: optional.Some(convertID(options.AssigneeID)),
|
||||
AssigneeID: options.AssigneeID,
|
||||
PosterID: options.PosterID,
|
||||
MentionedID: convertID(options.MentionID),
|
||||
ReviewRequestedID: convertID(options.ReviewRequestedID),
|
||||
|
||||
@ -45,11 +45,7 @@ func ToSearchOptions(keyword string, opts *issues_model.IssuesOptions) *SearchOp
|
||||
searchOpt.ProjectID = optional.Some[int64](0) // Those issues with no project(projectid==0)
|
||||
}
|
||||
|
||||
if opts.AssigneeID.Value() == db.NoConditionID {
|
||||
searchOpt.AssigneeID = optional.Some[int64](0) // FIXME: this is inconsistent from other places, 0 means "no assignee"
|
||||
} else if opts.AssigneeID.Value() != 0 {
|
||||
searchOpt.AssigneeID = opts.AssigneeID
|
||||
}
|
||||
|
||||
// See the comment of issues_model.SearchOptions for the reason why we need to convert
|
||||
convertID := func(id int64) optional.Option[int64] {
|
||||
|
||||
@ -212,12 +212,22 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
|
||||
query.Must(elastic.NewTermQuery("project_board_id", options.ProjectColumnID.Value()))
|
||||
}
|
||||
|
||||
if options.PosterID.Has() {
|
||||
query.Must(elastic.NewTermQuery("poster_id", options.PosterID.Value()))
|
||||
if options.PosterID != "" {
|
||||
// "(none)" becomes 0, it means no poster
|
||||
posterIDInt64, _ := strconv.ParseInt(options.PosterID, 10, 64)
|
||||
query.Must(elastic.NewTermQuery("poster_id", posterIDInt64))
|
||||
}
|
||||
|
||||
if options.AssigneeID.Has() {
|
||||
query.Must(elastic.NewTermQuery("assignee_id", options.AssigneeID.Value()))
|
||||
if options.AssigneeID != "" {
|
||||
if options.AssigneeID == "(any)" {
|
||||
q := elastic.NewRangeQuery("assignee_id")
|
||||
q.Gte(1)
|
||||
query.Must(q)
|
||||
} else {
|
||||
// "(none)" becomes 0, it means no assignee
|
||||
assigneeIDInt64, _ := strconv.ParseInt(options.AssigneeID, 10, 64)
|
||||
query.Must(elastic.NewTermQuery("assignee_id", assigneeIDInt64))
|
||||
}
|
||||
}
|
||||
|
||||
if options.MentionID.Has() {
|
||||
|
||||
@ -44,6 +44,7 @@ func TestDBSearchIssues(t *testing.T) {
|
||||
t.Run("search issues with order", searchIssueWithOrder)
|
||||
t.Run("search issues in project", searchIssueInProject)
|
||||
t.Run("search issues with paginator", searchIssueWithPaginator)
|
||||
t.Run("search issues with any assignee", searchIssueWithAnyAssignee)
|
||||
}
|
||||
|
||||
func searchIssueWithKeyword(t *testing.T) {
|
||||
@ -176,19 +177,19 @@ func searchIssueByID(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
opts: SearchOptions{
|
||||
PosterID: optional.Some(int64(1)),
|
||||
PosterID: "1",
|
||||
},
|
||||
expectedIDs: []int64{11, 6, 3, 2, 1},
|
||||
},
|
||||
{
|
||||
opts: SearchOptions{
|
||||
AssigneeID: optional.Some(int64(1)),
|
||||
AssigneeID: "1",
|
||||
},
|
||||
expectedIDs: []int64{6, 1},
|
||||
},
|
||||
{
|
||||
// NOTE: This tests no assignees filtering and also ToSearchOptions() to ensure it will set AssigneeID to 0 when it is passed as -1.
|
||||
opts: *ToSearchOptions("", &issues.IssuesOptions{AssigneeID: optional.Some(db.NoConditionID)}),
|
||||
// NOTE: This tests no assignees filtering and also ToSearchOptions() to ensure it handles the filter correctly
|
||||
opts: *ToSearchOptions("", &issues.IssuesOptions{AssigneeID: "(none)"}),
|
||||
expectedIDs: []int64{22, 21, 16, 15, 14, 13, 12, 11, 20, 5, 19, 18, 10, 7, 4, 9, 8, 3, 2},
|
||||
},
|
||||
{
|
||||
@ -462,3 +463,25 @@ func searchIssueWithPaginator(t *testing.T) {
|
||||
assert.Equal(t, test.expectedTotal, total)
|
||||
}
|
||||
}
|
||||
|
||||
func searchIssueWithAnyAssignee(t *testing.T) {
|
||||
tests := []struct {
|
||||
opts SearchOptions
|
||||
expectedIDs []int64
|
||||
expectedTotal int64
|
||||
}{
|
||||
{
|
||||
SearchOptions{
|
||||
AssigneeID: "(any)",
|
||||
},
|
||||
[]int64{17, 6, 1},
|
||||
3,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
issueIDs, total, err := SearchIssues(t.Context(), &test.opts)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, test.expectedIDs, issueIDs)
|
||||
assert.Equal(t, test.expectedTotal, total)
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,9 +97,8 @@ type SearchOptions struct {
|
||||
ProjectID optional.Option[int64] // project the issues belong to
|
||||
ProjectColumnID optional.Option[int64] // project column the issues belong to
|
||||
|
||||
PosterID optional.Option[int64] // poster of the issues
|
||||
|
||||
AssigneeID optional.Option[int64] // assignee of the issues, zero means no assignee
|
||||
PosterID string // poster of the issues, "(none)" or "(any)" or a user ID
|
||||
AssigneeID string // assignee of the issues, "(none)" or "(any)" or a user ID
|
||||
|
||||
MentionID optional.Option[int64] // mentioned user of the issues
|
||||
|
||||
|
||||
@ -379,7 +379,7 @@ var cases = []*testIndexerCase{
|
||||
Paginator: &db.ListOptions{
|
||||
PageSize: 5,
|
||||
},
|
||||
PosterID: optional.Some(int64(1)),
|
||||
PosterID: "1",
|
||||
},
|
||||
Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
|
||||
assert.Len(t, result.Hits, 5)
|
||||
@ -397,7 +397,7 @@ var cases = []*testIndexerCase{
|
||||
Paginator: &db.ListOptions{
|
||||
PageSize: 5,
|
||||
},
|
||||
AssigneeID: optional.Some(int64(1)),
|
||||
AssigneeID: "1",
|
||||
},
|
||||
Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
|
||||
assert.Len(t, result.Hits, 5)
|
||||
@ -415,7 +415,7 @@ var cases = []*testIndexerCase{
|
||||
Paginator: &db.ListOptions{
|
||||
PageSize: 5,
|
||||
},
|
||||
AssigneeID: optional.Some(int64(0)),
|
||||
AssigneeID: "(none)",
|
||||
},
|
||||
Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
|
||||
assert.Len(t, result.Hits, 5)
|
||||
@ -647,6 +647,21 @@ var cases = []*testIndexerCase{
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "SearchAnyAssignee",
|
||||
SearchOptions: &internal.SearchOptions{
|
||||
AssigneeID: "(any)",
|
||||
},
|
||||
Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
|
||||
assert.Len(t, result.Hits, 180)
|
||||
for _, v := range result.Hits {
|
||||
assert.GreaterOrEqual(t, data[v.ID].AssigneeID, int64(1))
|
||||
}
|
||||
assert.Equal(t, countIndexerData(data, func(v *internal.IndexerData) bool {
|
||||
return v.AssigneeID >= 1
|
||||
}), result.Total)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type testIndexerCase struct {
|
||||
|
||||
@ -187,12 +187,20 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
|
||||
query.And(inner_meilisearch.NewFilterEq("project_board_id", options.ProjectColumnID.Value()))
|
||||
}
|
||||
|
||||
if options.PosterID.Has() {
|
||||
query.And(inner_meilisearch.NewFilterEq("poster_id", options.PosterID.Value()))
|
||||
if options.PosterID != "" {
|
||||
// "(none)" becomes 0, it means no poster
|
||||
posterIDInt64, _ := strconv.ParseInt(options.PosterID, 10, 64)
|
||||
query.And(inner_meilisearch.NewFilterEq("poster_id", posterIDInt64))
|
||||
}
|
||||
|
||||
if options.AssigneeID.Has() {
|
||||
query.And(inner_meilisearch.NewFilterEq("assignee_id", options.AssigneeID.Value()))
|
||||
if options.AssigneeID != "" {
|
||||
if options.AssigneeID == "(any)" {
|
||||
query.And(inner_meilisearch.NewFilterGte("assignee_id", 1))
|
||||
} else {
|
||||
// "(none)" becomes 0, it means no assignee
|
||||
assigneeIDInt64, _ := strconv.ParseInt(options.AssigneeID, 10, 64)
|
||||
query.And(inner_meilisearch.NewFilterEq("assignee_id", assigneeIDInt64))
|
||||
}
|
||||
}
|
||||
|
||||
if options.MentionID.Has() {
|
||||
|
||||
@ -7,9 +7,9 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/httplib"
|
||||
"code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
@ -82,29 +82,32 @@ type HookProcReceiveRefResult struct {
|
||||
HeadBranch string
|
||||
}
|
||||
|
||||
func newInternalRequestAPIForHooks(ctx context.Context, hookName, ownerName, repoName string, opts HookOptions) *httplib.Request {
|
||||
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/%s/%s/%s", hookName, url.PathEscape(ownerName), url.PathEscape(repoName))
|
||||
req := newInternalRequestAPI(ctx, reqURL, "POST", opts)
|
||||
// This "timeout" applies to http.Client's timeout: A Timeout of zero means no timeout.
|
||||
// This "timeout" was previously set to `time.Duration(60+len(opts.OldCommitIDs))` seconds, but it caused unnecessary timeout failures.
|
||||
// It should be good enough to remove the client side timeout, only respect the "ctx" and server side timeout.
|
||||
req.SetReadWriteTimeout(0)
|
||||
return req
|
||||
}
|
||||
|
||||
// HookPreReceive check whether the provided commits are allowed
|
||||
func HookPreReceive(ctx context.Context, ownerName, repoName string, opts HookOptions) ResponseExtra {
|
||||
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/pre-receive/%s/%s", url.PathEscape(ownerName), url.PathEscape(repoName))
|
||||
req := newInternalRequestAPI(ctx, reqURL, "POST", opts)
|
||||
req.SetReadWriteTimeout(time.Duration(60+len(opts.OldCommitIDs)) * time.Second)
|
||||
req := newInternalRequestAPIForHooks(ctx, "pre-receive", ownerName, repoName, opts)
|
||||
_, extra := requestJSONResp(req, &ResponseText{})
|
||||
return extra
|
||||
}
|
||||
|
||||
// HookPostReceive updates services and users
|
||||
func HookPostReceive(ctx context.Context, ownerName, repoName string, opts HookOptions) (*HookPostReceiveResult, ResponseExtra) {
|
||||
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/post-receive/%s/%s", url.PathEscape(ownerName), url.PathEscape(repoName))
|
||||
req := newInternalRequestAPI(ctx, reqURL, "POST", opts)
|
||||
req.SetReadWriteTimeout(time.Duration(60+len(opts.OldCommitIDs)) * time.Second)
|
||||
req := newInternalRequestAPIForHooks(ctx, "post-receive", ownerName, repoName, opts)
|
||||
return requestJSONResp(req, &HookPostReceiveResult{})
|
||||
}
|
||||
|
||||
// HookProcReceive proc-receive hook
|
||||
func HookProcReceive(ctx context.Context, ownerName, repoName string, opts HookOptions) (*HookProcReceiveResult, ResponseExtra) {
|
||||
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/proc-receive/%s/%s", url.PathEscape(ownerName), url.PathEscape(repoName))
|
||||
|
||||
req := newInternalRequestAPI(ctx, reqURL, "POST", opts)
|
||||
req.SetReadWriteTimeout(time.Duration(60+len(opts.OldCommitIDs)) * time.Second)
|
||||
req := newInternalRequestAPIForHooks(ctx, "proc-receive", ownerName, repoName, opts)
|
||||
return requestJSONResp(req, &HookProcReceiveResult{})
|
||||
}
|
||||
|
||||
|
||||
@ -446,7 +446,6 @@ oauth_signup_submit=Dokončit účet
|
||||
oauth_signin_tab=Propojit s existujícím účtem
|
||||
oauth_signin_title=Přihlaste se pro ověření propojeného účtu
|
||||
oauth_signin_submit=Propojit účet
|
||||
oauth.signin.error=Došlo k chybě při zpracování žádosti o autorizaci. Pokud tato chyba přetrvává, obraťte se na správce webu.
|
||||
oauth.signin.error.access_denied=Žádost o autorizaci byla zamítnuta.
|
||||
oauth.signin.error.temporarily_unavailable=Autorizace se nezdařila, protože ověřovací server je dočasně nedostupný. Opakujte akci později.
|
||||
oauth_callback_unable_auto_reg=Automatická registrace je povolena, ale OAuth2 poskytovatel %[1]s vrátil chybějící pole: %[2]s, nelze vytvořit účet automaticky, vytvořte účet nebo se připojte k účtu, nebo kontaktujte správce webu.
|
||||
@ -1530,7 +1529,6 @@ issues.filter_project=Projekt
|
||||
issues.filter_project_all=Všechny projekty
|
||||
issues.filter_project_none=Žádný projekt
|
||||
issues.filter_assignee=Zpracovatel
|
||||
issues.filter_assginee_no_select=Všichni zpracovatelé
|
||||
issues.filter_assginee_no_assignee=Bez zpracovatele
|
||||
issues.filter_poster=Autor
|
||||
issues.filter_user_placeholder=Hledat uživatele
|
||||
|
||||
@ -452,7 +452,6 @@ oauth_signup_submit=Konto vervollständigen
|
||||
oauth_signin_tab=Mit existierendem Konto verbinden
|
||||
oauth_signin_title=Anmelden um verbundenes Konto zu autorisieren
|
||||
oauth_signin_submit=Konto verbinden
|
||||
oauth.signin.error=Beim Verarbeiten der Autorisierungsanfrage ist ein Fehler aufgetreten. Wenn dieser Fehler weiterhin besteht, wende dich bitte an deinen Administrator.
|
||||
oauth.signin.error.access_denied=Die Autorisierungsanfrage wurde abgelehnt.
|
||||
oauth.signin.error.temporarily_unavailable=Autorisierung fehlgeschlagen, da der Authentifizierungsserver vorübergehend nicht verfügbar ist. Bitte versuch es später erneut.
|
||||
oauth_callback_unable_auto_reg=Automatische Registrierung ist aktiviert, aber der OAuth2-Provider %[1]s hat fehlende Felder zurückgegeben: %[2]s, kann den Account nicht automatisch erstellen. Bitte erstelle oder verbinde einen Account oder kontaktieren den Administrator.
|
||||
@ -1531,7 +1530,6 @@ issues.filter_project=Projekt
|
||||
issues.filter_project_all=Alle Projekte
|
||||
issues.filter_project_none=Kein Projekt
|
||||
issues.filter_assignee=Zuständig
|
||||
issues.filter_assginee_no_select=Alle Zuständigen
|
||||
issues.filter_assginee_no_assignee=Niemand zuständig
|
||||
issues.filter_poster=Autor
|
||||
issues.filter_user_placeholder=Benutzer suchen
|
||||
|
||||
@ -390,7 +390,6 @@ oauth_signup_submit=Ολοκληρωμένος Λογαριασμός
|
||||
oauth_signin_tab=Σύνδεση με υπάρχων λογαριασμό
|
||||
oauth_signin_title=Συνδεθείτε για να εγκρίνετε τον Συνδεδεμένο Λογαριασμό
|
||||
oauth_signin_submit=Σύνδεση Λογαριασμού
|
||||
oauth.signin.error=Παρουσιάστηκε σφάλμα κατά την επεξεργασία του αιτήματος εξουσιοδότησης. Εάν αυτό το σφάλμα επιμένει, παρακαλούμε επικοινωνήστε με το διαχειριστή του ιστοτόπου.
|
||||
oauth.signin.error.access_denied=Η αίτηση εξουσιοδότησης απορρίφθηκε.
|
||||
oauth.signin.error.temporarily_unavailable=Η εξουσιοδότηση απέτυχε επειδή ο διακομιστής ταυτοποίησης δεν είναι διαθέσιμος προσωρινά. Παρακαλώ προσπαθήστε ξανά αργότερα.
|
||||
openid_connect_submit=Σύνδεση
|
||||
@ -1378,7 +1377,6 @@ issues.filter_project=Έργο
|
||||
issues.filter_project_all=Όλα τα έργα
|
||||
issues.filter_project_none=Χωρίς έργα
|
||||
issues.filter_assignee=Αποδέκτης
|
||||
issues.filter_assginee_no_select=Όλοι οι αποδέκτες
|
||||
issues.filter_assginee_no_assignee=Κανένας Αποδέκτης
|
||||
issues.filter_poster=Συγγραφέας
|
||||
issues.filter_type=Τύπος
|
||||
|
||||
@ -457,7 +457,7 @@ oauth_signup_submit = Complete Account
|
||||
oauth_signin_tab = Link to Existing Account
|
||||
oauth_signin_title = Sign In to Authorize Linked Account
|
||||
oauth_signin_submit = Link Account
|
||||
oauth.signin.error = There was an error processing the authorization request. If this error persists, please contact the site administrator.
|
||||
oauth.signin.error.general = There was an error processing the authorization request: %s. If this error persists, please contact the site administrator.
|
||||
oauth.signin.error.access_denied = The authorization request was denied.
|
||||
oauth.signin.error.temporarily_unavailable = Authorization failed because the authentication server is temporarily unavailable. Please try again later.
|
||||
oauth_callback_unable_auto_reg = Auto Registration is enabled, but OAuth2 Provider %[1]s returned missing fields: %[2]s, unable to create an account automatically, please create or link to an account, or contact the site administrator.
|
||||
@ -1547,8 +1547,8 @@ issues.filter_project = Project
|
||||
issues.filter_project_all = All projects
|
||||
issues.filter_project_none = No project
|
||||
issues.filter_assignee = Assignee
|
||||
issues.filter_assginee_no_select = All assignees
|
||||
issues.filter_assginee_no_assignee = No assignee
|
||||
issues.filter_assginee_no_assignee = Assigned to nobody
|
||||
issues.filter_assignee_any_assignee = Assigned to anybody
|
||||
issues.filter_poster = Author
|
||||
issues.filter_user_placeholder = Search users
|
||||
issues.filter_user_no_select = All users
|
||||
|
||||
@ -387,7 +387,6 @@ oauth_signup_submit=Completar Cuenta
|
||||
oauth_signin_tab=Vincular a una Cuenta Existente
|
||||
oauth_signin_title=Regístrese para autorizar cuenta vinculada
|
||||
oauth_signin_submit=Vincular Cuenta
|
||||
oauth.signin.error=Hubo un error al procesar la solicitud de autorización. Si este error persiste, póngase en contacto con el administrador del sitio.
|
||||
oauth.signin.error.access_denied=La solicitud de autorización fue denegada.
|
||||
oauth.signin.error.temporarily_unavailable=La autorización falló porque el servidor de autenticación no está disponible temporalmente. Inténtalo de nuevo más tarde.
|
||||
openid_connect_submit=Conectar
|
||||
@ -1368,7 +1367,6 @@ issues.filter_project=Proyecto
|
||||
issues.filter_project_all=Todos los proyectos
|
||||
issues.filter_project_none=Ningún proyecto
|
||||
issues.filter_assignee=Asignada a
|
||||
issues.filter_assginee_no_select=Todos los asignados
|
||||
issues.filter_assginee_no_assignee=Sin asignado
|
||||
issues.filter_poster=Autor
|
||||
issues.filter_type=Tipo
|
||||
|
||||
@ -1059,7 +1059,6 @@ issues.filter_label_no_select=تمامی برچسبها
|
||||
issues.filter_milestone=نقطه عطف
|
||||
issues.filter_project_none=هیچ پروژه ثبت نشده
|
||||
issues.filter_assignee=مسئول رسیدگی
|
||||
issues.filter_assginee_no_select=تمامی مسئولان رسیدگی
|
||||
issues.filter_assginee_no_assignee=بدون مسئول رسیدگی
|
||||
issues.filter_type=نوع
|
||||
issues.filter_type.all_issues=همه مسائل
|
||||
|
||||
@ -113,6 +113,7 @@ copy_type_unsupported=Ce type de fichier ne peut pas être copié
|
||||
write=Écrire
|
||||
preview=Aperçu
|
||||
loading=Chargement…
|
||||
files=Fichiers
|
||||
|
||||
error=Erreur
|
||||
error404=La page que vous essayez d'atteindre <strong>n'existe pas</strong> ou <strong>vous n'êtes pas autorisé</strong> à la voir.
|
||||
@ -169,6 +170,10 @@ search=Rechercher…
|
||||
type_tooltip=Type de recherche
|
||||
fuzzy=Approximative
|
||||
fuzzy_tooltip=Inclure également les résultats proches de la recherche
|
||||
words=Mots
|
||||
words_tooltip=Inclure uniquement les résultats qui correspondent exactement aux mots recherchés
|
||||
regexp=Regexp
|
||||
regexp_tooltip=Inclure uniquement les résultats qui correspondent à l’expression régulière recherchée
|
||||
exact=Exact
|
||||
exact_tooltip=Inclure uniquement les résultats qui correspondent exactement au terme de recherche
|
||||
repo_kind=Chercher des dépôts…
|
||||
@ -452,7 +457,6 @@ oauth_signup_submit=Finaliser la création du compte
|
||||
oauth_signin_tab=Lier à un compte existant
|
||||
oauth_signin_title=Connectez-vous pour autoriser le compte lié
|
||||
oauth_signin_submit=Lier un compte
|
||||
oauth.signin.error=Une erreur s'est produite lors du traitement de la demande d'autorisation. Si cette erreur persiste, veuillez contacter l'administrateur du site.
|
||||
oauth.signin.error.access_denied=La demande d'autorisation a été refusée.
|
||||
oauth.signin.error.temporarily_unavailable=L'autorisation a échoué car le serveur d'authentification est temporairement indisponible. Veuillez réessayer plus tard.
|
||||
oauth_callback_unable_auto_reg=L’inscription automatique est activée, mais le fournisseur OAuth2 %[1]s a signalé des champs manquants : %[2]s, impossible de créer un compte automatiquement, veuillez créer ou lier un compte, ou bien contacter l’administrateur du site.
|
||||
@ -1403,6 +1407,7 @@ commits.signed_by_untrusted_user_unmatched=Signature discordante de l'auteur de
|
||||
commits.gpg_key_id=ID de la clé GPG
|
||||
commits.ssh_key_fingerprint=Empreinte numérique de la clé SSH
|
||||
commits.view_path=Voir à ce point de l'historique
|
||||
commits.view_file_diff=Voir les modifications du fichier dans cette révision
|
||||
|
||||
commit.operations=Opérations
|
||||
commit.revert=Rétablir
|
||||
@ -1540,8 +1545,6 @@ issues.filter_project=Projet
|
||||
issues.filter_project_all=Tous les projets
|
||||
issues.filter_project_none=Aucun projet
|
||||
issues.filter_assignee=Assigné
|
||||
issues.filter_assginee_no_select=Tous les assignés
|
||||
issues.filter_assginee_no_assignee=Aucun assigné
|
||||
issues.filter_poster=Auteur
|
||||
issues.filter_user_placeholder=Rechercher des utilisateurs
|
||||
issues.filter_user_no_select=Tous les utilisateurs
|
||||
@ -3708,6 +3711,7 @@ creation=Ajouter un secret
|
||||
creation.description=Description
|
||||
creation.name_placeholder=Caractères alphanumériques ou tirets bas uniquement, insensibles à la casse, ne peut commencer par GITEA_ ou GITHUB_.
|
||||
creation.value_placeholder=Entrez n’importe quoi. Les blancs cernant seront taillés.
|
||||
creation.description_placeholder=Décrire brièvement votre dépôt (optionnel).
|
||||
creation.success=Le secret "%s" a été ajouté.
|
||||
creation.failed=Impossible d'ajouter le secret.
|
||||
deletion=Supprimer le secret
|
||||
|
||||
@ -113,6 +113,7 @@ copy_type_unsupported=Ní féidir an cineál comhaid seo a chóipeáil
|
||||
write=Scríobh
|
||||
preview=Réamhamharc
|
||||
loading=Á lódáil...
|
||||
files=Comhaid
|
||||
|
||||
error=Earráid
|
||||
error404=Níl an leathanach atá tú ag iarraidh a bhaint amach <strong>ann</strong> nó <strong>níl tú údaraithe</strong> chun é a fheiceáil.
|
||||
@ -169,6 +170,10 @@ search=Cuardaigh...
|
||||
type_tooltip=Cineál cuardaigh
|
||||
fuzzy=Doiléir
|
||||
fuzzy_tooltip=Cuir san áireamh torthaí a mheaitseálann an téarma cuardaigh go dlúth freisin
|
||||
words=Focail
|
||||
words_tooltip=Ná cuir san áireamh ach torthaí a mheaitseálann na focail téarma cuardaigh
|
||||
regexp=Nathanna Rialta
|
||||
regexp_tooltip=Ná cuir ach torthaí a mheaitseálann an téarma cuardaigh nathanna rialta san áireamh
|
||||
exact=Beacht
|
||||
exact_tooltip=Ní chuir san áireamh ach torthaí a mheaitseálann leis an téarma
|
||||
repo_kind=Cuardaigh stórtha...
|
||||
@ -452,7 +457,6 @@ oauth_signup_submit=Cuntas Comhlánaigh
|
||||
oauth_signin_tab=Nasc leis an gCuntas Reatha
|
||||
oauth_signin_title=Sínigh isteach chun Cuntas Nasctha a Údarú
|
||||
oauth_signin_submit=Cuntas Nasc
|
||||
oauth.signin.error=Bhí earráid ann ag próiseáil an t-iarratas ar údarú. Má leanann an earráid seo, déan teagmháil le riarthóir an láithreáin.
|
||||
oauth.signin.error.access_denied=Diúltaíodh an t-iarratas ar údarú.
|
||||
oauth.signin.error.temporarily_unavailable=Theip ar údarú toisc nach bhfuil an fhreastalaí fíordheimhnithe ar fáil Bain triail as arís níos déanaí.
|
||||
oauth_callback_unable_auto_reg=Tá Clárú Uathoibríoch cumasaithe, ach sheol Soláthraí OAuth2 %[1]s réimsí in easnamh ar ais: %[2]s, ní raibh sé in ann cuntas a chruthú go huathoibríoch, cruthaigh nó nasc le cuntas, nó déan teagmháil le riarthóir an tsuímh.
|
||||
@ -1403,6 +1407,7 @@ commits.signed_by_untrusted_user_unmatched=Sínithe ag úsáideoir neamhiontaofa
|
||||
commits.gpg_key_id=GPG Eochair ID
|
||||
commits.ssh_key_fingerprint=Méarloirg Eochair SSH
|
||||
commits.view_path=Féach ag an bpointe seo sa stair
|
||||
commits.view_file_diff=Féach ar athruithe ar an gcomhad seo sa tiomantas seo
|
||||
|
||||
commit.operations=Oibríochtaí
|
||||
commit.revert=Téigh ar ais
|
||||
@ -1540,8 +1545,8 @@ issues.filter_project=Tionscadal
|
||||
issues.filter_project_all=Gach tionscadal
|
||||
issues.filter_project_none=Gan aon tionscadal
|
||||
issues.filter_assignee=Sannaitheoir
|
||||
issues.filter_assginee_no_select=Gach sannaithe
|
||||
issues.filter_assginee_no_assignee=Gan sannaitheoir
|
||||
issues.filter_assginee_no_assignee=Sannta do dhuine ar bith
|
||||
issues.filter_assignee_any_assignee=Sannta do dhuine ar bith
|
||||
issues.filter_poster=Údar
|
||||
issues.filter_user_placeholder=Cuardaigh úsáideoirí
|
||||
issues.filter_user_no_select=Gach úsáideoir
|
||||
@ -3708,6 +3713,7 @@ creation=Cuir Rúnda leis
|
||||
creation.description=Cur síos
|
||||
creation.name_placeholder=carachtair alfanumair nó íoslaghda amháin nach féidir a thosú le GITEA_ nó GITHUB_
|
||||
creation.value_placeholder=Ionchur ábhar ar bith. Fágfar spás bán ag tús agus ag deireadh ar lár.
|
||||
creation.description_placeholder=Cuir isteach cur síos gairid (roghnach).
|
||||
creation.success=Tá an rún "%s" curtha leis.
|
||||
creation.failed=Theip ar an rún a chur leis.
|
||||
deletion=Bain rún
|
||||
|
||||
@ -774,8 +774,6 @@ issues.filter_label=Címke
|
||||
issues.filter_label_no_select=Minden címke
|
||||
issues.filter_milestone=Mérföldkő
|
||||
issues.filter_assignee=Megbízott
|
||||
issues.filter_assginee_no_select=Minden megbízott
|
||||
issues.filter_assginee_no_assignee=Nincs megbízott
|
||||
issues.filter_type=Típus
|
||||
issues.filter_type.all_issues=Minden hibajegy
|
||||
issues.filter_type.assigned_to_you=Hozzám rendelt
|
||||
|
||||
@ -763,7 +763,6 @@ issues.delete_branch_at=`telah dihapus cabang <b>%s</b> %s`
|
||||
issues.filter_label=Label
|
||||
issues.filter_milestone=Tonggak
|
||||
issues.filter_assignee=Menerima
|
||||
issues.filter_assginee_no_assignee=Tidak ada yang menerima
|
||||
issues.filter_type=Tipe
|
||||
issues.filter_type.all_issues=Semua masalah
|
||||
issues.filter_type.assigned_to_you=Ditugaskan kepada anda
|
||||
|
||||
@ -323,7 +323,6 @@ oauth_signup_submit=Completa l'Account
|
||||
oauth_signin_tab=Collegamento ad un Account Esistente
|
||||
oauth_signin_title=Accedi per autorizzare l' Account collegato
|
||||
oauth_signin_submit=Collega Account
|
||||
oauth.signin.error=Si è verificato un errore nell'elaborazione della richiesta di autorizzazione. Se questo errore persiste, si prega di contattare l'amministratore del sito.
|
||||
oauth.signin.error.access_denied=La richiesta di autorizzazione è stata negata.
|
||||
oauth.signin.error.temporarily_unavailable=Autorizzazione non riuscita perché il server di autenticazione non è temporaneamente disponibile. Riprova più tardi.
|
||||
openid_connect_submit=Connetti
|
||||
@ -1144,7 +1143,6 @@ issues.filter_milestone=Traguardo
|
||||
issues.filter_project=Progetto
|
||||
issues.filter_project_none=Nessun progetto
|
||||
issues.filter_assignee=Assegnatario
|
||||
issues.filter_assginee_no_select=Tutte le assegnazioni
|
||||
issues.filter_assginee_no_assignee=Nessun assegnatario
|
||||
issues.filter_poster=Autore
|
||||
issues.filter_type=Tipo
|
||||
|
||||
@ -452,7 +452,6 @@ oauth_signup_submit=アカウント登録完了
|
||||
oauth_signin_tab=既存アカウントにリンク
|
||||
oauth_signin_title=リンク先アカウント認可のためサインイン
|
||||
oauth_signin_submit=アカウントにリンク
|
||||
oauth.signin.error=認可リクエストの処理中にエラーが発生しました。このエラーが解決しない場合は、サイト管理者に問い合わせてください。
|
||||
oauth.signin.error.access_denied=認可リクエストが拒否されました。
|
||||
oauth.signin.error.temporarily_unavailable=認証サーバーが一時的に利用できないため、認可に失敗しました。後でもう一度やり直してください。
|
||||
oauth_callback_unable_auto_reg=自動登録が有効になっていますが、OAuth2プロバイダー %[1]s の応答はフィールド %[2]s が不足しており、自動でアカウントを作成することができません。 アカウントを作成またはリンクするか、サイト管理者に問い合わせてください。
|
||||
@ -1538,7 +1537,6 @@ issues.filter_project=プロジェクト
|
||||
issues.filter_project_all=すべてのプロジェクト
|
||||
issues.filter_project_none=プロジェクトなし
|
||||
issues.filter_assignee=担当者
|
||||
issues.filter_assginee_no_select=すべての担当者
|
||||
issues.filter_assginee_no_assignee=担当者なし
|
||||
issues.filter_poster=作成者
|
||||
issues.filter_user_placeholder=ユーザーを検索
|
||||
|
||||
@ -707,7 +707,6 @@ issues.filter_label=레이블
|
||||
issues.filter_label_no_select=모든 레이블
|
||||
issues.filter_milestone=마일스톤
|
||||
issues.filter_assignee=담당자
|
||||
issues.filter_assginee_no_select=모든 담당자
|
||||
issues.filter_assginee_no_assignee=담당자 없음
|
||||
issues.filter_type=유형
|
||||
issues.filter_type.all_issues=모든 이슈
|
||||
|
||||
@ -393,7 +393,6 @@ oauth_signup_submit=Pabeigt reģistrāciju
|
||||
oauth_signin_tab=Sasaistīt ar esošu kontu
|
||||
oauth_signin_title=Pieteikties, lai autorizētu saistīto kontu
|
||||
oauth_signin_submit=Sasaistīt kontu
|
||||
oauth.signin.error=Radās kļūda apstrādājot pieteikšanās pieprasījumu. Ja šī kļūda atkārtojas, sazinieties ar lapas administratoru.
|
||||
oauth.signin.error.access_denied=Autorizācijas pieprasījums tika noraidīts.
|
||||
oauth.signin.error.temporarily_unavailable=Pieteikšanās neizdevās, jo autentifikācijas serveris ir īslaicīgi nepieejams. Mēģiniet autorizēties vēlāk.
|
||||
openid_connect_submit=Pievienoties
|
||||
@ -1384,7 +1383,6 @@ issues.filter_project=Projekts
|
||||
issues.filter_project_all=Visi projekti
|
||||
issues.filter_project_none=Nav projekta
|
||||
issues.filter_assignee=Atbildīgais
|
||||
issues.filter_assginee_no_select=Visi atbildīgie
|
||||
issues.filter_assginee_no_assignee=Nav atbildīgā
|
||||
issues.filter_poster=Autors
|
||||
issues.filter_type=Veids
|
||||
|
||||
@ -322,7 +322,6 @@ oauth_signup_submit=Account voltooien
|
||||
oauth_signin_tab=Bestaand account koppelen
|
||||
oauth_signin_title=Inloggen om het gekoppelde account te machtigen
|
||||
oauth_signin_submit=Account koppelen
|
||||
oauth.signin.error=Er is een fout opgetreden bij het verwerken van het autorisatieverzoek. Als deze fout zich blijft voordoen, neem dan contact op met de sitebeheerder.
|
||||
oauth.signin.error.access_denied=Het autorisatieverzoek is geweigerd.
|
||||
oauth.signin.error.temporarily_unavailable=Autorisatie mislukt omdat de verificatieserver tijdelijk niet beschikbaar is. Probeer het later opnieuw.
|
||||
openid_connect_submit=Verbinden
|
||||
@ -1142,7 +1141,6 @@ issues.filter_milestone=Mijlpaal
|
||||
issues.filter_project=Project
|
||||
issues.filter_project_none=Geen project
|
||||
issues.filter_assignee=Aangewezene
|
||||
issues.filter_assginee_no_select=Alle toegewezen personen
|
||||
issues.filter_assginee_no_assignee=Geen verantwoordelijke
|
||||
issues.filter_poster=Auteur
|
||||
issues.filter_type=Type
|
||||
|
||||
@ -1054,7 +1054,6 @@ issues.filter_label_no_select=Wszystkie etykiety
|
||||
issues.filter_milestone=Kamień milowy
|
||||
issues.filter_project_none=Brak projektu
|
||||
issues.filter_assignee=Przypisany
|
||||
issues.filter_assginee_no_select=Wszyscy przypisani
|
||||
issues.filter_assginee_no_assignee=Brak przypisania
|
||||
issues.filter_type=Typ
|
||||
issues.filter_type.all_issues=Wszystkie zgłoszenia
|
||||
|
||||
@ -390,7 +390,6 @@ oauth_signup_submit=Completar conta
|
||||
oauth_signin_tab=Vincular à uma conta existente
|
||||
oauth_signin_title=Acesse com uma conta vinculada
|
||||
oauth_signin_submit=Vincular conta
|
||||
oauth.signin.error=Ocorreu um erro durante o processamento do pedido de autorização. Se este erro persistir, contate o administrador.
|
||||
oauth.signin.error.access_denied=O pedido de autorização foi negado.
|
||||
oauth.signin.error.temporarily_unavailable=A autorização falhou porque o servidor de autenticação está temporariamente indisponível. Por favor, tente novamente mais tarde.
|
||||
openid_connect_submit=Conectar
|
||||
@ -1379,8 +1378,6 @@ issues.filter_project=Projeto
|
||||
issues.filter_project_all=Todos os projetos
|
||||
issues.filter_project_none=Sem projeto
|
||||
issues.filter_assignee=Atribuído
|
||||
issues.filter_assginee_no_select=Todos os responsáveis
|
||||
issues.filter_assginee_no_assignee=Sem responsável
|
||||
issues.filter_poster=Autor
|
||||
issues.filter_type=Tipo
|
||||
issues.filter_type.all_issues=Todas as issues
|
||||
|
||||
@ -457,7 +457,6 @@ oauth_signup_submit=Completar conta
|
||||
oauth_signin_tab=Vincular a uma conta existente
|
||||
oauth_signin_title=Inicie a sessão para autorizar a vinculação à conta
|
||||
oauth_signin_submit=Vincular conta
|
||||
oauth.signin.error=Ocorreu um erro durante o processamento do pedido de autorização. Se este erro persistir, contacte o administrador.
|
||||
oauth.signin.error.access_denied=O pedido de autorização foi negado.
|
||||
oauth.signin.error.temporarily_unavailable=A autorização falhou porque o servidor de autenticação está temporariamente indisponível. Tente mais tarde.
|
||||
oauth_callback_unable_auto_reg=O registo automático está habilitado, mas o fornecedor OAuth2 %[1]s sinalizou campos em falta: %[2]s, por isso não foi possível criar uma conta automaticamente. Crie ou vincule uma conta ou contacte o administrador do sítio.
|
||||
@ -1546,8 +1545,8 @@ issues.filter_project=Planeamento
|
||||
issues.filter_project_all=Todos os planeamentos
|
||||
issues.filter_project_none=Nenhum planeamento
|
||||
issues.filter_assignee=Encarregado
|
||||
issues.filter_assginee_no_select=Todos os encarregados
|
||||
issues.filter_assginee_no_assignee=Sem encarregado
|
||||
issues.filter_assignee_any_assignee=Atribuído a qualquer pessoa
|
||||
issues.filter_poster=Autor(a)
|
||||
issues.filter_user_placeholder=Procurar utilizadores
|
||||
issues.filter_user_no_select=Todos os utilizadores
|
||||
|
||||
@ -388,7 +388,6 @@ oauth_signup_submit=Полная учётная запись
|
||||
oauth_signin_tab=Ссылка на существующую учётную запись
|
||||
oauth_signin_title=Войдите, чтобы авторизовать связанную учётную запись
|
||||
oauth_signin_submit=Привязать учётную запись
|
||||
oauth.signin.error=Произошла ошибка при обработке запроса авторизации. Если эта ошибка повторяется, обратитесь к администратору сайта.
|
||||
oauth.signin.error.access_denied=Запрос на авторизацию был отклонен.
|
||||
oauth.signin.error.temporarily_unavailable=Произошла ошибка авторизации, так как сервер аутентификации временно недоступен. Пожалуйста, повторите попытку позже.
|
||||
openid_connect_submit=Подключить
|
||||
@ -1356,7 +1355,6 @@ issues.filter_project=Проект
|
||||
issues.filter_project_all=Все проекты
|
||||
issues.filter_project_none=Нет проекта
|
||||
issues.filter_assignee=Назначено
|
||||
issues.filter_assginee_no_select=Все назначения
|
||||
issues.filter_assginee_no_assignee=Нет ответственного
|
||||
issues.filter_poster=Автор
|
||||
issues.filter_type=Тип
|
||||
|
||||
@ -1025,7 +1025,6 @@ issues.filter_label_no_select=සියලු ලේබල
|
||||
issues.filter_milestone=සන්ධිස්ථානය
|
||||
issues.filter_project_none=ව්යාපෘති නැත
|
||||
issues.filter_assignee=අස්ගිනී
|
||||
issues.filter_assginee_no_select=සියලුම ඇග්රි
|
||||
issues.filter_assginee_no_assignee=කිසිදු අස්වැද්දුමක්
|
||||
issues.filter_type=වර්ගය
|
||||
issues.filter_type.all_issues=සියලු ගැටළු
|
||||
|
||||
@ -377,7 +377,6 @@ oauth_signup_submit=Dokončiť účet
|
||||
oauth_signin_tab=Prepojiť s existujúcim účtom
|
||||
oauth_signin_title=Prihláste sa na overenie prepojeného účtu
|
||||
oauth_signin_submit=Prepojiť účet
|
||||
oauth.signin.error=Vyskytla sa chyba počas spracovania vašej autorizačnej žiadosti. Ak chyba pretrváva, kontaktujte, prosím, správcu.
|
||||
oauth.signin.error.access_denied=Žiadosť o autorizáciu bola zamietnutá.
|
||||
oauth.signin.error.temporarily_unavailable=Autorizácia zlyhala, pretože overovací server je dočasne nedostupný. Skúste to prosím neskôr.
|
||||
openid_connect_submit=Pripojiť
|
||||
|
||||
@ -873,7 +873,6 @@ issues.filter_label_no_select=Alla etiketter
|
||||
issues.filter_milestone=Milsten
|
||||
issues.filter_project_none=Inget projekt
|
||||
issues.filter_assignee=Förvärvare
|
||||
issues.filter_assginee_no_select=Alla tilldelade
|
||||
issues.filter_assginee_no_assignee=Ingen tilldelad
|
||||
issues.filter_type=Typ
|
||||
issues.filter_type.all_issues=Alla ärenden
|
||||
|
||||
@ -441,7 +441,6 @@ oauth_signup_submit=Hesabı Tamamla
|
||||
oauth_signin_tab=Mevcut Hesaba Bağla
|
||||
oauth_signin_title=Bağlantılı Hesabı Yetkilendirmek için Giriş Yapın
|
||||
oauth_signin_submit=Hesabı Bağla
|
||||
oauth.signin.error=Yetkilendirme isteğini işlerken bir hata oluştu. Eğer hata devam ederse lütfen site yöneticisiyle bağlantıya geçin.
|
||||
oauth.signin.error.access_denied=Yetkilendirme isteği reddedildi.
|
||||
oauth.signin.error.temporarily_unavailable=Yetkilendirme sunucusu geçici olarak erişilemez olduğu için yetkilendirme başarısız oldu. Lütfen daha sonra tekrar deneyin.
|
||||
oauth_callback_unable_auto_reg=Otomatik kayıt etkin ancak OAuth2 Sağlayıcı %[1] eksik sahalar döndürdü: %[2]s, otomatik olarak hesap oluşturulamıyor, lütfen bir hesap oluşturun veya bağlantı verin, veya site yöneticisiyle iletişim kurun.
|
||||
@ -1485,7 +1484,6 @@ issues.filter_project=Proje
|
||||
issues.filter_project_all=Tüm projeler
|
||||
issues.filter_project_none=Proje yok
|
||||
issues.filter_assignee=Atanan
|
||||
issues.filter_assginee_no_select=Tüm atananlar
|
||||
issues.filter_assginee_no_assignee=Atanan yok
|
||||
issues.filter_poster=Yazar
|
||||
issues.filter_type=Tür
|
||||
|
||||
@ -1071,7 +1071,6 @@ issues.filter_milestone=Етап
|
||||
issues.filter_project=Проєкт
|
||||
issues.filter_project_none=Проєкт відсутній
|
||||
issues.filter_assignee=Виконавець
|
||||
issues.filter_assginee_no_select=Всі виконавці
|
||||
issues.filter_assginee_no_assignee=Немає виконавця
|
||||
issues.filter_type=Тип
|
||||
issues.filter_type.all_issues=Всі задачі
|
||||
|
||||
@ -446,7 +446,6 @@ oauth_signup_submit=完成账号
|
||||
oauth_signin_tab=绑定到现有帐号
|
||||
oauth_signin_title=登录以授权绑定帐户
|
||||
oauth_signin_submit=绑定账号
|
||||
oauth.signin.error=处理授权请求时出错。 如果此错误仍然存在,请联系站点管理员。
|
||||
oauth.signin.error.access_denied=授权请求被拒绝。
|
||||
oauth.signin.error.temporarily_unavailable=授权失败,因为认证服务器暂时不可用。请稍后再试。
|
||||
oauth_callback_unable_auto_reg=自动注册已启用,但OAuth2 提供商 %[1]s 返回缺失的字段:%[2]s,无法自动创建帐户,请创建或链接到一个帐户,或联系站点管理员。
|
||||
@ -1525,8 +1524,6 @@ issues.filter_project=项目
|
||||
issues.filter_project_all=所有项目
|
||||
issues.filter_project_none=暂无项目
|
||||
issues.filter_assignee=指派人筛选
|
||||
issues.filter_assginee_no_select=所有指派成员
|
||||
issues.filter_assginee_no_assignee=未指派
|
||||
issues.filter_poster=作者
|
||||
issues.filter_user_placeholder=搜索用户
|
||||
issues.filter_user_no_select=所有用户
|
||||
|
||||
@ -444,7 +444,6 @@ oauth_signup_submit=完成帳戶
|
||||
oauth_signin_tab=連結到現有帳戶
|
||||
oauth_signin_title=登入以授權連結帳戶
|
||||
oauth_signin_submit=連結帳戶
|
||||
oauth.signin.error=處理授權請求時發生錯誤。如果這個問題持續發生,請聯絡網站管理員。
|
||||
oauth.signin.error.access_denied=授權請求被拒絕。
|
||||
oauth.signin.error.temporarily_unavailable=授權失敗,因為認證伺服器暫時無法使用。請稍後再試。
|
||||
oauth_callback_unable_auto_reg=自助註冊已啟用,但是 OAuth2 提供者 %[1]s 回傳的結果缺少欄位:%[2]s,導致無法自動建立帳號。請建立新帳號或是連結至既存的帳號,或是聯絡網站管理者。
|
||||
@ -1518,8 +1517,6 @@ issues.filter_project=專案
|
||||
issues.filter_project_all=所有專案
|
||||
issues.filter_project_none=未選擇專案
|
||||
issues.filter_assignee=負責人
|
||||
issues.filter_assginee_no_select=所有負責人
|
||||
issues.filter_assginee_no_assignee=沒有負責人
|
||||
issues.filter_poster=作者
|
||||
issues.filter_user_placeholder=搜尋使用者
|
||||
issues.filter_user_no_select=所有使用者
|
||||
|
||||
@ -290,10 +290,10 @@ func SearchIssues(ctx *context.APIContext) {
|
||||
if ctx.IsSigned {
|
||||
ctxUserID := ctx.Doer.ID
|
||||
if ctx.FormBool("created") {
|
||||
searchOpt.PosterID = optional.Some(ctxUserID)
|
||||
searchOpt.PosterID = strconv.FormatInt(ctxUserID, 10)
|
||||
}
|
||||
if ctx.FormBool("assigned") {
|
||||
searchOpt.AssigneeID = optional.Some(ctxUserID)
|
||||
searchOpt.AssigneeID = strconv.FormatInt(ctxUserID, 10)
|
||||
}
|
||||
if ctx.FormBool("mentioned") {
|
||||
searchOpt.MentionID = optional.Some(ctxUserID)
|
||||
@ -538,10 +538,10 @@ func ListIssues(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
if createdByID > 0 {
|
||||
searchOpt.PosterID = optional.Some(createdByID)
|
||||
searchOpt.PosterID = strconv.FormatInt(createdByID, 10)
|
||||
}
|
||||
if assignedByID > 0 {
|
||||
searchOpt.AssigneeID = optional.Some(assignedByID)
|
||||
searchOpt.AssigneeID = strconv.FormatInt(assignedByID, 10)
|
||||
}
|
||||
if mentionedByID > 0 {
|
||||
searchOpt.MentionID = optional.Some(mentionedByID)
|
||||
|
||||
@ -61,14 +61,15 @@ func TestUserLogin(t *testing.T) {
|
||||
assert.Equal(t, "/", test.RedirectURL(resp))
|
||||
}
|
||||
|
||||
func TestSignUpOAuth2ButMissingFields(t *testing.T) {
|
||||
func TestSignUpOAuth2Login(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.OAuth2Client.EnableAutoRegistration, true)()
|
||||
defer test.MockVariableValue(&gothic.CompleteUserAuth, func(res http.ResponseWriter, req *http.Request) (goth.User, error) {
|
||||
return goth.User{Provider: "dummy-auth-source", UserID: "dummy-user"}, nil
|
||||
})()
|
||||
|
||||
addOAuth2Source(t, "dummy-auth-source", oauth2.Source{})
|
||||
|
||||
t.Run("OAuth2MissingField", func(t *testing.T) {
|
||||
defer test.MockVariableValue(&gothic.CompleteUserAuth, func(res http.ResponseWriter, req *http.Request) (goth.User, error) {
|
||||
return goth.User{Provider: "dummy-auth-source", UserID: "dummy-user"}, nil
|
||||
})()
|
||||
mockOpt := contexttest.MockContextOption{SessionStore: session.NewMockStore("dummy-sid")}
|
||||
ctx, resp := contexttest.MockContext(t, "/user/oauth2/dummy-auth-source/callback?code=dummy-code", mockOpt)
|
||||
ctx.SetPathParam("provider", "dummy-auth-source")
|
||||
@ -80,4 +81,15 @@ func TestSignUpOAuth2ButMissingFields(t *testing.T) {
|
||||
ctx, _ = contexttest.MockContext(t, "/user/link_account", mockOpt)
|
||||
LinkAccount(ctx)
|
||||
assert.EqualValues(t, "auth.oauth_callback_unable_auto_reg:dummy-auth-source,email", ctx.Data["AutoRegistrationFailedPrompt"])
|
||||
})
|
||||
|
||||
t.Run("OAuth2CallbackError", func(t *testing.T) {
|
||||
mockOpt := contexttest.MockContextOption{SessionStore: session.NewMockStore("dummy-sid")}
|
||||
ctx, resp := contexttest.MockContext(t, "/user/oauth2/dummy-auth-source/callback", mockOpt)
|
||||
ctx.SetPathParam("provider", "dummy-auth-source")
|
||||
SignInOAuthCallback(ctx)
|
||||
assert.Equal(t, http.StatusSeeOther, resp.Code)
|
||||
assert.Equal(t, "/user/login", test.RedirectURL(resp))
|
||||
assert.Contains(t, ctx.Flash.ErrorMsg, "auth.oauth.signin.error.general")
|
||||
})
|
||||
}
|
||||
|
||||
@ -115,7 +115,7 @@ func SignInOAuthCallback(ctx *context.Context) {
|
||||
case "temporarily_unavailable":
|
||||
ctx.Flash.Error(ctx.Tr("auth.oauth.signin.error.temporarily_unavailable"))
|
||||
default:
|
||||
ctx.Flash.Error(ctx.Tr("auth.oauth.signin.error"))
|
||||
ctx.Flash.Error(ctx.Tr("auth.oauth.signin.error.general", callbackErr.Description))
|
||||
}
|
||||
ctx.Redirect(setting.AppSubURL + "/user/login")
|
||||
return
|
||||
@ -431,8 +431,10 @@ func oAuth2UserLoginCallback(ctx *context.Context, authSource *auth.Source, requ
|
||||
gothUser, err := oauth2Source.Callback(request, response)
|
||||
if err != nil {
|
||||
if err.Error() == "securecookie: the value is too long" || strings.Contains(err.Error(), "Data too long") {
|
||||
log.Error("OAuth2 Provider %s returned too long a token. Current max: %d. Either increase the [OAuth2] MAX_TOKEN_LENGTH or reduce the information returned from the OAuth2 provider", authSource.Name, setting.OAuth2.MaxTokenLength)
|
||||
err = fmt.Errorf("OAuth2 Provider %s returned too long a token. Current max: %d. Either increase the [OAuth2] MAX_TOKEN_LENGTH or reduce the information returned from the OAuth2 provider", authSource.Name, setting.OAuth2.MaxTokenLength)
|
||||
log.Error("oauth2Source.Callback failed: %v", err)
|
||||
} else {
|
||||
err = errCallback{Code: "internal", Description: err.Error()}
|
||||
}
|
||||
return nil, goth.User{}, err
|
||||
}
|
||||
|
||||
@ -249,7 +249,7 @@ func AuthorizeOAuth(ctx *context.Context) {
|
||||
}, form.RedirectURI)
|
||||
return
|
||||
}
|
||||
if err := ctx.Session.Set("CodeChallengeMethod", form.CodeChallenge); err != nil {
|
||||
if err := ctx.Session.Set("CodeChallenge", form.CodeChallenge); err != nil {
|
||||
handleAuthorizeError(ctx, AuthorizeError{
|
||||
ErrorCode: ErrorCodeServerError,
|
||||
ErrorDescription: "cannot set code challenge",
|
||||
|
||||
@ -347,11 +347,11 @@ func ViewProject(ctx *context.Context) {
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
assigneeID := ctx.FormInt64("assignee") // TODO: use "optional" but not 0 in the future
|
||||
assigneeID := ctx.FormString("assignee")
|
||||
|
||||
opts := issues_model.IssuesOptions{
|
||||
LabelIDs: labelIDs,
|
||||
AssigneeID: optional.Some(assigneeID),
|
||||
AssigneeID: assigneeID,
|
||||
Owner: project.Owner,
|
||||
Doer: ctx.Doer,
|
||||
}
|
||||
|
||||
@ -208,10 +208,10 @@ func SearchIssues(ctx *context.Context) {
|
||||
if ctx.IsSigned {
|
||||
ctxUserID := ctx.Doer.ID
|
||||
if ctx.FormBool("created") {
|
||||
searchOpt.PosterID = optional.Some(ctxUserID)
|
||||
searchOpt.PosterID = strconv.FormatInt(ctxUserID, 10)
|
||||
}
|
||||
if ctx.FormBool("assigned") {
|
||||
searchOpt.AssigneeID = optional.Some(ctxUserID)
|
||||
searchOpt.AssigneeID = strconv.FormatInt(ctxUserID, 10)
|
||||
}
|
||||
if ctx.FormBool("mentioned") {
|
||||
searchOpt.MentionID = optional.Some(ctxUserID)
|
||||
@ -373,10 +373,10 @@ func SearchRepoIssuesJSON(ctx *context.Context) {
|
||||
}
|
||||
|
||||
if createdByID > 0 {
|
||||
searchOpt.PosterID = optional.Some(createdByID)
|
||||
searchOpt.PosterID = strconv.FormatInt(createdByID, 10)
|
||||
}
|
||||
if assignedByID > 0 {
|
||||
searchOpt.AssigneeID = optional.Some(assignedByID)
|
||||
searchOpt.AssigneeID = strconv.FormatInt(assignedByID, 10)
|
||||
}
|
||||
if mentionedByID > 0 {
|
||||
searchOpt.MentionID = optional.Some(mentionedByID)
|
||||
@ -490,7 +490,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt
|
||||
viewType = "all"
|
||||
}
|
||||
|
||||
assigneeID := ctx.FormInt64("assignee") // TODO: use "optional" but not 0 in the future
|
||||
assigneeID := ctx.FormString("assignee")
|
||||
posterUsername := ctx.FormString("poster")
|
||||
posterUserID := shared_user.GetFilterUserIDByName(ctx, posterUsername)
|
||||
var mentionedID, reviewRequestedID, reviewedID int64
|
||||
@ -498,11 +498,11 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt
|
||||
if ctx.IsSigned {
|
||||
switch viewType {
|
||||
case "created_by":
|
||||
posterUserID = optional.Some(ctx.Doer.ID)
|
||||
posterUserID = strconv.FormatInt(ctx.Doer.ID, 10)
|
||||
case "mentioned":
|
||||
mentionedID = ctx.Doer.ID
|
||||
case "assigned":
|
||||
assigneeID = ctx.Doer.ID
|
||||
assigneeID = fmt.Sprint(ctx.Doer.ID)
|
||||
case "review_requested":
|
||||
reviewRequestedID = ctx.Doer.ID
|
||||
case "reviewed_by":
|
||||
@ -532,7 +532,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt
|
||||
LabelIDs: labelIDs,
|
||||
MilestoneIDs: mileIDs,
|
||||
ProjectID: projectID,
|
||||
AssigneeID: optional.Some(assigneeID),
|
||||
AssigneeID: assigneeID,
|
||||
MentionedID: mentionedID,
|
||||
PosterID: posterUserID,
|
||||
ReviewRequestedID: reviewRequestedID,
|
||||
@ -613,7 +613,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt
|
||||
PageSize: setting.UI.IssuePagingNum,
|
||||
},
|
||||
RepoIDs: []int64{repo.ID},
|
||||
AssigneeID: optional.Some(assigneeID),
|
||||
AssigneeID: assigneeID,
|
||||
PosterID: posterUserID,
|
||||
MentionedID: mentionedID,
|
||||
ReviewRequestedID: reviewRequestedID,
|
||||
|
||||
@ -315,12 +315,12 @@ func ViewProject(ctx *context.Context) {
|
||||
|
||||
labelIDs := issue.PrepareFilterIssueLabels(ctx, ctx.Repo.Repository.ID, ctx.Repo.Owner)
|
||||
|
||||
assigneeID := ctx.FormInt64("assignee") // TODO: use "optional" but not 0 in the future
|
||||
assigneeID := ctx.FormString("assignee")
|
||||
|
||||
issuesMap, err := project_service.LoadIssuesFromProject(ctx, project, &issues_model.IssuesOptions{
|
||||
RepoIDs: []int64{ctx.Repo.Repository.ID},
|
||||
LabelIDs: labelIDs,
|
||||
AssigneeID: optional.Some(assigneeID),
|
||||
AssigneeID: assigneeID,
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("LoadIssuesOfColumns", err)
|
||||
|
||||
@ -8,9 +8,7 @@ import (
|
||||
"slices"
|
||||
"strconv"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/optional"
|
||||
)
|
||||
|
||||
func MakeSelfOnTop(doer *user.User, users []*user.User) []*user.User {
|
||||
@ -34,19 +32,20 @@ func MakeSelfOnTop(doer *user.User, users []*user.User) []*user.User {
|
||||
// So it's better to make it work like GitHub: users could input username directly.
|
||||
// Since it only converts the username to ID directly and is only used internally (to search issues), so no permission check is needed.
|
||||
// Return values:
|
||||
// * nil: no filter
|
||||
// * some(id): match the id, the id could be -1 to match the issues without assignee
|
||||
// * some(NonExistingID): match no issue (due to the user doesn't exist)
|
||||
func GetFilterUserIDByName(ctx context.Context, name string) optional.Option[int64] {
|
||||
// * "": no filter
|
||||
// * "{the-id}": match the id
|
||||
// * "(none)": match no issue (due to the user doesn't exist)
|
||||
func GetFilterUserIDByName(ctx context.Context, name string) string {
|
||||
if name == "" {
|
||||
return optional.None[int64]()
|
||||
return ""
|
||||
}
|
||||
u, err := user.GetUserByName(ctx, name)
|
||||
if err != nil {
|
||||
if id, err := strconv.ParseInt(name, 10, 64); err == nil {
|
||||
return optional.Some(id)
|
||||
return strconv.FormatInt(id, 10)
|
||||
}
|
||||
return optional.Some(db.NonExistingID)
|
||||
// The "(none)" is for internal usage only: when doer tries to search non-existing user, use "(none)" to return empty result.
|
||||
return "(none)"
|
||||
}
|
||||
return optional.Some(u.ID)
|
||||
return strconv.FormatInt(u.ID, 10)
|
||||
}
|
||||
|
||||
@ -501,9 +501,9 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
|
||||
case issues_model.FilterModeAll:
|
||||
case issues_model.FilterModeYourRepositories:
|
||||
case issues_model.FilterModeAssign:
|
||||
opts.AssigneeID = optional.Some(ctx.Doer.ID)
|
||||
opts.AssigneeID = strconv.FormatInt(ctx.Doer.ID, 10)
|
||||
case issues_model.FilterModeCreate:
|
||||
opts.PosterID = optional.Some(ctx.Doer.ID)
|
||||
opts.PosterID = strconv.FormatInt(ctx.Doer.ID, 10)
|
||||
case issues_model.FilterModeMention:
|
||||
opts.MentionedID = ctx.Doer.ID
|
||||
case issues_model.FilterModeReviewRequested:
|
||||
@ -792,9 +792,9 @@ func getUserIssueStats(ctx *context.Context, ctxUser *user_model.User, filterMod
|
||||
case issues_model.FilterModeYourRepositories:
|
||||
openClosedOpts.AllPublic = false
|
||||
case issues_model.FilterModeAssign:
|
||||
openClosedOpts.AssigneeID = optional.Some(doerID)
|
||||
openClosedOpts.AssigneeID = strconv.FormatInt(doerID, 10)
|
||||
case issues_model.FilterModeCreate:
|
||||
openClosedOpts.PosterID = optional.Some(doerID)
|
||||
openClosedOpts.PosterID = strconv.FormatInt(doerID, 10)
|
||||
case issues_model.FilterModeMention:
|
||||
openClosedOpts.MentionID = optional.Some(doerID)
|
||||
case issues_model.FilterModeReviewRequested:
|
||||
@ -816,8 +816,8 @@ func getUserIssueStats(ctx *context.Context, ctxUser *user_model.User, filterMod
|
||||
|
||||
// Below stats are for the left sidebar
|
||||
opts = opts.Copy(func(o *issue_indexer.SearchOptions) {
|
||||
o.AssigneeID = nil
|
||||
o.PosterID = nil
|
||||
o.AssigneeID = ""
|
||||
o.PosterID = ""
|
||||
o.MentionID = nil
|
||||
o.ReviewRequestedID = nil
|
||||
o.ReviewedID = nil
|
||||
@ -827,11 +827,11 @@ func getUserIssueStats(ctx *context.Context, ctxUser *user_model.User, filterMod
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret.AssignCount, err = issue_indexer.CountIssues(ctx, opts.Copy(func(o *issue_indexer.SearchOptions) { o.AssigneeID = optional.Some(doerID) }))
|
||||
ret.AssignCount, err = issue_indexer.CountIssues(ctx, opts.Copy(func(o *issue_indexer.SearchOptions) { o.AssigneeID = strconv.FormatInt(doerID, 10) }))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret.CreateCount, err = issue_indexer.CountIssues(ctx, opts.Copy(func(o *issue_indexer.SearchOptions) { o.PosterID = optional.Some(doerID) }))
|
||||
ret.CreateCount, err = issue_indexer.CountIssues(ctx, opts.Copy(func(o *issue_indexer.SearchOptions) { o.PosterID = strconv.FormatInt(doerID, 10) }))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -15,8 +15,8 @@
|
||||
"UserSearchList" $.Assignees
|
||||
"SelectedUserId" $.AssigneeID
|
||||
"TextFilterTitle" (ctx.Locale.Tr "repo.issues.filter_assignee")
|
||||
"TextZeroValue" (ctx.Locale.Tr "repo.issues.filter_assginee_no_select")
|
||||
"TextNegativeOne" (ctx.Locale.Tr "repo.issues.filter_assginee_no_assignee")
|
||||
"TextFilterMatchNone" (ctx.Locale.Tr "repo.issues.filter_assginee_no_assignee")
|
||||
"TextFilterMatchAny" (ctx.Locale.Tr "repo.issues.filter_assignee_any_assignee")
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -4,8 +4,8 @@
|
||||
* UserSearchList
|
||||
* SelectedUserId: 0 or empty means default, -1 means "no user is set"
|
||||
* TextFilterTitle
|
||||
* TextZeroValue: the text for "all issues"
|
||||
* TextNegativeOne: the text for "issues with no assignee"
|
||||
* TextFilterMatchNone: the text for "issues with no assignee"
|
||||
* TextFilterMatchAny: the text for "issues with any assignee"
|
||||
*/}}
|
||||
{{$queryLink := .QueryLink}}
|
||||
<div class="item ui dropdown jump {{if not .UserSearchList}}disabled{{end}}">
|
||||
@ -15,16 +15,24 @@
|
||||
<i class="icon">{{svg "octicon-search" 16}}</i>
|
||||
<input type="text" placeholder="{{ctx.Locale.Tr "repo.issues.filter_user_placeholder"}}">
|
||||
</div>
|
||||
{{if $.TextZeroValue}}
|
||||
<a class="item {{if not .SelectedUserId}}selected{{end}}" href="{{QueryBuild $queryLink $.QueryParamKey NIL}}">{{$.TextZeroValue}}</a>
|
||||
{{if $.TextFilterMatchNone}}
|
||||
{{$isSelected := eq .SelectedUserId "(none)"}}
|
||||
<a class="item" href="{{QueryBuild $queryLink $.QueryParamKey (Iif $isSelected NIL "(none)")}}">
|
||||
{{svg "octicon-check" 14 (Iif $isSelected "" "tw-invisible")}} {{$.TextFilterMatchNone}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{if $.TextNegativeOne}}
|
||||
<a class="item {{if eq .SelectedUserId -1}}selected{{end}}" href="{{QueryBuild $queryLink $.QueryParamKey -1}}">{{$.TextNegativeOne}}</a>
|
||||
{{if $.TextFilterMatchAny}}
|
||||
{{$isSelected := eq .SelectedUserId "(any)"}}
|
||||
<a class="item" href="{{QueryBuild $queryLink $.QueryParamKey (Iif $isSelected NIL "(any)")}}">
|
||||
{{svg "octicon-check" 14 (Iif $isSelected "" "tw-invisible")}} {{$.TextFilterMatchAny}}
|
||||
</a>
|
||||
{{end}}
|
||||
<div class="divider"></div>
|
||||
{{range .UserSearchList}}
|
||||
<a class="item {{if eq $.SelectedUserId .ID}}selected{{end}}" href="{{QueryBuild $queryLink $.QueryParamKey .ID}}">
|
||||
{{ctx.AvatarUtils.Avatar . 20}}{{template "repo/search_name" .}}
|
||||
{{range $user := .UserSearchList}}
|
||||
{{$isSelected := eq $.SelectedUserId (print $user.ID)}}
|
||||
<a class="item" href="{{QueryBuild $queryLink $.QueryParamKey (Iif $isSelected NIL $user.ID)}}">
|
||||
{{svg "octicon-check" 14 (Iif $isSelected "" "tw-invisible")}}
|
||||
{{ctx.AvatarUtils.Avatar $user 20}}{{template "repo/search_name" .}}
|
||||
</a>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
@ -94,8 +94,8 @@
|
||||
"UserSearchList" $.Assignees
|
||||
"SelectedUserId" $.AssigneeID
|
||||
"TextFilterTitle" (ctx.Locale.Tr "repo.issues.filter_assignee")
|
||||
"TextZeroValue" (ctx.Locale.Tr "repo.issues.filter_assginee_no_select")
|
||||
"TextNegativeOne" (ctx.Locale.Tr "repo.issues.filter_assginee_no_assignee")
|
||||
"TextFilterMatchNone" (ctx.Locale.Tr "repo.issues.filter_assginee_no_assignee")
|
||||
"TextFilterMatchAny" (ctx.Locale.Tr "repo.issues.filter_assignee_any_assignee")
|
||||
}}
|
||||
|
||||
{{if .IsSigned}}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
{{template "base/head" .}}
|
||||
<div role="main" aria-label="{{.Title}}" class="page-content ui one column stackable tw-text-center page grid oauth2-authorize-application-box">
|
||||
<div class="column seven wide">
|
||||
<div class="ui middle centered raised segments">
|
||||
<div role="main" aria-label="{{.Title}}" class="page-content oauth2-authorize-application-box">
|
||||
<div class="ui container tw-max-w-[500px]">
|
||||
<h3 class="ui top attached header">
|
||||
{{ctx.Locale.Tr "auth.authorize_title" .Application.Name}}
|
||||
</h3>
|
||||
@ -18,7 +17,7 @@
|
||||
<div class="ui attached segment">
|
||||
<p>{{ctx.Locale.Tr "auth.authorize_redirect_notice" .ApplicationRedirectDomainHTML}}</p>
|
||||
</div>
|
||||
<div class="ui attached segment">
|
||||
<div class="ui attached segment tw-text-center">
|
||||
<form method="post" action="{{AppSubUrl}}/login/oauth/grant">
|
||||
{{.CsrfTokenHtml}}
|
||||
<input type="hidden" name="client_id" value="{{.Application.ClientID}}">
|
||||
@ -32,5 +31,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{template "base/footer" .}}
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
{{template "base/head" .}}
|
||||
<div role="main" aria-label="{{.Title}}" class="page-content ui one column stackable tw-text-center page grid oauth2-authorize-application-box {{if .IsRepo}}repository{{end}}">
|
||||
{{if .IsRepo}}{{template "repo/header" .}}{{end}}
|
||||
<div class="column seven wide">
|
||||
<div class="ui middle centered raised segments">
|
||||
<div role="main" aria-label="{{.Title}}" class="page-content oauth2-authorize-application-box">
|
||||
<div class="ui container tw-max-w-[500px]">
|
||||
<h1 class="ui top attached header">
|
||||
{{ctx.Locale.Tr "auth.authorization_failed"}}
|
||||
</h1>
|
||||
@ -12,5 +10,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{template "base/footer" .}}
|
||||
|
||||
@ -19,7 +19,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
oauth2_provider "code.gitea.io/gitea/services/oauth2_provider"
|
||||
"code.gitea.io/gitea/services/oauth2_provider"
|
||||
"code.gitea.io/gitea/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
@ -1130,7 +1130,11 @@ $.fn.dropdown = function(parameters) {
|
||||
icon: {
|
||||
click: function(event) {
|
||||
iconClicked=true;
|
||||
if(module.has.search()) {
|
||||
// GITEA-PATCH: official dropdown doesn't support the search input in menu
|
||||
// so we need to make the menu could be shown when the search input is in menu and user clicks the icon
|
||||
const searchInputInMenu = Boolean($menu.find('.search > input').length);
|
||||
if(module.has.search() && !searchInputInMenu) {
|
||||
// the search input is in the dropdown element (but not in the popup menu), try to focus it
|
||||
if(!module.is.active()) {
|
||||
if(settings.showOnFocus){
|
||||
module.focusSearch();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user