feat(api): add more sorting to own repository list (#7256)

- Add more sorting options, by leveraging the existing `repo_model.OrderByFlatMap` map, to the `/api/v1/user/repos` endpoint.
- Swagger has been updated.
- Add (non-exhaustive) integration testing.
- Ref: gitnex/GitNex#1266

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/7256
Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org>
Co-authored-by: Gusted <postmaster@gusted.xyz>
Co-committed-by: Gusted <postmaster@gusted.xyz>
This commit is contained in:
Gusted 2025-03-17 20:03:24 +00:00 committed by Gusted
parent 9786982c6e
commit e2aa9adad7
3 changed files with 84 additions and 7 deletions

View file

@ -101,8 +101,9 @@ func ListMyRepos(ctx *context.APIContext) {
// type: integer // type: integer
// - name: order_by // - name: order_by
// in: query // in: query
// description: order the repositories by name (default), id, or size // description: order the repositories
// type: string // type: string
// enum: [name, id, newest, oldest, recentupdate, leastupdate, reversealphabetically, alphabetically, reversesize, size, reversegitsize, gitsize, reverselfssize, lfssize, moststars, feweststars, mostforks, fewestforks]
// responses: // responses:
// "200": // "200":
// "$ref": "#/responses/RepositoryList" // "$ref": "#/responses/RepositoryList"
@ -124,15 +125,16 @@ func ListMyRepos(ctx *context.APIContext) {
switch orderBy { switch orderBy {
case "name": case "name":
opts.OrderBy = "name ASC" opts.OrderBy = "name ASC"
case "size":
opts.OrderBy = "size DESC"
case "id": case "id":
opts.OrderBy = "id ASC" opts.OrderBy = "id ASC"
case "":
default: default:
if orderBy, ok := repo_model.OrderByFlatMap[orderBy]; ok {
opts.OrderBy = orderBy
} else if orderBy != "" {
ctx.Error(http.StatusUnprocessableEntity, "", "invalid order_by") ctx.Error(http.StatusUnprocessableEntity, "", "invalid order_by")
return return
} }
}
repos, count, err := repo_model.SearchRepository(ctx, opts) repos, count, err := repo_model.SearchRepository(ctx, opts)
if err != nil { if err != nil {

View file

@ -19361,8 +19361,28 @@
"in": "query" "in": "query"
}, },
{ {
"enum": [
"name",
"id",
"newest",
"oldest",
"recentupdate",
"leastupdate",
"reversealphabetically",
"alphabetically",
"reversesize",
"size",
"reversegitsize",
"gitsize",
"reverselfssize",
"lfssize",
"moststars",
"feweststars",
"mostforks",
"fewestforks"
],
"type": "string", "type": "string",
"description": "order the repositories by name (default), id, or size", "description": "order the repositories",
"name": "order_by", "name": "order_by",
"in": "query" "in": "query"
} }

View file

@ -764,3 +764,58 @@ func TestAPIRepoCommitPull(t *testing.T) {
req = NewRequest(t, "GET", "/api/v1/repos/user2/repo1/commits/not-a-commit/pull") req = NewRequest(t, "GET", "/api/v1/repos/user2/repo1/commits/not-a-commit/pull")
MakeRequest(t, req, http.StatusNotFound) MakeRequest(t, req, http.StatusNotFound)
} }
func TestAPIListOwnRepoSorting(t *testing.T) {
defer tests.PrepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository, auth_model.AccessTokenScopeReadUser)
t.Run("No sorting", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
MakeRequest(t, NewRequest(t, "GET", "/api/v1/user/repos").AddTokenAuth(token), http.StatusOK)
})
t.Run("ID sorting", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
var repos []api.Repository
resp := MakeRequest(t, NewRequest(t, "GET", "/api/v1/user/repos?limit=2&order_by=id").AddTokenAuth(token), http.StatusOK)
DecodeJSON(t, resp, &repos)
assert.Len(t, repos, 2)
assert.EqualValues(t, 1, repos[0].ID)
assert.EqualValues(t, 2, repos[1].ID)
})
t.Run("Name sorting", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
var repos []api.Repository
resp := MakeRequest(t, NewRequest(t, "GET", "/api/v1/user/repos?limit=2&order_by=name").AddTokenAuth(token), http.StatusOK)
DecodeJSON(t, resp, &repos)
assert.Len(t, repos, 2)
assert.EqualValues(t, "big_test_private_4", repos[0].Name)
// Postgres doesn't do ascii sorting.
if setting.Database.Type.IsPostgreSQL() {
assert.EqualValues(t, "commitsonpr", repos[1].Name)
} else {
assert.EqualValues(t, "commits_search_test", repos[1].Name)
}
})
t.Run("Reverse alphabetic sorting", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
var repos []api.Repository
resp := MakeRequest(t, NewRequest(t, "GET", "/api/v1/user/repos?limit=2&order_by=reversealphabetically").AddTokenAuth(token), http.StatusOK)
DecodeJSON(t, resp, &repos)
assert.Len(t, repos, 2)
assert.EqualValues(t, "utf8", repos[0].Name)
assert.EqualValues(t, "test_workflows", repos[1].Name)
})
}