fleet/server/activity/api/list_activities.go
Victor Lyuboslavsky 61f635dd44
Activity bounded context: Complete read operations (#38555)
<!-- 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 -->
2026-02-09 15:29:12 -06:00

70 lines
2.7 KiB
Go

package api
import (
"context"
"encoding/json"
"time"
)
// OrderDirection represents the sort direction for list queries.
type OrderDirection string
const (
OrderAscending OrderDirection = "asc"
OrderDescending OrderDirection = "desc"
)
type ListActivitiesService interface {
ListActivities(ctx context.Context, opt ListOptions) ([]*Activity, *PaginationMetadata, error)
}
// Activity represents a recorded activity in the audit log.
type Activity struct {
ID uint `json:"id,omitempty" db:"id"`
UUID string `json:"uuid,omitempty" db:"uuid"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
Type string `json:"type" db:"activity_type"`
ActorID *uint `json:"actor_id,omitempty" db:"user_id"`
ActorFullName *string `json:"actor_full_name,omitempty" db:"name"`
ActorEmail *string `json:"actor_email,omitempty" db:"user_email"`
ActorGravatar *string `json:"actor_gravatar,omitempty" db:"gravatar_url"`
ActorAPIOnly *bool `json:"actor_api_only,omitempty" db:"api_only"`
Streamed *bool `json:"-" db:"streamed"`
FleetInitiated bool `json:"fleet_initiated" db:"fleet_initiated"`
Details *json.RawMessage `json:"details" db:"details"`
}
// AuthzType implements the authorization type for activities.
func (a *Activity) AuthzType() string {
return "activity"
}
// ListOptions defines options for listing activities.
// Note: Query parameter decoding is handled by listOptionsFromRequest in the service layer,
// not via struct tags. This keeps the API package free of HTTP-specific concerns.
type ListOptions struct {
// Pagination
Page uint
PerPage uint
After string // Cursor-based pagination: start after this value (used with OrderKey)
// Sorting
OrderKey string // Field to order by (e.g., "created_at", "id")
OrderDirection OrderDirection // OrderAscending or OrderDescending
// Filters
ActivityType string // Filter by activity type
StartCreatedAt string // ISO date string, filter activities created after this time
EndCreatedAt string // ISO date string, filter activities created before this time
MatchQuery string // Search query for actor name and email
Streamed *bool // Filter by streamed status (nil = all, true = streamed only, false = not streamed only)
}
// PaginationMetadata contains pagination information for list responses.
type PaginationMetadata struct {
HasNextResults bool `json:"has_next_results"`
HasPreviousResults bool `json:"has_previous_results"`
// TotalResults is excluded from JSON responses to match legacy behavior.
// It can be used by server-side code but won't be sent to API clients.
TotalResults uint `json:"-"`
}