mirror of
https://github.com/fleetdm/fleet
synced 2026-05-20 23:48:52 +00:00
Add pagination to List* endpoints (#309)
- Introduce kolide.ListOptions to store pagination params (in the future it can also store ordering/filtering params) - Refactor service/datastore methods to take kolide.ListOptions - Implement pagination
This commit is contained in:
parent
f9fa3e289f
commit
7f636aef4f
50 changed files with 478 additions and 100 deletions
|
|
@ -84,3 +84,15 @@ func openGORM(driver, conn string, maxAttempts int) (*gorm.DB, error) {
|
|||
}
|
||||
return db, nil
|
||||
}
|
||||
|
||||
// applyLimitOffset applies the appropriate limit and offset parameters to the
|
||||
// gorm.DB instance, returning a DB that can be chained as usual with *gorm.DB.
|
||||
func (orm *gormDB) applyListOptions(opt kolide.ListOptions) *gorm.DB {
|
||||
if opt.PerPage == 0 {
|
||||
// PerPage value of 0 indicates unlimited
|
||||
return orm.DB
|
||||
}
|
||||
|
||||
offset := opt.Page * opt.PerPage
|
||||
return orm.DB.Limit(opt.PerPage).Offset(offset)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,9 +100,9 @@ func (orm gormDB) Host(id uint) (*kolide.Host, error) {
|
|||
return host, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) Hosts() ([]*kolide.Host, error) {
|
||||
func (orm gormDB) Hosts(opt kolide.ListOptions) ([]*kolide.Host, error) {
|
||||
var hosts []*kolide.Host
|
||||
err := orm.DB.Find(&hosts).Error
|
||||
err := orm.applyListOptions(opt).Find(&hosts).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@ func (orm gormDB) InviteByEmail(email string) (*kolide.Invite, error) {
|
|||
return invite, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) Invites() ([]*kolide.Invite, error) {
|
||||
func (orm gormDB) Invites(opt kolide.ListOptions) ([]*kolide.Invite, error) {
|
||||
var invites []*kolide.Invite
|
||||
err := orm.DB.Find(&invites).Error
|
||||
err := orm.applyListOptions(opt).Find(&invites).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,9 +54,9 @@ func (orm gormDB) Label(lid uint) (*kolide.Label, error) {
|
|||
return label, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) Labels() ([]*kolide.Label, error) {
|
||||
func (orm gormDB) Labels(opt kolide.ListOptions) ([]*kolide.Label, error) {
|
||||
var labels []*kolide.Label
|
||||
err := orm.DB.Find(&labels).Error
|
||||
err := orm.applyListOptions(opt).Find(&labels).Error
|
||||
return labels, err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,9 +50,9 @@ func (orm gormDB) Pack(pid uint) (*kolide.Pack, error) {
|
|||
return pack, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) Packs() ([]*kolide.Pack, error) {
|
||||
func (orm gormDB) Packs(opt kolide.ListOptions) ([]*kolide.Pack, error) {
|
||||
var packs []*kolide.Pack
|
||||
err := orm.DB.Find(&packs).Error
|
||||
err := orm.applyListOptions(opt).Find(&packs).Error
|
||||
return packs, err
|
||||
}
|
||||
|
||||
|
|
@ -151,7 +151,7 @@ func (orm gormDB) ActivePacksForHost(hid uint) ([]*kolide.Pack, error) {
|
|||
|
||||
// we will need to give some subset of packs to this host based on the
|
||||
// labels which this host is known to belong to
|
||||
allPacks, err := orm.Packs()
|
||||
allPacks, err := orm.Packs(kolide.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ func (orm gormDB) Query(id uint) (*kolide.Query, error) {
|
|||
return query, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) Queries() ([]*kolide.Query, error) {
|
||||
func (orm gormDB) Queries(opt kolide.ListOptions) ([]*kolide.Query, error) {
|
||||
var queries []*kolide.Query
|
||||
err := orm.DB.Find(&queries).Error
|
||||
err := orm.applyListOptions(opt).Find(&queries).Error
|
||||
return queries, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,9 +23,9 @@ func (orm gormDB) User(username string) (*kolide.User, error) {
|
|||
return user, nil
|
||||
}
|
||||
|
||||
func (orm gormDB) Users() ([]*kolide.User, error) {
|
||||
func (orm gormDB) Users(opt kolide.ListOptions) ([]*kolide.User, error) {
|
||||
var users []*kolide.User
|
||||
err := orm.DB.Find(&users).Error
|
||||
err := orm.applyListOptions(opt).Find(&users).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,3 +44,23 @@ func (orm *inmem) Migrate() error {
|
|||
func (orm *inmem) Drop() error {
|
||||
return orm.Migrate()
|
||||
}
|
||||
|
||||
// getLimitOffsetSliceBounds returns the bounds that should be used for
|
||||
// re-slicing the results to comply with the requested ListOptions. Lack of
|
||||
// generics forces us to do this rather than reslicing in this method.
|
||||
func (orm *inmem) getLimitOffsetSliceBounds(opt kolide.ListOptions, length int) (low uint, high uint) {
|
||||
if opt.PerPage == 0 {
|
||||
// PerPage value of 0 indicates unlimited
|
||||
return 0, uint(length)
|
||||
}
|
||||
|
||||
offset := opt.Page * opt.PerPage
|
||||
max := offset + opt.PerPage
|
||||
if offset > uint(length) {
|
||||
offset = uint(length)
|
||||
}
|
||||
if max > uint(length) {
|
||||
max = uint(length)
|
||||
}
|
||||
return offset, max
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package datastore
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
|
|
@ -59,14 +60,25 @@ func (orm *inmem) Host(id uint) (*kolide.Host, error) {
|
|||
return host, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) Hosts() ([]*kolide.Host, error) {
|
||||
func (orm *inmem) Hosts(opt kolide.ListOptions) ([]*kolide.Host, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
hosts := []*kolide.Host{}
|
||||
for _, host := range orm.hosts {
|
||||
hosts = append(hosts, host)
|
||||
// We need to sort by keys to provide reliable ordering
|
||||
keys := []int{}
|
||||
for k, _ := range orm.hosts {
|
||||
keys = append(keys, int(k))
|
||||
}
|
||||
sort.Ints(keys)
|
||||
|
||||
hosts := []*kolide.Host{}
|
||||
for _, k := range keys {
|
||||
hosts = append(hosts, orm.hosts[uint(k)])
|
||||
}
|
||||
|
||||
// Apply limit/offset
|
||||
low, high := orm.getLimitOffsetSliceBounds(opt, len(hosts))
|
||||
hosts = hosts[low:high]
|
||||
|
||||
return hosts, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
package datastore
|
||||
|
||||
import "github.com/kolide/kolide-ose/server/kolide"
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
// NewInvite creates and stores a new invitation in a DB.
|
||||
func (orm *inmem) NewInvite(invite *kolide.Invite) (*kolide.Invite, error) {
|
||||
|
|
@ -19,14 +23,25 @@ func (orm *inmem) NewInvite(invite *kolide.Invite) (*kolide.Invite, error) {
|
|||
}
|
||||
|
||||
// Invites lists all invites in the datastore.
|
||||
func (orm *inmem) Invites() ([]*kolide.Invite, error) {
|
||||
func (orm *inmem) Invites(opt kolide.ListOptions) ([]*kolide.Invite, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
var invites []*kolide.Invite
|
||||
for _, invite := range orm.invites {
|
||||
invites = append(invites, invite)
|
||||
// We need to sort by keys to provide reliable ordering
|
||||
keys := []int{}
|
||||
for k, _ := range orm.invites {
|
||||
keys = append(keys, int(k))
|
||||
}
|
||||
sort.Ints(keys)
|
||||
|
||||
invites := []*kolide.Invite{}
|
||||
for _, k := range keys {
|
||||
invites = append(invites, orm.invites[uint(k)])
|
||||
}
|
||||
|
||||
// Apply limit/offset
|
||||
low, high := orm.getLimitOffsetSliceBounds(opt, len(invites))
|
||||
invites = invites[low:high]
|
||||
|
||||
return invites, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package datastore
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
|
|
@ -58,14 +60,25 @@ func (orm *inmem) Pack(id uint) (*kolide.Pack, error) {
|
|||
return pack, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) Packs() ([]*kolide.Pack, error) {
|
||||
func (orm *inmem) Packs(opt kolide.ListOptions) ([]*kolide.Pack, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
packs := []*kolide.Pack{}
|
||||
for _, pack := range orm.packs {
|
||||
packs = append(packs, pack)
|
||||
// We need to sort by keys to provide reliable ordering
|
||||
keys := []int{}
|
||||
for k, _ := range orm.packs {
|
||||
keys = append(keys, int(k))
|
||||
}
|
||||
sort.Ints(keys)
|
||||
|
||||
packs := []*kolide.Pack{}
|
||||
for _, k := range keys {
|
||||
packs = append(packs, orm.packs[uint(k)])
|
||||
}
|
||||
|
||||
// Apply limit/offset
|
||||
low, high := orm.getLimitOffsetSliceBounds(opt, len(packs))
|
||||
packs = packs[low:high]
|
||||
|
||||
return packs, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package datastore
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
|
|
@ -58,14 +60,25 @@ func (orm *inmem) Query(id uint) (*kolide.Query, error) {
|
|||
return query, nil
|
||||
}
|
||||
|
||||
func (orm *inmem) Queries() ([]*kolide.Query, error) {
|
||||
func (orm *inmem) Queries(opt kolide.ListOptions) ([]*kolide.Query, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
queries := []*kolide.Query{}
|
||||
for _, query := range orm.queries {
|
||||
queries = append(queries, query)
|
||||
// We need to sort by keys to provide reliable ordering
|
||||
keys := []int{}
|
||||
for k, _ := range orm.queries {
|
||||
keys = append(keys, int(k))
|
||||
}
|
||||
sort.Ints(keys)
|
||||
|
||||
queries := []*kolide.Query{}
|
||||
for _, k := range keys {
|
||||
queries = append(queries, orm.queries[uint(k)])
|
||||
}
|
||||
|
||||
// Apply limit/offset
|
||||
low, high := orm.getLimitOffsetSliceBounds(opt, len(queries))
|
||||
queries = queries[low:high]
|
||||
|
||||
return queries, nil
|
||||
}
|
||||
|
|
|
|||
68
server/datastore/inmem_test.go
Normal file
68
server/datastore/inmem_test.go
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
package datastore
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestApplyLimitOffset(t *testing.T) {
|
||||
im := inmem{}
|
||||
data := []int{}
|
||||
|
||||
// should work with empty
|
||||
low, high := im.getLimitOffsetSliceBounds(kolide.ListOptions{}, len(data))
|
||||
result := data[low:high]
|
||||
assert.Len(t, result, 0)
|
||||
low, high = im.getLimitOffsetSliceBounds(kolide.ListOptions{Page: 1, PerPage: 20}, len(data))
|
||||
result = data[low:high]
|
||||
assert.Len(t, result, 0)
|
||||
|
||||
// insert some data
|
||||
for i := 0; i < 100; i++ {
|
||||
data = append(data, i)
|
||||
}
|
||||
|
||||
// unlimited
|
||||
low, high = im.getLimitOffsetSliceBounds(kolide.ListOptions{}, len(data))
|
||||
result = data[low:high]
|
||||
assert.Len(t, result, 100)
|
||||
assert.Equal(t, data, result)
|
||||
|
||||
// reasonable limit page 0
|
||||
low, high = im.getLimitOffsetSliceBounds(kolide.ListOptions{PerPage: 20}, len(data))
|
||||
result = data[low:high]
|
||||
assert.Len(t, result, 20)
|
||||
assert.Equal(t, data[:20], result)
|
||||
|
||||
// too many per page
|
||||
low, high = im.getLimitOffsetSliceBounds(kolide.ListOptions{PerPage: 200}, len(data))
|
||||
result = data[low:high]
|
||||
assert.Len(t, result, 100)
|
||||
assert.Equal(t, data, result)
|
||||
|
||||
// offset should be past end (zero results)
|
||||
low, high = im.getLimitOffsetSliceBounds(kolide.ListOptions{Page: 1, PerPage: 200}, len(data))
|
||||
result = data[low:high]
|
||||
assert.Len(t, result, 0)
|
||||
|
||||
// all pages appended should equal the original data
|
||||
result = []int{}
|
||||
for i := 0; i < 5; i++ { // 5 used intentionally
|
||||
low, high = im.getLimitOffsetSliceBounds(kolide.ListOptions{Page: uint(i), PerPage: 25}, len(data))
|
||||
result = append(result, data[low:high]...)
|
||||
}
|
||||
assert.Len(t, result, 100)
|
||||
assert.Equal(t, data, result)
|
||||
|
||||
// again with different params
|
||||
result = []int{}
|
||||
for i := 0; i < 100; i++ { // 5 used intentionally
|
||||
low, high = im.getLimitOffsetSliceBounds(kolide.ListOptions{Page: uint(i), PerPage: 1}, len(data))
|
||||
result = append(result, data[low:high]...)
|
||||
}
|
||||
assert.Len(t, result, 100)
|
||||
assert.Equal(t, data, result)
|
||||
|
||||
}
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
package datastore
|
||||
|
||||
import "github.com/kolide/kolide-ose/server/kolide"
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
)
|
||||
|
||||
func (orm *inmem) NewUser(user *kolide.User) (*kolide.User, error) {
|
||||
orm.mtx.Lock()
|
||||
|
|
@ -31,14 +35,25 @@ func (orm *inmem) User(username string) (*kolide.User, error) {
|
|||
return nil, ErrNotFound
|
||||
}
|
||||
|
||||
func (orm *inmem) Users() ([]*kolide.User, error) {
|
||||
func (orm *inmem) Users(opt kolide.ListOptions) ([]*kolide.User, error) {
|
||||
orm.mtx.Lock()
|
||||
defer orm.mtx.Unlock()
|
||||
|
||||
var users []*kolide.User
|
||||
for _, user := range orm.users {
|
||||
users = append(users, user)
|
||||
// We need to sort by keys to provide reliable ordering
|
||||
keys := []int{}
|
||||
for k, _ := range orm.users {
|
||||
keys = append(keys, int(k))
|
||||
}
|
||||
sort.Ints(keys)
|
||||
|
||||
users := []*kolide.User{}
|
||||
for _, k := range keys {
|
||||
users = append(users, orm.users[uint(k)])
|
||||
}
|
||||
|
||||
// Apply limit/offset
|
||||
low, high := orm.getLimitOffsetSliceBounds(opt, len(users))
|
||||
users = users[low:high]
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,3 +32,13 @@ type OrgInfoPayload struct {
|
|||
OrgName *string `json:"org_name"`
|
||||
OrgLogoURL *string `json:"org_logo_url"`
|
||||
}
|
||||
|
||||
// ListOptions defines options related to paging and ordering to be used when
|
||||
// listing objects
|
||||
type ListOptions struct {
|
||||
// Which page to return (must be positive integer)
|
||||
Page uint
|
||||
// How many results per page (must be positive integer, 0 indicates
|
||||
// unlimited)
|
||||
PerPage uint
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,14 +11,14 @@ type HostStore interface {
|
|||
SaveHost(host *Host) error
|
||||
DeleteHost(host *Host) error
|
||||
Host(id uint) (*Host, error)
|
||||
Hosts() ([]*Host, error)
|
||||
Hosts(opt ListOptions) ([]*Host, error)
|
||||
EnrollHost(uuid, hostname, ip, platform string, nodeKeySize int) (*Host, error)
|
||||
AuthenticateHost(nodeKey string) (*Host, error)
|
||||
MarkHostSeen(host *Host, t time.Time) error
|
||||
}
|
||||
|
||||
type HostService interface {
|
||||
ListHosts(ctx context.Context) ([]*Host, error)
|
||||
ListHosts(ctx context.Context, opt ListOptions) ([]*Host, error)
|
||||
GetHost(ctx context.Context, id uint) (*Host, error)
|
||||
HostStatus(ctx context.Context, host Host) string
|
||||
DeleteHost(ctx context.Context, id uint) error
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ type InviteStore interface {
|
|||
NewInvite(i *Invite) (*Invite, error)
|
||||
|
||||
// Invites lists all invites in the datastore.
|
||||
Invites() ([]*Invite, error)
|
||||
Invites(opt ListOptions) ([]*Invite, error)
|
||||
|
||||
// Invite retrieves an invite by it's ID.
|
||||
Invite(id uint) (*Invite, error)
|
||||
|
|
@ -40,7 +40,7 @@ type InviteService interface {
|
|||
DeleteInvite(ctx context.Context, id uint) (err error)
|
||||
|
||||
// Invites returns a list of all invites.
|
||||
Invites(ctx context.Context) (invites []*Invite, err error)
|
||||
ListInvites(ctx context.Context, opt ListOptions) (invites []*Invite, err error)
|
||||
|
||||
// VerifyInvite verifies that an invite exists and that it matches the
|
||||
// invite token.
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ type LabelStore interface {
|
|||
SaveLabel(Label *Label) error
|
||||
DeleteLabel(lid uint) error
|
||||
Label(lid uint) (*Label, error)
|
||||
Labels() ([]*Label, error)
|
||||
Labels(opt ListOptions) ([]*Label, error)
|
||||
|
||||
// LabelQueriesForHost returns the label queries that should be executed
|
||||
// for the given host. The cutoff is the minimum timestamp a query
|
||||
|
|
@ -32,7 +32,7 @@ type LabelStore interface {
|
|||
}
|
||||
|
||||
type LabelService interface {
|
||||
ListLabels(ctx context.Context) ([]*Label, error)
|
||||
ListLabels(ctx context.Context, opt ListOptions) ([]*Label, error)
|
||||
GetLabel(ctx context.Context, id uint) (*Label, error)
|
||||
NewLabel(ctx context.Context, p LabelPayload) (*Label, error)
|
||||
ModifyLabel(ctx context.Context, id uint, p LabelPayload) (*Label, error)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ type PackStore interface {
|
|||
SavePack(pack *Pack) error
|
||||
DeletePack(pid uint) error
|
||||
Pack(pid uint) (*Pack, error)
|
||||
Packs() ([]*Pack, error)
|
||||
Packs(opt ListOptions) ([]*Pack, error)
|
||||
|
||||
// Modifying the queries in packs
|
||||
AddQueryToPack(qid uint, pid uint) error
|
||||
|
|
@ -29,7 +29,7 @@ type PackStore interface {
|
|||
}
|
||||
|
||||
type PackService interface {
|
||||
ListPacks(ctx context.Context) ([]*Pack, error)
|
||||
ListPacks(ctx context.Context, opt ListOptions) ([]*Pack, error)
|
||||
GetPack(ctx context.Context, id uint) (*Pack, error)
|
||||
NewPack(ctx context.Context, p PackPayload) (*Pack, error)
|
||||
ModifyPack(ctx context.Context, id uint, p PackPayload) (*Pack, error)
|
||||
|
|
|
|||
|
|
@ -12,11 +12,11 @@ type QueryStore interface {
|
|||
SaveQuery(query *Query) error
|
||||
DeleteQuery(query *Query) error
|
||||
Query(id uint) (*Query, error)
|
||||
Queries() ([]*Query, error)
|
||||
Queries(opt ListOptions) ([]*Query, error)
|
||||
}
|
||||
|
||||
type QueryService interface {
|
||||
ListQueries(ctx context.Context) ([]*Query, error)
|
||||
ListQueries(ctx context.Context, opt ListOptions) ([]*Query, error)
|
||||
GetQuery(ctx context.Context, id uint) (*Query, error)
|
||||
NewQuery(ctx context.Context, p QueryPayload) (*Query, error)
|
||||
ModifyQuery(ctx context.Context, id uint, p QueryPayload) (*Query, error)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import (
|
|||
type UserStore interface {
|
||||
NewUser(user *User) (*User, error)
|
||||
User(username string) (*User, error)
|
||||
Users() ([]*User, error)
|
||||
Users(opt ListOptions) ([]*User, error)
|
||||
UserByEmail(email string) (*User, error)
|
||||
UserByID(id uint) (*User, error)
|
||||
SaveUser(user *User) error
|
||||
|
|
@ -33,7 +33,7 @@ type UserService interface {
|
|||
AuthenticatedUser(ctx context.Context) (user *User, err error)
|
||||
|
||||
// Users returns all users
|
||||
Users(ctx context.Context) (users []*User, err error)
|
||||
ListUsers(ctx context.Context, opt ListOptions) (users []*User, err error)
|
||||
|
||||
// RequestPasswordReset generates a password reset request for
|
||||
// a user. The request results in a token emailed to the user.
|
||||
|
|
|
|||
|
|
@ -41,6 +41,10 @@ func makeGetHostEndpoint(svc kolide.Service) endpoint.Endpoint {
|
|||
// List Hosts
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type listHostsRequest struct {
|
||||
ListOptions kolide.ListOptions
|
||||
}
|
||||
|
||||
type listHostsResponse struct {
|
||||
Hosts []hostResponse `json:"hosts"`
|
||||
Err error `json:"error,omitempty"`
|
||||
|
|
@ -50,7 +54,8 @@ func (r listHostsResponse) error() error { return r.Err }
|
|||
|
||||
func makeListHostsEndpoint(svc kolide.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
hosts, err := svc.ListHosts(ctx)
|
||||
req := request.(listHostsRequest)
|
||||
hosts, err := svc.ListHosts(ctx, req.ListOptions)
|
||||
if err != nil {
|
||||
return listHostsResponse{Err: err}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,10 @@ func makeCreateInviteEndpoint(svc kolide.Service) endpoint.Endpoint {
|
|||
}
|
||||
}
|
||||
|
||||
type listInvitesRequest struct {
|
||||
ListOptions kolide.ListOptions
|
||||
}
|
||||
|
||||
type listInvitesResponse struct {
|
||||
Invites []kolide.Invite `json:"invites"`
|
||||
Err error `json:"error,omitempty"`
|
||||
|
|
@ -37,7 +41,8 @@ func (r listInvitesResponse) error() error { return r.Err }
|
|||
|
||||
func makeListInvitesEndpoint(svc kolide.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
invites, err := svc.Invites(ctx)
|
||||
req := request.(listInvitesRequest)
|
||||
invites, err := svc.ListInvites(ctx, req.ListOptions)
|
||||
if err != nil {
|
||||
return listInvitesResponse{Err: err}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,10 @@ func makeGetLabelEndpoint(svc kolide.Service) endpoint.Endpoint {
|
|||
// List Labels
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type listLabelsRequest struct {
|
||||
ListOptions kolide.ListOptions
|
||||
}
|
||||
|
||||
type listLabelsResponse struct {
|
||||
Labels []kolide.Label `json:"labels"`
|
||||
Err error `json:"error,omitempty"`
|
||||
|
|
@ -45,7 +49,8 @@ func (r listLabelsResponse) error() error { return r.Err }
|
|||
|
||||
func makeListLabelsEndpoint(svc kolide.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
labels, err := svc.ListLabels(ctx)
|
||||
req := request.(listLabelsRequest)
|
||||
labels, err := svc.ListLabels(ctx, req.ListOptions)
|
||||
if err != nil {
|
||||
return listLabelsResponse{Err: err}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,10 @@ func makeGetPackEndpoint(svc kolide.Service) endpoint.Endpoint {
|
|||
// List Packs
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type listPacksRequest struct {
|
||||
ListOptions kolide.ListOptions
|
||||
}
|
||||
|
||||
type listPacksResponse struct {
|
||||
Packs []kolide.Pack `json:"packs"`
|
||||
Err error `json:"error,omitempty"`
|
||||
|
|
@ -45,7 +49,8 @@ func (r listPacksResponse) error() error { return r.Err }
|
|||
|
||||
func makeListPacksEndpoint(svc kolide.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
packs, err := svc.ListPacks(ctx)
|
||||
req := request.(listPacksRequest)
|
||||
packs, err := svc.ListPacks(ctx, req.ListOptions)
|
||||
if err != nil {
|
||||
return getPackResponse{Err: err}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ func makeGetQueryEndpoint(svc kolide.Service) endpoint.Endpoint {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// List Queries
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
type listQueriesRequest struct {
|
||||
ListOptions kolide.ListOptions
|
||||
}
|
||||
|
||||
type listQueriesResponse struct {
|
||||
Queries []kolide.Query `json:"queries"`
|
||||
|
|
@ -45,7 +48,8 @@ func (r listQueriesResponse) error() error { return r.Err }
|
|||
|
||||
func makeListQueriesEndpoint(svc kolide.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
queries, err := svc.ListQueries(ctx)
|
||||
req := request.(listQueriesRequest)
|
||||
queries, err := svc.ListQueries(ctx, req.ListOptions)
|
||||
if err != nil {
|
||||
return listQueriesResponse{Err: err}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,10 @@ func makeGetSessionUserEndpoint(svc kolide.Service) endpoint.Endpoint {
|
|||
// List Users
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type listUsersRequest struct {
|
||||
ListOptions kolide.ListOptions
|
||||
}
|
||||
|
||||
type listUsersResponse struct {
|
||||
Users []kolide.User `json:"users"`
|
||||
Err error `json:"error,omitempty"`
|
||||
|
|
@ -83,7 +87,8 @@ func (r listUsersResponse) error() error { return r.Err }
|
|||
|
||||
func makeListUsersEndpoint(svc kolide.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
users, err := svc.Users(ctx)
|
||||
req := request.(listUsersRequest)
|
||||
users, err := svc.ListUsers(ctx, req.ListOptions)
|
||||
if err != nil {
|
||||
return listUsersResponse{Err: err}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ func makeKolideKitHandlers(ctx context.Context, e KolideEndpoints, opts []kithtt
|
|||
Me: newServer(e.Me, decodeNoParamsRequest),
|
||||
CreateUser: newServer(e.CreateUser, decodeCreateUserRequest),
|
||||
GetUser: newServer(e.GetUser, decodeGetUserRequest),
|
||||
ListUsers: newServer(e.ListUsers, decodeNoParamsRequest),
|
||||
ListUsers: newServer(e.ListUsers, decodeListUsersRequest),
|
||||
ModifyUser: newServer(e.ModifyUser, decodeModifyUserRequest),
|
||||
GetSessionsForUserInfo: newServer(e.GetSessionsForUserInfo, decodeGetInfoAboutSessionsForUserRequest),
|
||||
DeleteSessionsForUser: newServer(e.DeleteSessionsForUser, decodeDeleteSessionsForUserRequest),
|
||||
|
|
@ -190,15 +190,15 @@ func makeKolideKitHandlers(ctx context.Context, e KolideEndpoints, opts []kithtt
|
|||
GetAppConfig: newServer(e.GetAppConfig, decodeNoParamsRequest),
|
||||
ModifyAppConfig: newServer(e.ModifyAppConfig, decodeModifyAppConfigRequest),
|
||||
CreateInvite: newServer(e.CreateInvite, decodeCreateInviteRequest),
|
||||
ListInvites: newServer(e.ListInvites, decodeNoParamsRequest),
|
||||
ListInvites: newServer(e.ListInvites, decodeListInvitesRequest),
|
||||
DeleteInvite: newServer(e.DeleteInvite, decodeDeleteInviteRequest),
|
||||
GetQuery: newServer(e.GetQuery, decodeGetQueryRequest),
|
||||
ListQueries: newServer(e.ListQueries, decodeNoParamsRequest),
|
||||
ListQueries: newServer(e.ListQueries, decodeListQueriesRequest),
|
||||
CreateQuery: newServer(e.CreateQuery, decodeCreateQueryRequest),
|
||||
ModifyQuery: newServer(e.ModifyQuery, decodeModifyQueryRequest),
|
||||
DeleteQuery: newServer(e.DeleteQuery, decodeDeleteQueryRequest),
|
||||
GetPack: newServer(e.GetPack, decodeGetPackRequest),
|
||||
ListPacks: newServer(e.ListPacks, decodeNoParamsRequest),
|
||||
ListPacks: newServer(e.ListPacks, decodeListPacksRequest),
|
||||
CreatePack: newServer(e.CreatePack, decodeCreatePackRequest),
|
||||
ModifyPack: newServer(e.ModifyPack, decodeModifyPackRequest),
|
||||
DeletePack: newServer(e.DeletePack, decodeDeletePackRequest),
|
||||
|
|
@ -211,7 +211,7 @@ func makeKolideKitHandlers(ctx context.Context, e KolideEndpoints, opts []kithtt
|
|||
SubmitDistributedQueryResults: newServer(e.SubmitDistributedQueryResults, decodeSubmitDistributedQueryResultsRequest),
|
||||
SubmitLogs: newServer(e.SubmitLogs, decodeSubmitLogsRequest),
|
||||
GetLabel: newServer(e.GetLabel, decodeGetLabelRequest),
|
||||
ListLabels: newServer(e.ListLabels, decodeNoParamsRequest),
|
||||
ListLabels: newServer(e.ListLabels, decodeListLabelsRequest),
|
||||
CreateLabel: newServer(e.CreateLabel, decodeCreateLabelRequest),
|
||||
ModifyLabel: newServer(e.ModifyLabel, decodeModifyLabelRequest),
|
||||
DeleteLabel: newServer(e.DeleteLabel, decodeDeleteLabelRequest),
|
||||
|
|
@ -220,7 +220,7 @@ func makeKolideKitHandlers(ctx context.Context, e KolideEndpoints, opts []kithtt
|
|||
DeleteLabelFromPack: newServer(e.DeleteLabelFromPack, decodeDeleteLabelFromPackRequest),
|
||||
GetHost: newServer(e.GetHost, decodeGetHostRequest),
|
||||
DeleteHost: newServer(e.DeleteHost, decodeDeleteHostRequest),
|
||||
ListHosts: newServer(e.ListHosts, decodeNoParamsRequest),
|
||||
ListHosts: newServer(e.ListHosts, decodeListHostsRequest),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ func (mw loggingMiddleware) Invites(ctx context.Context) ([]*kolide.Invite, erro
|
|||
"took", time.Since(begin),
|
||||
)
|
||||
}(time.Now())
|
||||
invites, err = mw.Service.Invites(ctx)
|
||||
invites, err = mw.Service.ListInvites(ctx, kolide.ListOptions{})
|
||||
return invites, err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ func (mw metricsMiddleware) DeleteInvite(ctx context.Context, id uint) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (mw metricsMiddleware) Invites(ctx context.Context) ([]*kolide.Invite, error) {
|
||||
func (mw metricsMiddleware) ListInvites(ctx context.Context, opt kolide.ListOptions) ([]*kolide.Invite, error) {
|
||||
var (
|
||||
invites []*kolide.Invite
|
||||
err error
|
||||
|
|
@ -45,7 +45,7 @@ func (mw metricsMiddleware) Invites(ctx context.Context) ([]*kolide.Invite, erro
|
|||
mw.requestCount.With(lvs...).Add(1)
|
||||
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
invites, err = mw.Service.Invites(ctx)
|
||||
invites, err = mw.Service.ListInvites(ctx, opt)
|
||||
return invites, err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ func (mw metricsMiddleware) User(ctx context.Context, id uint) (*kolide.User, er
|
|||
return user, err
|
||||
}
|
||||
|
||||
func (mw metricsMiddleware) Users(ctx context.Context) ([]*kolide.User, error) {
|
||||
func (mw metricsMiddleware) ListUsers(ctx context.Context, opt kolide.ListOptions) ([]*kolide.User, error) {
|
||||
|
||||
var (
|
||||
users []*kolide.User
|
||||
|
|
@ -67,7 +67,7 @@ func (mw metricsMiddleware) Users(ctx context.Context) ([]*kolide.User, error) {
|
|||
mw.requestLatency.With(lvs...).Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
users, err = mw.Service.Users(ctx)
|
||||
users, err = mw.Service.ListUsers(ctx, opt)
|
||||
return users, err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import (
|
|||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func (svc service) ListHosts(ctx context.Context) ([]*kolide.Host, error) {
|
||||
return svc.ds.Hosts()
|
||||
func (svc service) ListHosts(ctx context.Context, opt kolide.ListOptions) ([]*kolide.Host, error) {
|
||||
return svc.ds.Hosts(opt)
|
||||
}
|
||||
|
||||
func (svc service) GetHost(ctx context.Context, id uint) (*kolide.Host, error) {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ func TestListHosts(t *testing.T) {
|
|||
|
||||
ctx := context.Background()
|
||||
|
||||
hosts, err := svc.ListHosts(ctx)
|
||||
hosts, err := svc.ListHosts(ctx, kolide.ListOptions{})
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, hosts, 0)
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ func TestListHosts(t *testing.T) {
|
|||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
hosts, err = svc.ListHosts(ctx)
|
||||
hosts, err = svc.ListHosts(ctx, kolide.ListOptions{})
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, hosts, 1)
|
||||
}
|
||||
|
|
@ -71,7 +71,7 @@ func TestDeleteHost(t *testing.T) {
|
|||
err = svc.DeleteHost(ctx, host.ID)
|
||||
assert.Nil(t, err)
|
||||
|
||||
hosts, err := ds.Hosts()
|
||||
hosts, err := ds.Hosts(kolide.ListOptions{})
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, hosts, 0)
|
||||
|
||||
|
|
|
|||
|
|
@ -61,8 +61,8 @@ func (svc service) InviteNewUser(ctx context.Context, payload kolide.InvitePaylo
|
|||
return invite, nil
|
||||
}
|
||||
|
||||
func (svc service) Invites(ctx context.Context) ([]*kolide.Invite, error) {
|
||||
return svc.ds.Invites()
|
||||
func (svc service) ListInvites(ctx context.Context, opt kolide.ListOptions) ([]*kolide.Invite, error) {
|
||||
return svc.ds.Invites(opt)
|
||||
}
|
||||
|
||||
func (svc service) VerifyInvite(ctx context.Context, email, token string) error {
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import (
|
|||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func (svc service) ListLabels(ctx context.Context) ([]*kolide.Label, error) {
|
||||
return svc.ds.Labels()
|
||||
func (svc service) ListLabels(ctx context.Context, opt kolide.ListOptions) ([]*kolide.Label, error) {
|
||||
return svc.ds.Labels(opt)
|
||||
}
|
||||
|
||||
func (svc service) GetLabel(ctx context.Context, id uint) (*kolide.Label, error) {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ func TestListLabels(t *testing.T) {
|
|||
|
||||
ctx := context.Background()
|
||||
|
||||
labels, err := svc.ListLabels(ctx)
|
||||
labels, err := svc.ListLabels(ctx, kolide.ListOptions{})
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, labels, 0)
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ func TestListLabels(t *testing.T) {
|
|||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
labels, err = svc.ListLabels(ctx)
|
||||
labels, err = svc.ListLabels(ctx, kolide.ListOptions{})
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, labels, 1)
|
||||
assert.Equal(t, "foo", labels[0].Name)
|
||||
|
|
@ -75,7 +75,7 @@ func TestNewLabel(t *testing.T) {
|
|||
|
||||
assert.Nil(t, err)
|
||||
|
||||
labels, err := ds.Labels()
|
||||
labels, err := ds.Labels(kolide.ListOptions{})
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, labels, 1)
|
||||
assert.Equal(t, "foo", labels[0].Name)
|
||||
|
|
@ -127,7 +127,7 @@ func TestDeleteLabel(t *testing.T) {
|
|||
err = svc.DeleteLabel(ctx, label.ID)
|
||||
assert.Nil(t, err)
|
||||
|
||||
labels, err := ds.Labels()
|
||||
labels, err := ds.Labels(kolide.ListOptions{})
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, labels, 0)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ func TestEnrollAgent(t *testing.T) {
|
|||
|
||||
ctx := context.Background()
|
||||
|
||||
hosts, err := ds.Hosts()
|
||||
hosts, err := ds.Hosts(kolide.ListOptions{})
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, hosts, 0)
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ func TestEnrollAgent(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
assert.NotEmpty(t, nodeKey)
|
||||
|
||||
hosts, err = ds.Hosts()
|
||||
hosts, err = ds.Hosts(kolide.ListOptions{})
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, hosts, 1)
|
||||
}
|
||||
|
|
@ -48,7 +48,7 @@ func TestEnrollAgentIncorrectEnrollSecret(t *testing.T) {
|
|||
|
||||
ctx := context.Background()
|
||||
|
||||
hosts, err := ds.Hosts()
|
||||
hosts, err := ds.Hosts(kolide.ListOptions{})
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, hosts, 0)
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ func TestEnrollAgentIncorrectEnrollSecret(t *testing.T) {
|
|||
assert.NotNil(t, err)
|
||||
assert.Empty(t, nodeKey)
|
||||
|
||||
hosts, err = ds.Hosts()
|
||||
hosts, err = ds.Hosts(kolide.ListOptions{})
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, hosts, 0)
|
||||
}
|
||||
|
|
@ -75,7 +75,7 @@ func TestSubmitStatusLogs(t *testing.T) {
|
|||
_, err = svc.EnrollAgent(ctx, "", "host123")
|
||||
assert.Nil(t, err)
|
||||
|
||||
hosts, err := ds.Hosts()
|
||||
hosts, err := ds.Hosts(kolide.ListOptions{})
|
||||
require.Nil(t, err)
|
||||
require.Len(t, hosts, 1)
|
||||
host := hosts[0]
|
||||
|
|
@ -147,7 +147,7 @@ func TestSubmitResultLogs(t *testing.T) {
|
|||
_, err = svc.EnrollAgent(ctx, "", "host123")
|
||||
assert.Nil(t, err)
|
||||
|
||||
hosts, err := ds.Hosts()
|
||||
hosts, err := ds.Hosts(kolide.ListOptions{})
|
||||
require.Nil(t, err)
|
||||
require.Len(t, hosts, 1)
|
||||
host := hosts[0]
|
||||
|
|
@ -248,7 +248,7 @@ func TestLabelQueries(t *testing.T) {
|
|||
_, err = svc.EnrollAgent(ctx, "", "host123")
|
||||
assert.Nil(t, err)
|
||||
|
||||
hosts, err := ds.Hosts()
|
||||
hosts, err := ds.Hosts(kolide.ListOptions{})
|
||||
require.Nil(t, err)
|
||||
require.Len(t, hosts, 1)
|
||||
host := hosts[0]
|
||||
|
|
@ -410,14 +410,14 @@ func TestGetClientConfig(t *testing.T) {
|
|||
|
||||
ctx := context.Background()
|
||||
|
||||
hosts, err := ds.Hosts()
|
||||
hosts, err := ds.Hosts(kolide.ListOptions{})
|
||||
require.Nil(t, err)
|
||||
require.Len(t, hosts, 0)
|
||||
|
||||
_, err = svc.EnrollAgent(ctx, "", "user.local")
|
||||
assert.Nil(t, err)
|
||||
|
||||
hosts, err = ds.Hosts()
|
||||
hosts, err = ds.Hosts(kolide.ListOptions{})
|
||||
require.Nil(t, err)
|
||||
require.Len(t, hosts, 1)
|
||||
host := hosts[0]
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import (
|
|||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func (svc service) ListPacks(ctx context.Context) ([]*kolide.Pack, error) {
|
||||
return svc.ds.Packs()
|
||||
func (svc service) ListPacks(ctx context.Context, opt kolide.ListOptions) ([]*kolide.Pack, error) {
|
||||
return svc.ds.Packs(opt)
|
||||
}
|
||||
|
||||
func (svc service) GetPack(ctx context.Context, id uint) (*kolide.Pack, error) {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ func TestListPacks(t *testing.T) {
|
|||
|
||||
ctx := context.Background()
|
||||
|
||||
queries, err := svc.ListPacks(ctx)
|
||||
queries, err := svc.ListPacks(ctx, kolide.ListOptions{})
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, queries, 0)
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ func TestListPacks(t *testing.T) {
|
|||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
queries, err = svc.ListPacks(ctx)
|
||||
queries, err = svc.ListPacks(ctx, kolide.ListOptions{})
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, queries, 1)
|
||||
}
|
||||
|
|
@ -70,7 +70,7 @@ func TestNewPack(t *testing.T) {
|
|||
|
||||
assert.Nil(t, err)
|
||||
|
||||
queries, err := ds.Packs()
|
||||
queries, err := ds.Packs(kolide.ListOptions{})
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, queries, 1)
|
||||
}
|
||||
|
|
@ -120,7 +120,7 @@ func TestDeletePack(t *testing.T) {
|
|||
err = svc.DeletePack(ctx, pack.ID)
|
||||
assert.Nil(t, err)
|
||||
|
||||
queries, err := ds.Packs()
|
||||
queries, err := ds.Packs(kolide.ListOptions{})
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, queries, 0)
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import (
|
|||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func (svc service) ListQueries(ctx context.Context) ([]*kolide.Query, error) {
|
||||
return svc.ds.Queries()
|
||||
func (svc service) ListQueries(ctx context.Context, opt kolide.ListOptions) ([]*kolide.Query, error) {
|
||||
return svc.ds.Queries(opt)
|
||||
}
|
||||
|
||||
func (svc service) GetQuery(ctx context.Context, id uint) (*kolide.Query, error) {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ func TestListQueries(t *testing.T) {
|
|||
|
||||
ctx := context.Background()
|
||||
|
||||
queries, err := svc.ListQueries(ctx)
|
||||
queries, err := svc.ListQueries(ctx, kolide.ListOptions{})
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, queries, 0)
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ func TestListQueries(t *testing.T) {
|
|||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
queries, err = svc.ListQueries(ctx)
|
||||
queries, err = svc.ListQueries(ctx, kolide.ListOptions{})
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, queries, 1)
|
||||
}
|
||||
|
|
@ -74,7 +74,7 @@ func TestNewQuery(t *testing.T) {
|
|||
|
||||
assert.Nil(t, err)
|
||||
|
||||
queries, err := ds.Queries()
|
||||
queries, err := ds.Queries(kolide.ListOptions{})
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, queries, 1)
|
||||
}
|
||||
|
|
@ -126,7 +126,7 @@ func TestDeleteQuery(t *testing.T) {
|
|||
err = svc.DeleteQuery(ctx, query.ID)
|
||||
assert.Nil(t, err)
|
||||
|
||||
queries, err := ds.Queries()
|
||||
queries, err := ds.Queries(kolide.ListOptions{})
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, queries, 0)
|
||||
|
||||
|
|
|
|||
|
|
@ -115,8 +115,8 @@ func (svc service) AuthenticatedUser(ctx context.Context) (*kolide.User, error)
|
|||
return vc.User, nil
|
||||
}
|
||||
|
||||
func (svc service) Users(ctx context.Context) ([]*kolide.User, error) {
|
||||
return svc.ds.Users()
|
||||
func (svc service) ListUsers(ctx context.Context, opt kolide.ListOptions) ([]*kolide.User, error) {
|
||||
return svc.ds.Users(opt)
|
||||
}
|
||||
|
||||
func (svc service) ResetPassword(ctx context.Context, token, password string) error {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"strconv"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
|
|
@ -52,6 +53,50 @@ func idFromRequest(r *http.Request, name string) (uint, error) {
|
|||
return uint(uid), nil
|
||||
}
|
||||
|
||||
// default number of items to include per page
|
||||
const defaultPerPage = 20
|
||||
|
||||
// listOptionsFromRequest parses the list options from the request parameters
|
||||
func listOptionsFromRequest(r *http.Request) (kolide.ListOptions, error) {
|
||||
var err error
|
||||
|
||||
pageString := r.URL.Query().Get("page")
|
||||
perPageString := r.URL.Query().Get("per_page")
|
||||
|
||||
var page int = 0
|
||||
if pageString != "" {
|
||||
page, err = strconv.Atoi(pageString)
|
||||
if err != nil {
|
||||
return kolide.ListOptions{}, errors.New("non-int page value")
|
||||
}
|
||||
if page < 0 {
|
||||
return kolide.ListOptions{}, errors.New("negative page value")
|
||||
}
|
||||
}
|
||||
|
||||
// We default to 0 for per_page so that not specifying any paging
|
||||
// information gets all results
|
||||
var perPage int = 0
|
||||
if perPageString != "" {
|
||||
perPage, err = strconv.Atoi(perPageString)
|
||||
if err != nil {
|
||||
return kolide.ListOptions{}, errors.New("non-int per_page value")
|
||||
}
|
||||
if perPage <= 0 {
|
||||
return kolide.ListOptions{}, errors.New("invalid per_page value")
|
||||
}
|
||||
}
|
||||
|
||||
if perPage == 0 && pageString != "" {
|
||||
// We explicitly set a non-zero default if a page is specified
|
||||
// (because the client probably intended for paging, and
|
||||
// leaving the 0 would turn that off)
|
||||
perPage = defaultPerPage
|
||||
}
|
||||
|
||||
return kolide.ListOptions{Page: uint(page), PerPage: uint(perPage)}, nil
|
||||
}
|
||||
|
||||
func decodeNoParamsRequest(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,3 +21,11 @@ func decodeDeleteHostRequest(ctx context.Context, r *http.Request) (interface{},
|
|||
}
|
||||
return deleteHostRequest{ID: id}, nil
|
||||
}
|
||||
|
||||
func decodeListHostsRequest(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
opt, err := listOptionsFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return listHostsRequest{ListOptions: opt}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,3 +32,11 @@ func decodeDeleteInviteRequest(ctx context.Context, r *http.Request) (interface{
|
|||
req.ID = id
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeListInvitesRequest(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
opt, err := listOptionsFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return listInvitesRequest{ListOptions: opt}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,3 +47,11 @@ func decodeGetLabelRequest(ctx context.Context, r *http.Request) (interface{}, e
|
|||
req.ID = id
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeListLabelsRequest(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
opt, err := listOptionsFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return listLabelsRequest{ListOptions: opt}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,14 @@ func decodeGetPackRequest(ctx context.Context, r *http.Request) (interface{}, er
|
|||
return req, nil
|
||||
}
|
||||
|
||||
func decodeListPacksRequest(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
opt, err := listOptionsFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return listPacksRequest{ListOptions: opt}, nil
|
||||
}
|
||||
|
||||
func decodeAddQueryToPackRequest(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
qid, err := idFromRequest(r, "qid")
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -47,3 +47,11 @@ func decodeGetQueryRequest(ctx context.Context, r *http.Request) (interface{}, e
|
|||
req.ID = id
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeListQueriesRequest(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
opt, err := listOptionsFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return listQueriesRequest{ListOptions: opt}, nil
|
||||
}
|
||||
|
|
|
|||
78
server/service/transport_test.go
Normal file
78
server/service/transport_test.go
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/kolide/kolide-ose/server/kolide"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestListOptionsFromRequest(t *testing.T) {
|
||||
var listOptionsTests = []struct {
|
||||
// url string to parse
|
||||
url string
|
||||
// expected list options
|
||||
listOptions kolide.ListOptions
|
||||
// should cause an error
|
||||
shouldErr bool
|
||||
}{
|
||||
// both params provided
|
||||
{
|
||||
url: "/foo?page=1&per_page=10",
|
||||
listOptions: kolide.ListOptions{Page: 1, PerPage: 10},
|
||||
},
|
||||
// only per_page (page should default to 0)
|
||||
{
|
||||
url: "/foo?per_page=10",
|
||||
listOptions: kolide.ListOptions{Page: 0, PerPage: 10},
|
||||
},
|
||||
// only page (per_page should default to defaultPerPage
|
||||
{
|
||||
url: "/foo?page=10",
|
||||
listOptions: kolide.ListOptions{Page: 10, PerPage: defaultPerPage},
|
||||
},
|
||||
// no params provided (defaults to empty ListOptions indicating
|
||||
// unlimited)
|
||||
{
|
||||
url: "/foo?unrelated=foo",
|
||||
listOptions: kolide.ListOptions{},
|
||||
},
|
||||
|
||||
// various error cases
|
||||
{
|
||||
url: "/foo?page=foo&per_page=10",
|
||||
shouldErr: true,
|
||||
},
|
||||
{
|
||||
url: "/foo?page=1&per_page=foo",
|
||||
shouldErr: true,
|
||||
},
|
||||
{
|
||||
url: "/foo?page=-1",
|
||||
shouldErr: true,
|
||||
},
|
||||
{
|
||||
url: "/foo?page=-1&per_page=-10",
|
||||
shouldErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range listOptionsTests {
|
||||
t.Run(tt.url, func(t *testing.T) {
|
||||
url, _ := url.Parse(tt.url)
|
||||
req := &http.Request{URL: url}
|
||||
opt, err := listOptionsFromRequest(req)
|
||||
|
||||
if tt.shouldErr {
|
||||
assert.NotNil(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, tt.listOptions, opt)
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -24,6 +24,14 @@ func decodeGetUserRequest(ctx context.Context, r *http.Request) (interface{}, er
|
|||
return getUserRequest{ID: id}, nil
|
||||
}
|
||||
|
||||
func decodeListUsersRequest(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
opt, err := listOptionsFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return listUsersRequest{ListOptions: opt}, nil
|
||||
}
|
||||
|
||||
func decodeChangePasswordRequest(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
var req resetPasswordRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
|
|
|
|||
Loading…
Reference in a new issue