mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 09:28:54 +00:00
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #38534 moved `/api/_version_/fleet/hosts/{id:[0-9]+}/activities` endpoint and `MarkActivitiesAsStreamed` to activity bounded context # Checklist for submitter - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. ## Testing - [x] Added/updated automated tests - [x] Where appropriate, [automated tests simulate multiple hosts and test for host isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing) (updates to one hosts's records do not affect another) - [x] QA'd all new/changed functionality manually <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added new endpoint to retrieve host-specific past activities with pagination metadata. * **Refactor** * Refactored activity service architecture and authorization layer to improve data provider integration and activity streaming capabilities. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
96 lines
2.5 KiB
Go
96 lines
2.5 KiB
Go
// Package activityacl provides the anti-corruption layer between the activity
|
|
// bounded context and legacy Fleet code.
|
|
//
|
|
// This package is the ONLY place that imports both activity types and fleet types.
|
|
// It translates between them, allowing the activity context to remain decoupled
|
|
// from legacy code.
|
|
package activityacl
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/fleetdm/fleet/v4/server/activity"
|
|
"github.com/fleetdm/fleet/v4/server/fleet"
|
|
)
|
|
|
|
// FleetServiceAdapter provides access to Fleet service methods
|
|
// for data that the activity bounded context doesn't own.
|
|
type FleetServiceAdapter struct {
|
|
svc fleet.LookupService
|
|
}
|
|
|
|
// NewFleetServiceAdapter creates a new adapter for the Fleet service.
|
|
func NewFleetServiceAdapter(svc fleet.LookupService) *FleetServiceAdapter {
|
|
return &FleetServiceAdapter{svc: svc}
|
|
}
|
|
|
|
// Ensure FleetServiceAdapter implements activity.UserProvider and activity.HostProvider
|
|
var (
|
|
_ activity.UserProvider = (*FleetServiceAdapter)(nil)
|
|
_ activity.HostProvider = (*FleetServiceAdapter)(nil)
|
|
)
|
|
|
|
// UsersByIDs fetches users by their IDs from the Fleet service.
|
|
func (a *FleetServiceAdapter) UsersByIDs(ctx context.Context, ids []uint) ([]*activity.User, error) {
|
|
if len(ids) == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
// Fetch only the requested users by their IDs
|
|
users, err := a.svc.UsersByIDs(ctx, ids)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Convert to activity.User
|
|
result := make([]*activity.User, 0, len(users))
|
|
for _, u := range users {
|
|
result = append(result, convertUser(u))
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// FindUserIDs searches for users by name/email prefix and returns their IDs.
|
|
func (a *FleetServiceAdapter) FindUserIDs(ctx context.Context, query string) ([]uint, error) {
|
|
if query == "" {
|
|
return nil, nil
|
|
}
|
|
|
|
// Search users via Fleet service with the query
|
|
users, err := a.svc.ListUsers(ctx, fleet.UserListOptions{
|
|
ListOptions: fleet.ListOptions{
|
|
MatchQuery: query,
|
|
},
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ids := make([]uint, 0, len(users))
|
|
for _, u := range users {
|
|
ids = append(ids, u.ID)
|
|
}
|
|
return ids, nil
|
|
}
|
|
|
|
// GetHostLite fetches minimal host information for authorization.
|
|
func (a *FleetServiceAdapter) GetHostLite(ctx context.Context, hostID uint) (*activity.Host, error) {
|
|
host, err := a.svc.GetHostLite(ctx, hostID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &activity.Host{
|
|
ID: host.ID,
|
|
TeamID: host.TeamID,
|
|
}, nil
|
|
}
|
|
|
|
func convertUser(u *fleet.UserSummary) *activity.User {
|
|
return &activity.User{
|
|
ID: u.ID,
|
|
Name: u.Name,
|
|
Email: u.Email,
|
|
Gravatar: u.GravatarURL,
|
|
APIOnly: u.APIOnly,
|
|
}
|
|
}
|