mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-10-05 19:30:58 +00:00
Merge remote-tracking branch 'origin/forgejo' into fix-context-timeout
This commit is contained in:
commit
ee58dfaab9
15 changed files with 187 additions and 27 deletions
4
go.mod
4
go.mod
|
@ -71,7 +71,7 @@ require (
|
||||||
github.com/lib/pq v1.10.9
|
github.com/lib/pq v1.10.9
|
||||||
github.com/markbates/goth v1.80.0
|
github.com/markbates/goth v1.80.0
|
||||||
github.com/mattn/go-isatty v0.0.20
|
github.com/mattn/go-isatty v0.0.20
|
||||||
github.com/mattn/go-sqlite3 v1.14.28
|
github.com/mattn/go-sqlite3 v1.14.29
|
||||||
github.com/meilisearch/meilisearch-go v0.31.0
|
github.com/meilisearch/meilisearch-go v0.31.0
|
||||||
github.com/mholt/archiver/v3 v3.5.1
|
github.com/mholt/archiver/v3 v3.5.1
|
||||||
github.com/microcosm-cc/bluemonday v1.0.27
|
github.com/microcosm-cc/bluemonday v1.0.27
|
||||||
|
@ -244,7 +244,7 @@ require (
|
||||||
|
|
||||||
replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1
|
replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1
|
||||||
|
|
||||||
replace github.com/nektos/act => code.forgejo.org/forgejo/act v1.32.0
|
replace github.com/nektos/act => code.forgejo.org/forgejo/act v1.33.0
|
||||||
|
|
||||||
replace github.com/mholt/archiver/v3 => code.forgejo.org/forgejo/archiver/v3 v3.5.1
|
replace github.com/mholt/archiver/v3 => code.forgejo.org/forgejo/archiver/v3 v3.5.1
|
||||||
|
|
||||||
|
|
8
go.sum
8
go.sum
|
@ -4,8 +4,8 @@ code.forgejo.org/f3/gof3/v3 v3.11.0 h1:f/xToKwqTgxG6PYxvewywjDQyCcyHEEJ6sZqUitFs
|
||||||
code.forgejo.org/f3/gof3/v3 v3.11.0/go.mod h1:4FaRUNSQGBiD1M0DuB0yNv+Z2wMtlOeckgygHSSq4KQ=
|
code.forgejo.org/f3/gof3/v3 v3.11.0/go.mod h1:4FaRUNSQGBiD1M0DuB0yNv+Z2wMtlOeckgygHSSq4KQ=
|
||||||
code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251 h1:HTZl3CBk3ABNYtFI6TPLvJgGKFIhKT5CBk0sbOtkDKU=
|
code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251 h1:HTZl3CBk3ABNYtFI6TPLvJgGKFIhKT5CBk0sbOtkDKU=
|
||||||
code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:PphB88CPbx601QrWPMZATeorACeVmQlyv3u+uUMbSaM=
|
code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:PphB88CPbx601QrWPMZATeorACeVmQlyv3u+uUMbSaM=
|
||||||
code.forgejo.org/forgejo/act v1.32.0 h1:hns2WvrJs6qWCmvzoSllNGNzSvcDMcSvJvVtQj3FaQc=
|
code.forgejo.org/forgejo/act v1.33.0 h1:ayQTXkpk+Vj5/yQMNZagA0xpQgGVeSbcrPXcIS3K1kY=
|
||||||
code.forgejo.org/forgejo/act v1.32.0/go.mod h1:WkmxVBteC4zoyQGYp8ZFZY7Xb+jat+b7ChvqW6TxqF8=
|
code.forgejo.org/forgejo/act v1.33.0/go.mod h1:WkmxVBteC4zoyQGYp8ZFZY7Xb+jat+b7ChvqW6TxqF8=
|
||||||
code.forgejo.org/forgejo/archiver/v3 v3.5.1 h1:UmmbA7D5550uf71SQjarmrn6yKwOGxtEjb3jaYYtmSE=
|
code.forgejo.org/forgejo/archiver/v3 v3.5.1 h1:UmmbA7D5550uf71SQjarmrn6yKwOGxtEjb3jaYYtmSE=
|
||||||
code.forgejo.org/forgejo/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
|
code.forgejo.org/forgejo/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
|
||||||
code.forgejo.org/forgejo/go-rpmutils v1.0.0 h1:RZGGeKt70p/WaIEL97pyT6uiiEIoN8/aLmS5Z6WmX0M=
|
code.forgejo.org/forgejo/go-rpmutils v1.0.0 h1:RZGGeKt70p/WaIEL97pyT6uiiEIoN8/aLmS5Z6WmX0M=
|
||||||
|
@ -395,8 +395,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A=
|
github.com/mattn/go-sqlite3 v1.14.29 h1:1O6nRLJKvsi1H2Sj0Hzdfojwt8GiGKm+LOfLaBFaouQ=
|
||||||
github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
github.com/mattn/go-sqlite3 v1.14.29/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
github.com/meilisearch/meilisearch-go v0.31.0 h1:yZRhY1qJqdH8h6GFZALGtkDLyj8f9v5aJpsNMyrUmnY=
|
github.com/meilisearch/meilisearch-go v0.31.0 h1:yZRhY1qJqdH8h6GFZALGtkDLyj8f9v5aJpsNMyrUmnY=
|
||||||
github.com/meilisearch/meilisearch-go v0.31.0/go.mod h1:aNtyuwurDg/ggxQIcKqWH6G9g2ptc8GyY7PLY4zMn/g=
|
github.com/meilisearch/meilisearch-go v0.31.0/go.mod h1:aNtyuwurDg/ggxQIcKqWH6G9g2ptc8GyY7PLY4zMn/g=
|
||||||
github.com/mholt/acmez/v3 v3.1.2 h1:auob8J/0FhmdClQicvJvuDavgd5ezwLBfKuYmynhYzc=
|
github.com/mholt/acmez/v3 v3.1.2 h1:auob8J/0FhmdClQicvJvuDavgd5ezwLBfKuYmynhYzc=
|
||||||
|
|
|
@ -35,6 +35,7 @@ var (
|
||||||
PasswordHashAlgo string
|
PasswordHashAlgo string
|
||||||
PasswordCheckPwn bool
|
PasswordCheckPwn bool
|
||||||
SuccessfulTokensCacheSize int
|
SuccessfulTokensCacheSize int
|
||||||
|
DisableQueryAuthToken bool
|
||||||
CSRFCookieName = "_csrf"
|
CSRFCookieName = "_csrf"
|
||||||
CSRFCookieHTTPOnly = true
|
CSRFCookieHTTPOnly = true
|
||||||
)
|
)
|
||||||
|
@ -159,4 +160,14 @@ func loadSecurityFrom(rootCfg ConfigProvider) {
|
||||||
PasswordComplexity = append(PasswordComplexity, name)
|
PasswordComplexity = append(PasswordComplexity, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sectionHasDisableQueryAuthToken := sec.HasKey("DISABLE_QUERY_AUTH_TOKEN")
|
||||||
|
|
||||||
|
// TODO: default value should be true in future releases
|
||||||
|
DisableQueryAuthToken = sec.Key("DISABLE_QUERY_AUTH_TOKEN").MustBool(false)
|
||||||
|
|
||||||
|
// warn if the setting is set to false explicitly
|
||||||
|
if sectionHasDisableQueryAuthToken && !DisableQueryAuthToken {
|
||||||
|
log.Warn("Enabling Query API Auth tokens is not recommended. DISABLE_QUERY_AUTH_TOKEN will default to true in gitea 1.23 and will be removed in gitea 1.24.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ func Middlewares() (stack []any) {
|
||||||
return append(stack,
|
return append(stack,
|
||||||
context.APIContexter(),
|
context.APIContexter(),
|
||||||
|
|
||||||
|
checkDeprecatedAuthMethods,
|
||||||
// Get user from session if logged in.
|
// Get user from session if logged in.
|
||||||
apiAuth(buildAuthGroup()),
|
apiAuth(buildAuthGroup()),
|
||||||
verifyAuthWithOptions(&common.VerifyOptions{
|
verifyAuthWithOptions(&common.VerifyOptions{
|
||||||
|
@ -126,6 +127,13 @@ func verifyAuthWithOptions(options *common.VerifyOptions) func(ctx *context.APIC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check for and warn against deprecated authentication options
|
||||||
|
func checkDeprecatedAuthMethods(ctx *context.APIContext) {
|
||||||
|
if ctx.FormString("token") != "" || ctx.FormString("access_token") != "" {
|
||||||
|
ctx.Resp.Header().Set("Warning", "token and access_token API authentication is deprecated and will be removed in gitea 1.23. Please use AuthorizationHeaderToken instead. Existing queries will continue to work but without authorization.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func securityHeaders() func(http.Handler) http.Handler {
|
func securityHeaders() func(http.Handler) http.Handler {
|
||||||
return func(next http.Handler) http.Handler {
|
return func(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
|
||||||
|
|
|
@ -436,26 +436,6 @@ func SearchUsers(ctx *context.APIContext) {
|
||||||
|
|
||||||
listOptions := utils.GetListOptions(ctx)
|
listOptions := utils.GetListOptions(ctx)
|
||||||
|
|
||||||
sort := ctx.FormString("sort")
|
|
||||||
var orderBy db.SearchOrderBy
|
|
||||||
|
|
||||||
switch sort {
|
|
||||||
case "oldest":
|
|
||||||
orderBy = db.SearchOrderByOldest
|
|
||||||
case "newest":
|
|
||||||
orderBy = db.SearchOrderByNewest
|
|
||||||
case "alphabetically":
|
|
||||||
orderBy = db.SearchOrderByAlphabetically
|
|
||||||
case "reversealphabetically":
|
|
||||||
orderBy = db.SearchOrderByAlphabeticallyReverse
|
|
||||||
case "recentupdate":
|
|
||||||
orderBy = db.SearchOrderByRecentUpdated
|
|
||||||
case "leastupdate":
|
|
||||||
orderBy = db.SearchOrderByLeastUpdated
|
|
||||||
default:
|
|
||||||
orderBy = db.SearchOrderByAlphabetically
|
|
||||||
}
|
|
||||||
|
|
||||||
intSource, err := strconv.ParseInt(ctx.FormString("source_id"), 10, 64)
|
intSource, err := strconv.ParseInt(ctx.FormString("source_id"), 10, 64)
|
||||||
var sourceID optional.Option[int64]
|
var sourceID optional.Option[int64]
|
||||||
if ctx.FormString("source_id") == "" || err != nil {
|
if ctx.FormString("source_id") == "" || err != nil {
|
||||||
|
@ -469,7 +449,7 @@ func SearchUsers(ctx *context.APIContext) {
|
||||||
Type: user_model.UserTypeIndividual,
|
Type: user_model.UserTypeIndividual,
|
||||||
LoginName: ctx.FormTrim("login_name"),
|
LoginName: ctx.FormTrim("login_name"),
|
||||||
SourceID: sourceID,
|
SourceID: sourceID,
|
||||||
OrderBy: orderBy,
|
OrderBy: utils.GetDbSearchOrder(ctx),
|
||||||
ListOptions: listOptions,
|
ListOptions: listOptions,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
//
|
//
|
||||||
// Security:
|
// Security:
|
||||||
// - BasicAuth :
|
// - BasicAuth :
|
||||||
|
// - Token :
|
||||||
|
// - AccessToken :
|
||||||
// - AuthorizationHeaderToken :
|
// - AuthorizationHeaderToken :
|
||||||
// - SudoParam :
|
// - SudoParam :
|
||||||
// - SudoHeader :
|
// - SudoHeader :
|
||||||
|
@ -30,6 +32,16 @@
|
||||||
// SecurityDefinitions:
|
// SecurityDefinitions:
|
||||||
// BasicAuth:
|
// BasicAuth:
|
||||||
// type: basic
|
// type: basic
|
||||||
|
// Token:
|
||||||
|
// type: apiKey
|
||||||
|
// name: token
|
||||||
|
// in: query
|
||||||
|
// description: This authentication option is deprecated for removal in Forgejo v13.0.0. Please use AuthorizationHeaderToken instead.
|
||||||
|
// AccessToken:
|
||||||
|
// type: apiKey
|
||||||
|
// name: access_token
|
||||||
|
// in: query
|
||||||
|
// description: This authentication option is deprecated for removal in Forgejo v13.0.0. Please use AuthorizationHeaderToken instead.
|
||||||
// AuthorizationHeaderToken:
|
// AuthorizationHeaderToken:
|
||||||
// type: apiKey
|
// type: apiKey
|
||||||
// name: Authorization
|
// name: Authorization
|
||||||
|
|
|
@ -33,6 +33,11 @@ func Search(ctx *context.APIContext) {
|
||||||
// description: ID of the user to search for
|
// description: ID of the user to search for
|
||||||
// type: integer
|
// type: integer
|
||||||
// format: int64
|
// format: int64
|
||||||
|
// - name: sort
|
||||||
|
// in: query
|
||||||
|
// description: sort order of results
|
||||||
|
// type: string
|
||||||
|
// enum: [oldest, newest, alphabetically, reversealphabetically, recentupdate, leastupdate]
|
||||||
// - name: page
|
// - name: page
|
||||||
// in: query
|
// in: query
|
||||||
// description: page number of results to return (1-based)
|
// description: page number of results to return (1-based)
|
||||||
|
@ -81,6 +86,7 @@ func Search(ctx *context.APIContext) {
|
||||||
SearchByEmail: true,
|
SearchByEmail: true,
|
||||||
Visible: visible,
|
Visible: visible,
|
||||||
ListOptions: listOptions,
|
ListOptions: listOptions,
|
||||||
|
OrderBy: utils.GetDbSearchOrder(ctx),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.JSON(http.StatusInternalServerError, map[string]any{
|
ctx.JSON(http.StatusInternalServerError, map[string]any{
|
||||||
|
|
28
routers/api/v1/utils/db_search_order.go
Normal file
28
routers/api/v1/utils/db_search_order.go
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"forgejo.org/models/db"
|
||||||
|
"forgejo.org/services/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetDbSearchOrder(ctx *context.APIContext) db.SearchOrderBy {
|
||||||
|
switch ctx.FormString("sort") {
|
||||||
|
case "oldest":
|
||||||
|
return db.SearchOrderByOldest
|
||||||
|
case "newest":
|
||||||
|
return db.SearchOrderByNewest
|
||||||
|
case "alphabetically":
|
||||||
|
return db.SearchOrderByAlphabetically
|
||||||
|
case "reversealphabetically":
|
||||||
|
return db.SearchOrderByAlphabeticallyReverse
|
||||||
|
case "recentupdate":
|
||||||
|
return db.SearchOrderByRecentUpdated
|
||||||
|
case "leastupdate":
|
||||||
|
return db.SearchOrderByLeastUpdated
|
||||||
|
default:
|
||||||
|
return db.SearchOrderByAlphabetically
|
||||||
|
}
|
||||||
|
}
|
|
@ -122,6 +122,18 @@ func (o *OAuth2) Name() string {
|
||||||
// representing whether the token exists or not
|
// representing whether the token exists or not
|
||||||
func parseToken(req *http.Request) (string, bool) {
|
func parseToken(req *http.Request) (string, bool) {
|
||||||
_ = req.ParseForm()
|
_ = req.ParseForm()
|
||||||
|
if !setting.DisableQueryAuthToken {
|
||||||
|
// Check token.
|
||||||
|
if token := req.Form.Get("token"); token != "" {
|
||||||
|
return token, true
|
||||||
|
}
|
||||||
|
// Check access token.
|
||||||
|
if token := req.Form.Get("access_token"); token != "" {
|
||||||
|
return token, true
|
||||||
|
}
|
||||||
|
} else if req.Form.Get("token") != "" || req.Form.Get("access_token") != "" {
|
||||||
|
log.Warn("API token sent in query string but DISABLE_QUERY_AUTH_TOKEN=true")
|
||||||
|
}
|
||||||
|
|
||||||
// check header token
|
// check header token
|
||||||
if auHead := req.Header.Get("Authorization"); auHead != "" {
|
if auHead := req.Header.Get("Authorization"); auHead != "" {
|
||||||
|
|
32
templates/swagger/v1_json.tmpl
generated
32
templates/swagger/v1_json.tmpl
generated
|
@ -20284,6 +20284,20 @@
|
||||||
"name": "uid",
|
"name": "uid",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"enum": [
|
||||||
|
"oldest",
|
||||||
|
"newest",
|
||||||
|
"alphabetically",
|
||||||
|
"reversealphabetically",
|
||||||
|
"recentupdate",
|
||||||
|
"leastupdate"
|
||||||
|
],
|
||||||
|
"type": "string",
|
||||||
|
"description": "sort order of results",
|
||||||
|
"name": "sort",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "page number of results to return (1-based)",
|
"description": "page number of results to return (1-based)",
|
||||||
|
@ -30084,6 +30098,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"securityDefinitions": {
|
"securityDefinitions": {
|
||||||
|
"AccessToken": {
|
||||||
|
"description": "This authentication option is deprecated for removal in Forgejo v13.0.0. Please use AuthorizationHeaderToken instead.",
|
||||||
|
"type": "apiKey",
|
||||||
|
"name": "access_token",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
"AuthorizationHeaderToken": {
|
"AuthorizationHeaderToken": {
|
||||||
"description": "API tokens must be prepended with \"token\" followed by a space.",
|
"description": "API tokens must be prepended with \"token\" followed by a space.",
|
||||||
"type": "apiKey",
|
"type": "apiKey",
|
||||||
|
@ -30110,12 +30130,24 @@
|
||||||
"type": "apiKey",
|
"type": "apiKey",
|
||||||
"name": "X-FORGEJO-OTP",
|
"name": "X-FORGEJO-OTP",
|
||||||
"in": "header"
|
"in": "header"
|
||||||
|
},
|
||||||
|
"Token": {
|
||||||
|
"description": "This authentication option is deprecated for removal in Forgejo v13.0.0. Please use AuthorizationHeaderToken instead.",
|
||||||
|
"type": "apiKey",
|
||||||
|
"name": "token",
|
||||||
|
"in": "query"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"BasicAuth": []
|
"BasicAuth": []
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"Token": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AccessToken": []
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"AuthorizationHeaderToken": []
|
"AuthorizationHeaderToken": []
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,6 +10,9 @@ export async function validate_form({page}: {page: Page}, scope: 'form' | 'field
|
||||||
// legacy dropdowns don't use semantic HTML yet,
|
// legacy dropdowns don't use semantic HTML yet,
|
||||||
// avoid using these where possible
|
// avoid using these where possible
|
||||||
'.ui.dropdown',
|
'.ui.dropdown',
|
||||||
|
// for some reason we use h1 to h5 for form sections,
|
||||||
|
// and it usually makes no sense semantically
|
||||||
|
'.ui.top.attached.header',
|
||||||
];
|
];
|
||||||
await accessibilityCheck({page}, [scope], excludedElements, []);
|
await accessibilityCheck({page}, [scope], excludedElements, []);
|
||||||
|
|
||||||
|
|
|
@ -4,18 +4,25 @@
|
||||||
package integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
auth_model "forgejo.org/models/auth"
|
auth_model "forgejo.org/models/auth"
|
||||||
|
"forgejo.org/models/db"
|
||||||
"forgejo.org/models/unittest"
|
"forgejo.org/models/unittest"
|
||||||
user_model "forgejo.org/models/user"
|
user_model "forgejo.org/models/user"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
api "forgejo.org/modules/structs"
|
api "forgejo.org/modules/structs"
|
||||||
"forgejo.org/modules/test"
|
"forgejo.org/modules/test"
|
||||||
|
"forgejo.org/modules/timeutil"
|
||||||
"forgejo.org/tests"
|
"forgejo.org/tests"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SearchResults struct {
|
type SearchResults struct {
|
||||||
|
@ -179,3 +186,61 @@ func TestAPIUserSearchByEmail(t *testing.T) {
|
||||||
assert.Len(t, results.Data, 1)
|
assert.Len(t, results.Data, 1)
|
||||||
assert.Equal(t, query, results.Data[0].Email)
|
assert.Equal(t, query, results.Data[0].Email)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUsersSearchSorted(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
createTimestamp := time.Now().Unix() - 1000
|
||||||
|
updateTimestamp := time.Now().Unix() - 500
|
||||||
|
sess := db.GetEngine(context.Background())
|
||||||
|
|
||||||
|
for i := int64(1); i <= 10; i++ {
|
||||||
|
name := "sorttest" + strconv.Itoa(int(i))
|
||||||
|
user := &user_model.User{
|
||||||
|
Name: name,
|
||||||
|
LowerName: name,
|
||||||
|
LoginName: name,
|
||||||
|
Email: name + "@example.com",
|
||||||
|
Passwd: name + ".password",
|
||||||
|
Avatar: "xyz",
|
||||||
|
Type: user_model.UserTypeIndividual,
|
||||||
|
LoginType: auth_model.OAuth2,
|
||||||
|
CreatedUnix: timeutil.TimeStamp(createTimestamp - i),
|
||||||
|
UpdatedUnix: timeutil.TimeStamp(updateTimestamp - i),
|
||||||
|
}
|
||||||
|
_, err := sess.NoAutoTime().Insert(user)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
session := loginUser(t, "user1")
|
||||||
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadUser)
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
sortType string
|
||||||
|
expectedUsers []string
|
||||||
|
}{
|
||||||
|
{"alphabetically", []string{"sorttest1", "sorttest10", "sorttest2", "sorttest3"}},
|
||||||
|
{"reversealphabetically", []string{"sorttest9", "sorttest8", "sorttest7", "sorttest6"}},
|
||||||
|
{"newest", []string{"sorttest1", "sorttest2", "sorttest3", "sorttest4"}},
|
||||||
|
{"oldest", []string{"sorttest10", "sorttest9", "sorttest8", "sorttest7"}},
|
||||||
|
{"recentupdate", []string{"sorttest1", "sorttest2", "sorttest3", "sorttest4"}},
|
||||||
|
{"leastupdate", []string{"sorttest10", "sorttest9", "sorttest8", "sorttest7"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
req := NewRequest(
|
||||||
|
t,
|
||||||
|
"GET",
|
||||||
|
fmt.Sprintf("/api/v1/users/search?q=sorttest&sort=%s&limit=4",
|
||||||
|
testCase.sortType,
|
||||||
|
),
|
||||||
|
).AddTokenAuth(token)
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
var results SearchResults
|
||||||
|
DecodeJSON(t, resp, &results)
|
||||||
|
assert.Len(t, results.Data, 4)
|
||||||
|
for i, searchData := range results.Data {
|
||||||
|
assert.Equalf(t, testCase.expectedUsers[i], searchData.UserName, "Sort type: %s, index %d", testCase.sortType, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -92,6 +92,7 @@ DISABLE_GIT_HOOKS = false
|
||||||
INSTALL_LOCK = true
|
INSTALL_LOCK = true
|
||||||
SECRET_KEY = 9pCviYTWSb
|
SECRET_KEY = 9pCviYTWSb
|
||||||
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTU1NTE2MTh9.hhSVGOANkaKk3vfCd2jDOIww4pUk0xtg9JRde5UogyQ
|
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTU1NTE2MTh9.hhSVGOANkaKk3vfCd2jDOIww4pUk0xtg9JRde5UogyQ
|
||||||
|
DISABLE_QUERY_AUTH_TOKEN = true
|
||||||
|
|
||||||
[lfs]
|
[lfs]
|
||||||
PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mysql/data/lfs
|
PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mysql/data/lfs
|
||||||
|
|
|
@ -97,6 +97,7 @@ DISABLE_GIT_HOOKS = false
|
||||||
INSTALL_LOCK = true
|
INSTALL_LOCK = true
|
||||||
SECRET_KEY = 9pCviYTWSb
|
SECRET_KEY = 9pCviYTWSb
|
||||||
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTU1NTE2MTh9.hhSVGOANkaKk3vfCd2jDOIww4pUk0xtg9JRde5UogyQ
|
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTU1NTE2MTh9.hhSVGOANkaKk3vfCd2jDOIww4pUk0xtg9JRde5UogyQ
|
||||||
|
DISABLE_QUERY_AUTH_TOKEN = true
|
||||||
|
|
||||||
[lfs]
|
[lfs]
|
||||||
MINIO_BASE_PATH = lfs/
|
MINIO_BASE_PATH = lfs/
|
||||||
|
|
|
@ -94,6 +94,7 @@ DISABLE_GIT_HOOKS = false
|
||||||
INSTALL_LOCK = true
|
INSTALL_LOCK = true
|
||||||
SECRET_KEY = 9pCviYTWSb
|
SECRET_KEY = 9pCviYTWSb
|
||||||
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTI3OTU5ODN9.OQkH5UmzID2XBdwQ9TAI6Jj2t1X-wElVTjbE7aoN4I8
|
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTI3OTU5ODN9.OQkH5UmzID2XBdwQ9TAI6Jj2t1X-wElVTjbE7aoN4I8
|
||||||
|
DISABLE_QUERY_AUTH_TOKEN = true
|
||||||
|
|
||||||
[oauth2]
|
[oauth2]
|
||||||
JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko
|
JWT_SECRET = KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue