Refactor ListActivities to new endpoint pattern (#3115)

This commit is contained in:
Martin Angers 2021-11-29 08:12:22 -05:00 committed by GitHub
parent c6fc91f2e4
commit 5c113bd468
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 112 additions and 69 deletions

View 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)
}

View 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)
}

View file

@ -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
}
}

View file

@ -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

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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
}