diff --git a/server/datastore/datastore.go b/server/datastore/datastore.go index 2e04bd8175..85ad715afd 100644 --- a/server/datastore/datastore.go +++ b/server/datastore/datastore.go @@ -97,7 +97,7 @@ var TestFunctions = [...]func(*testing.T, kolide.Datastore){ testCarveListCarves, testCarveCleanupCarves, testCarveUpdateCarve, - testTeamGetSet, + testTeamGetSetDelete, testUserTeams, testUserCreateWithTeams, } diff --git a/server/datastore/datastore_teams.go b/server/datastore/datastore_teams.go index 46c582920e..fdbfea3105 100644 --- a/server/datastore/datastore_teams.go +++ b/server/datastore/datastore_teams.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" ) -func testTeamGetSet(t *testing.T, ds kolide.Datastore) { +func testTeamGetSetDelete(t *testing.T, ds kolide.Datastore) { var createTests = []struct { name, description string }{ @@ -34,6 +34,12 @@ func testTeamGetSet(t *testing.T, ds kolide.Datastore) { require.NoError(t, err) assert.Equal(t, tt.name, team.Name) assert.Equal(t, tt.description, team.Description) + + err = ds.DeleteTeam(team.ID) + require.NoError(t, err) + + team, err = ds.TeamByName(tt.name) + require.Error(t, err) }) } } diff --git a/server/datastore/mysql/teams.go b/server/datastore/mysql/teams.go index 1f29a48bf5..72bdba605e 100644 --- a/server/datastore/mysql/teams.go +++ b/server/datastore/mysql/teams.go @@ -42,6 +42,13 @@ func (d *Datastore) Team(tid uint) (*kolide.Team, error) { return team, nil } +func (d *Datastore) DeleteTeam(tid uint) error { + if err := d.deleteEntity("teams", tid); err != nil { + return errors.Wrapf(err, "delete team id %d", tid) + } + return nil +} + func (d *Datastore) TeamByName(name string) (*kolide.Team, error) { sql := ` SELECT * FROM teams diff --git a/server/kolide/teams.go b/server/kolide/teams.go index 680a754024..b1bc6e8565 100644 --- a/server/kolide/teams.go +++ b/server/kolide/teams.go @@ -10,6 +10,8 @@ type TeamStore interface { NewTeam(team *Team) (*Team, error) // Team retrieves the Team by ID. Team(tid uint) (*Team, error) + // Team deletes the Team by ID. + DeleteTeam(tid uint) error // TeamByName retrieves the Team by Name. TeamByName(name string) (*Team, error) // SaveTeam saves any changes to the team. @@ -24,6 +26,8 @@ type TeamService interface { NewTeam(ctx context.Context, p TeamPayload) (*Team, error) // ModifyTeam modifies an existing team. ModifyTeam(ctx context.Context, id uint, payload TeamPayload) (*Team, error) + // DeleteTeam deletes an existing team. + DeleteTeam(ctx context.Context, id uint) error // ListTeams lists teams with the ordering and filters in the provided // options. ListTeams(ctx context.Context, opt ListOptions) ([]*Team, error) diff --git a/server/service/endpoint_teams.go b/server/service/endpoint_teams.go index eb7d503a29..5cc7b316c3 100644 --- a/server/service/endpoint_teams.go +++ b/server/service/endpoint_teams.go @@ -93,3 +93,28 @@ func makeListTeamsEndpoint(svc kolide.Service) endpoint.Endpoint { return resp, nil } } + +//////////////////////////////////////////////////////////////////////////////// +// Delete Team +//////////////////////////////////////////////////////////////////////////////// + +type deleteTeamRequest struct { + ID uint `json:"id"` +} + +type deleteTeamResponse struct { + Err error `json:"error,omitempty"` +} + +func (r deleteTeamResponse) error() error { return r.Err } + +func makeDeleteTeamEndpoint(svc kolide.Service) endpoint.Endpoint { + return func(ctx context.Context, request interface{}) (interface{}, error) { + req := request.(deleteTeamRequest) + err := svc.DeleteTeam(ctx, req.ID) + if err != nil { + return deleteTeamResponse{Err: err}, nil + } + return deleteTeamResponse{}, nil + } +} diff --git a/server/service/handler.go b/server/service/handler.go index 8c140fb971..abaeb22fdd 100644 --- a/server/service/handler.go +++ b/server/service/handler.go @@ -112,6 +112,7 @@ type KolideEndpoints struct { Version endpoint.Endpoint CreateTeam endpoint.Endpoint ModifyTeam endpoint.Endpoint + DeleteTeam endpoint.Endpoint ListTeams endpoint.Endpoint } @@ -218,6 +219,7 @@ func MakeKolideServerEndpoints(svc kolide.Service, jwtKey, urlPrefix string, lim // TODO permissions for teams endpoints CreateTeam: authenticatedUser(jwtKey, svc, makeCreateTeamEndpoint(svc)), ModifyTeam: authenticatedUser(jwtKey, svc, makeModifyTeamEndpoint(svc)), + DeleteTeam: authenticatedUser(jwtKey, svc, makeDeleteTeamEndpoint(svc)), ListTeams: authenticatedUser(jwtKey, svc, makeListTeamsEndpoint(svc)), // Authenticated status endpoints @@ -330,6 +332,7 @@ type kolideHandlers struct { Version http.Handler CreateTeam http.Handler ModifyTeam http.Handler + DeleteTeam http.Handler ListTeams http.Handler } @@ -429,6 +432,7 @@ func makeKolideKitHandlers(e KolideEndpoints, opts []kithttp.ServerOption) *koli Version: newServer(e.Version, decodeNoParamsRequest), CreateTeam: newServer(e.CreateTeam, decodeCreateTeamRequest), ModifyTeam: newServer(e.ModifyTeam, decodeModifyTeamRequest), + DeleteTeam: newServer(e.DeleteTeam, decodeDeleteTeamRequest), ListTeams: newServer(e.ListTeams, decodeListTeamsRequest), } } @@ -645,6 +649,7 @@ func attachKolideAPIRoutes(r *mux.Router, h *kolideHandlers) { r.Handle("/api/v1/fleet/teams", h.CreateTeam).Methods("POST").Name("create_team") r.Handle("/api/v1/fleet/teams", h.ListTeams).Methods("GET").Name("list_teams") r.Handle("/api/v1/fleet/teams/{id}", h.ModifyTeam).Methods("PATCH").Name("modify_team") + r.Handle("/api/v1/fleet/teams/{id}", h.DeleteTeam).Methods("DELETE").Name("delete_team") r.Handle("/api/v1/osquery/enroll", h.EnrollAgent).Methods("POST").Name("enroll_agent") r.Handle("/api/v1/osquery/config", h.GetClientConfig).Methods("POST").Name("get_client_config") diff --git a/server/service/service_teams.go b/server/service/service_teams.go index 7bf91986ec..a380c83e20 100644 --- a/server/service/service_teams.go +++ b/server/service/service_teams.go @@ -49,3 +49,7 @@ func (svc service) ModifyTeam(ctx context.Context, id uint, payload kolide.TeamP func (svc service) ListTeams(ctx context.Context, opt kolide.ListOptions) ([]*kolide.Team, error) { return svc.ds.ListTeams(opt) } + +func (svc service) DeleteTeam(ctx context.Context, tid uint) error { + return svc.ds.DeleteTeam(tid) +} diff --git a/server/service/transport_teams.go b/server/service/transport_teams.go index 4036dd4dd1..020fc4a4c1 100644 --- a/server/service/transport_teams.go +++ b/server/service/transport_teams.go @@ -35,3 +35,11 @@ func decodeListTeamsRequest(ctx context.Context, r *http.Request) (interface{}, } return listTeamsRequest{ListOptions: opt}, nil } + +func decodeDeleteTeamRequest(ctx context.Context, r *http.Request) (interface{}, error) { + id, err := idFromRequest(r, "id") + if err != nil { + return nil, err + } + return deleteTeamRequest{ID: id}, nil +}