diff --git a/orgs.go b/orgs.go index 6649795..9871529 100644 --- a/orgs.go +++ b/orgs.go @@ -4,6 +4,7 @@ import ( "context" "iter" "net/http" + "time" "dappco.re/go/core/forge/types" ) @@ -18,6 +19,20 @@ type OrgService struct { Resource[types.Organization, types.CreateOrgOption, types.EditOrgOption] } +// OrgActivityFeedListOptions controls filtering for organisation activity feeds. +type OrgActivityFeedListOptions struct { + Date *time.Time +} + +func (o OrgActivityFeedListOptions) queryParams() map[string]string { + if o.Date == nil { + return nil + } + return map[string]string{ + "date": o.Date.Format("2006-01-02"), + } +} + func newOrgService(c *Client) *OrgService { return &OrgService{ Resource: *NewResource[types.Organization, types.CreateOrgOption, types.EditOrgOption]( @@ -87,6 +102,18 @@ func (s *OrgService) Unblock(ctx context.Context, org, username string) error { return s.client.Delete(ctx, path) } +// ListActivityFeeds returns the organisation's activity feed entries. +func (s *OrgService) ListActivityFeeds(ctx context.Context, org string, filters ...OrgActivityFeedListOptions) ([]types.Activity, error) { + path := ResolvePath("/api/v1/orgs/{org}/activities/feeds", pathParams("org", org)) + return ListAll[types.Activity](ctx, s.client, path, orgActivityFeedQuery(filters...)) +} + +// IterActivityFeeds returns an iterator over the organisation's activity feed entries. +func (s *OrgService) IterActivityFeeds(ctx context.Context, org string, filters ...OrgActivityFeedListOptions) iter.Seq2[types.Activity, error] { + path := ResolvePath("/api/v1/orgs/{org}/activities/feeds", pathParams("org", org)) + return ListIter[types.Activity](ctx, s.client, path, orgActivityFeedQuery(filters...)) +} + // ListUserOrgs returns all organisations for a user. func (s *OrgService) ListUserOrgs(ctx context.Context, username string) ([]types.Organization, error) { path := ResolvePath("/api/v1/users/{username}/orgs", pathParams("username", username)) @@ -108,3 +135,20 @@ func (s *OrgService) ListMyOrgs(ctx context.Context) ([]types.Organization, erro func (s *OrgService) IterMyOrgs(ctx context.Context) iter.Seq2[types.Organization, error] { return ListIter[types.Organization](ctx, s.client, "/api/v1/user/orgs", nil) } + +func orgActivityFeedQuery(filters ...OrgActivityFeedListOptions) map[string]string { + if len(filters) == 0 { + return nil + } + + query := make(map[string]string, 1) + for _, filter := range filters { + if filter.Date != nil { + query["date"] = filter.Date.Format("2006-01-02") + } + } + if len(query) == 0 { + return nil + } + return query +} diff --git a/orgs_test.go b/orgs_test.go index eac1653..af100ca 100644 --- a/orgs_test.go +++ b/orgs_test.go @@ -6,6 +6,7 @@ import ( "net/http" "net/http/httptest" "testing" + "time" "dappco.re/go/core/forge/types" ) @@ -152,6 +153,72 @@ func TestOrgService_Unblock_Good(t *testing.T) { } } +func TestOrgService_ListActivityFeeds_Good(t *testing.T) { + date := time.Date(2026, time.April, 2, 15, 4, 5, 0, time.UTC) + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + t.Errorf("expected GET, got %s", r.Method) + } + if r.URL.Path != "/api/v1/orgs/core/activities/feeds" { + t.Errorf("wrong path: %s", r.URL.Path) + } + if got := r.URL.Query().Get("date"); got != "2026-04-02" { + t.Errorf("wrong date: %s", got) + } + w.Header().Set("X-Total-Count", "1") + json.NewEncoder(w).Encode([]types.Activity{{ + ID: 9, + OpType: "create_org", + Content: "created organisation", + }}) + })) + defer srv.Close() + + f := NewForge(srv.URL, "tok") + activities, err := f.Orgs.ListActivityFeeds(context.Background(), "core", OrgActivityFeedListOptions{Date: &date}) + if err != nil { + t.Fatal(err) + } + if len(activities) != 1 || activities[0].ID != 9 || activities[0].OpType != "create_org" { + t.Fatalf("got %#v", activities) + } +} + +func TestOrgService_IterActivityFeeds_Good(t *testing.T) { + var requests int + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + requests++ + if r.Method != http.MethodGet { + t.Errorf("expected GET, got %s", r.Method) + } + if r.URL.Path != "/api/v1/orgs/core/activities/feeds" { + t.Errorf("wrong path: %s", r.URL.Path) + } + w.Header().Set("X-Total-Count", "1") + json.NewEncoder(w).Encode([]types.Activity{{ + ID: 11, + OpType: "update_org", + Content: "updated organisation", + }}) + })) + defer srv.Close() + + f := NewForge(srv.URL, "tok") + var got []int64 + for activity, err := range f.Orgs.IterActivityFeeds(context.Background(), "core") { + if err != nil { + t.Fatal(err) + } + got = append(got, activity.ID) + } + if requests != 1 { + t.Fatalf("expected 1 request, got %d", requests) + } + if len(got) != 1 || got[0] != 11 { + t.Fatalf("got %#v", got) + } +} + func TestOrgService_IsBlocked_Good(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet {