outposts: implement general paginator for list API requests (#10619)
* outposts: implement general paginator Signed-off-by: Jens Langhammer <jens@goauthentik.io> * migrate LDAP Signed-off-by: Jens Langhammer <jens@goauthentik.io> * change main outpost refresh logic to use paginator everywhere Signed-off-by: Jens Langhammer <jens@goauthentik.io> * add comments to understand anything Signed-off-by: Jens Langhammer <jens@goauthentik.io> * actually use paginator everywhere Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
64
internal/outpost/ak/api_utils.go
Normal file
64
internal/outpost/ak/api_utils.go
Normal file
@ -0,0 +1,64 @@
|
||||
package ak
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"goauthentik.io/api/v3"
|
||||
)
|
||||
|
||||
// Generic interface that mimics a generated request by the API client
|
||||
// Requires mainly `Treq` which will be the actual request type, and
|
||||
// `Tres` which is the response type
|
||||
type PaginatorRequest[Treq any, Tres any] interface {
|
||||
Page(page int32) Treq
|
||||
PageSize(size int32) Treq
|
||||
Execute() (Tres, *http.Response, error)
|
||||
}
|
||||
|
||||
// Generic interface that mimics a generated response by the API client
|
||||
type PaginatorResponse[Tobj any] interface {
|
||||
GetResults() []Tobj
|
||||
GetPagination() api.Pagination
|
||||
}
|
||||
|
||||
// Paginator options for page size
|
||||
type PaginatorOptions struct {
|
||||
PageSize int
|
||||
Logger *log.Entry
|
||||
}
|
||||
|
||||
// Automatically fetch all objects from an API endpoint using the pagination
|
||||
// data received from the server.
|
||||
func Paginator[Tobj any, Treq any, Tres PaginatorResponse[Tobj]](
|
||||
req PaginatorRequest[Treq, Tres],
|
||||
opts PaginatorOptions,
|
||||
) ([]Tobj, error) {
|
||||
fetchOffset := func(page int32) (Tres, error) {
|
||||
req.Page(page)
|
||||
req.PageSize(int32(opts.PageSize))
|
||||
res, _, err := req.Execute()
|
||||
if err != nil {
|
||||
opts.Logger.WithError(err).WithField("page", page).Warning("failed to fetch page")
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
var page int32 = 1
|
||||
errs := make([]error, 0)
|
||||
objects := make([]Tobj, 0)
|
||||
for {
|
||||
apiObjects, err := fetchOffset(page)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
objects = append(objects, apiObjects.GetResults()...)
|
||||
if apiObjects.GetPagination().Next > 0 {
|
||||
page += 1
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return objects, errors.Join(errs...)
|
||||
}
|
Reference in New Issue
Block a user