* 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>
		
			
				
	
	
		
			65 lines
		
	
	
		
			1.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			65 lines
		
	
	
		
			1.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
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...)
 | 
						|
}
 |