mirror of
https://github.com/fleetdm/fleet
synced 2026-05-22 00:18:27 +00:00
Refactor ListActivities to new endpoint pattern (#3115)
This commit is contained in:
parent
c6fc91f2e4
commit
5c113bd468
7 changed files with 112 additions and 69 deletions
40
server/service/activities.go
Normal file
40
server/service/activities.go
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Get activities
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type listActivitiesRequest struct {
|
||||
ListOptions fleet.ListOptions `url:"list_options"`
|
||||
}
|
||||
|
||||
type listActivitiesResponse struct {
|
||||
Activities []*fleet.Activity `json:"activities"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r listActivitiesResponse) error() error { return r.Err }
|
||||
|
||||
func listActivitiesEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (interface{}, error) {
|
||||
req := request.(*listActivitiesRequest)
|
||||
activities, err := svc.ListActivities(ctx, req.ListOptions)
|
||||
if err != nil {
|
||||
return listActivitiesResponse{Err: err}, nil
|
||||
}
|
||||
|
||||
return listActivitiesResponse{Activities: activities}, nil
|
||||
}
|
||||
|
||||
// ListActivities returns a slice of activities for the whole organization
|
||||
func (svc *Service) ListActivities(ctx context.Context, opt fleet.ListOptions) ([]*fleet.Activity, error) {
|
||||
if err := svc.authz.Authorize(ctx, &fleet.Activity{}, fleet.ActionRead); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return svc.ds.ListActivities(ctx, opt)
|
||||
}
|
||||
39
server/service/activities_test.go
Normal file
39
server/service/activities_test.go
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server/authz"
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/fleetdm/fleet/v4/server/mock"
|
||||
"github.com/fleetdm/fleet/v4/server/test"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestListActivities(t *testing.T) {
|
||||
ds := new(mock.Store)
|
||||
svc := newTestService(ds, nil, nil)
|
||||
|
||||
ds.ListActivitiesFunc = func(ctx context.Context, opts fleet.ListOptions) ([]*fleet.Activity, error) {
|
||||
return []*fleet.Activity{
|
||||
{ID: 1},
|
||||
{ID: 2},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// admin user
|
||||
activities, err := svc.ListActivities(test.UserContext(test.UserAdmin), fleet.ListOptions{})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, activities, 2)
|
||||
|
||||
// anyone can read activities
|
||||
activities, err = svc.ListActivities(test.UserContext(test.UserNoRoles), fleet.ListOptions{})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, activities, 2)
|
||||
|
||||
// no user in context
|
||||
_, err = svc.ListActivities(context.Background(), fleet.ListOptions{})
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), authz.ForbiddenErrorMessage)
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Get activities
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type listActivitiesRequest struct {
|
||||
ListOptions fleet.ListOptions
|
||||
}
|
||||
|
||||
type listActivitiesResponse struct {
|
||||
Activities []*fleet.Activity `json:"activities"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r listActivitiesResponse) error() error { return r.Err }
|
||||
|
||||
func makeListActivitiesEndpoint(svc fleet.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(listActivitiesRequest)
|
||||
activities, err := svc.ListActivities(ctx, req.ListOptions)
|
||||
if err != nil {
|
||||
return listActivitiesResponse{Err: err}, nil
|
||||
}
|
||||
|
||||
return listActivitiesResponse{Activities: activities}, err
|
||||
}
|
||||
}
|
||||
|
|
@ -120,7 +120,6 @@ type FleetEndpoints struct {
|
|||
AddTeamUsers endpoint.Endpoint
|
||||
DeleteTeamUsers endpoint.Endpoint
|
||||
TeamEnrollSecrets endpoint.Endpoint
|
||||
ListActivities endpoint.Endpoint
|
||||
}
|
||||
|
||||
// MakeFleetServerEndpoints creates the Fleet API endpoints.
|
||||
|
|
@ -228,7 +227,6 @@ func MakeFleetServerEndpoints(svc fleet.Service, urlPrefix string, limitStore th
|
|||
AddTeamUsers: authenticatedUser(svc, makeAddTeamUsersEndpoint(svc)),
|
||||
DeleteTeamUsers: authenticatedUser(svc, makeDeleteTeamUsersEndpoint(svc)),
|
||||
TeamEnrollSecrets: authenticatedUser(svc, makeTeamEnrollSecretsEndpoint(svc)),
|
||||
ListActivities: authenticatedUser(svc, makeListActivitiesEndpoint(svc)),
|
||||
|
||||
// Authenticated status endpoints
|
||||
StatusResultStore: authenticatedUser(svc, makeStatusResultStoreEndpoint(svc)),
|
||||
|
|
@ -348,7 +346,6 @@ type fleetHandlers struct {
|
|||
AddTeamUsers http.Handler
|
||||
DeleteTeamUsers http.Handler
|
||||
TeamEnrollSecrets http.Handler
|
||||
ListActivities http.Handler
|
||||
}
|
||||
|
||||
func makeKitHandlers(e FleetEndpoints, opts []kithttp.ServerOption) *fleetHandlers {
|
||||
|
|
@ -455,7 +452,6 @@ func makeKitHandlers(e FleetEndpoints, opts []kithttp.ServerOption) *fleetHandle
|
|||
AddTeamUsers: newServer(e.AddTeamUsers, decodeModifyTeamUsersRequest),
|
||||
DeleteTeamUsers: newServer(e.DeleteTeamUsers, decodeModifyTeamUsersRequest),
|
||||
TeamEnrollSecrets: newServer(e.TeamEnrollSecrets, decodeTeamEnrollSecretsRequest),
|
||||
ListActivities: newServer(e.ListActivities, decodeListActivitiesRequest),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -666,8 +662,6 @@ func attachFleetAPIRoutes(r *mux.Router, h *fleetHandlers) {
|
|||
r.Handle("/api/v1/osquery/log", h.SubmitLogs).Methods("POST").Name("submit_logs")
|
||||
r.Handle("/api/v1/osquery/carve/begin", h.CarveBegin).Methods("POST").Name("carve_begin")
|
||||
r.Handle("/api/v1/osquery/carve/block", h.CarveBlock).Methods("POST").Name("carve_block")
|
||||
|
||||
r.Handle("/api/v1/fleet/activities", h.ListActivities).Methods("GET").Name("list_activities")
|
||||
}
|
||||
|
||||
func attachNewStyleFleetAPIRoutes(r *mux.Router, svc fleet.Service, opts []kithttp.ServerOption) {
|
||||
|
|
@ -723,6 +717,8 @@ func attachNewStyleFleetAPIRoutes(r *mux.Router, svc fleet.Service, opts []kitht
|
|||
e.GET("/api/v1/fleet/queries/run", runLiveQueryEndpoint, runLiveQueryRequest{})
|
||||
|
||||
e.PATCH("/api/v1/fleet/invites/{id:[0-9]+}", updateInviteEndpoint, updateInviteRequest{})
|
||||
|
||||
e.GET("/api/v1/fleet/activities", listActivitiesEndpoint, listActivitiesRequest{})
|
||||
}
|
||||
|
||||
// TODO: this duplicates the one in makeKitHandler
|
||||
|
|
|
|||
|
|
@ -1146,3 +1146,34 @@ func (s *integrationTestSuite) TestHostDetailsPolicies() {
|
|||
// Try to create a team policy with an existing name.
|
||||
s.DoJSON("POST", fmt.Sprintf("/api/v1/fleet/teams/%d/policies", team1.ID), tpParams, http.StatusConflict, &tpResp)
|
||||
}
|
||||
|
||||
func (s *integrationTestSuite) TestListActivities() {
|
||||
t := s.T()
|
||||
|
||||
ctx := context.Background()
|
||||
u := s.users["admin1@example.com"]
|
||||
details := make(map[string]interface{})
|
||||
|
||||
err := s.ds.NewActivity(ctx, &u, fleet.ActivityTypeAppliedSpecPack, &details)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = s.ds.NewActivity(ctx, &u, fleet.ActivityTypeDeletedPack, &details)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = s.ds.NewActivity(ctx, &u, fleet.ActivityTypeEditedPack, &details)
|
||||
require.NoError(t, err)
|
||||
|
||||
var listResp listActivitiesResponse
|
||||
s.DoJSON("GET", "/api/v1/fleet/activities", nil, http.StatusOK, &listResp, "per_page", "2", "order_key", "id")
|
||||
require.Len(t, listResp.Activities, 2)
|
||||
assert.Equal(t, fleet.ActivityTypeAppliedSpecPack, listResp.Activities[0].Type)
|
||||
assert.Equal(t, fleet.ActivityTypeDeletedPack, listResp.Activities[1].Type)
|
||||
|
||||
s.DoJSON("GET", "/api/v1/fleet/activities", nil, http.StatusOK, &listResp, "per_page", "2", "order_key", "id", "page", "1")
|
||||
require.Len(t, listResp.Activities, 1)
|
||||
assert.Equal(t, fleet.ActivityTypeEditedPack, listResp.Activities[0].Type)
|
||||
|
||||
s.DoJSON("GET", "/api/v1/fleet/activities", nil, http.StatusOK, &listResp, "per_page", "1", "order_key", "id", "order_direction", "desc")
|
||||
require.Len(t, listResp.Activities, 1)
|
||||
assert.Equal(t, fleet.ActivityTypeEditedPack, listResp.Activities[0].Type)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
)
|
||||
|
||||
// ListActivities returns a slice of activities for the whole organization
|
||||
func (svc *Service) ListActivities(ctx context.Context, opt fleet.ListOptions) ([]*fleet.Activity, error) {
|
||||
if err := svc.authz.Authorize(ctx, &fleet.Activity{}, fleet.ActionRead); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return svc.ds.ListActivities(ctx, opt)
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func decodeListActivitiesRequest(ctx context.Context, r *http.Request) (interface{}, error) {
|
||||
opt, err := listOptionsFromRequest(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return listActivitiesRequest{ListOptions: opt}, nil
|
||||
}
|
||||
Loading…
Reference in a new issue