Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,73 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
> if user.Has2FA != nil && *user.Has2FA { ... }
> ```

- **`ListReactions` now uses cursor-based pagination** — `ListReactionsParameters` replaces
`Count`/`Page` with `Cursor`/`Limit`, and `ListReactions`/`ListReactionsContext` now return
`([]ReactedItem, string, error)` where the string is the next cursor, instead of
`([]ReactedItem, *Paging, error)`. ([#825])

> [!WARNING]
> **Breaking change.** Both the parameters and return signature have changed:
>
> ```go
> // Before
> params := slack.NewListReactionsParameters()
> params.Count = 100
> params.Page = 2
> items, paging, err := api.ListReactions(params)
>
> // After
> params := slack.NewListReactionsParameters()
> params.Limit = 100
> items, nextCursor, err := api.ListReactions(params)
> // Use nextCursor for the next page: params.Cursor = nextCursor
> ```

- **`ListStars`/`GetStarred` now use cursor-based pagination** — `StarsParameters` replaces
`Count`/`Page` with `Cursor`/`Limit` (and adds `TeamID`), and `ListStars`/`ListStarsContext`/
`GetStarred`/`GetStarredContext` now return `string` (next cursor) instead of `*Paging`.
Slack's `stars.list` API no longer returns `paging` data — only `response_metadata.next_cursor`.

> [!WARNING]
> **Breaking change.** Both the parameters and return signature have changed:
>
> ```go
> // Before
> params := slack.NewStarsParameters()
> params.Count = 100
> params.Page = 2
> items, paging, err := api.ListStars(params)
>
> // After
> params := slack.NewStarsParameters()
> params.Limit = 100
> items, nextCursor, err := api.ListStars(params)
> // Use nextCursor for the next page: params.Cursor = nextCursor
> ```

- **`GetAccessLogs` now uses cursor-based pagination** — `AccessLogParameters` replaces
`Count`/`Page` with `Cursor`/`Limit` (and adds `Before`), and `GetAccessLogs`/
`GetAccessLogsContext` now return `string` (next cursor) instead of `*Paging`.
Slack's `team.accessLogs` API warns `use_cursor_pagination_instead` when using the old
parameters.

> [!WARNING]
> **Breaking change.** Both the parameters and return signature have changed:
>
> ```go
> // Before
> params := slack.NewAccessLogParameters()
> params.Count = 100
> params.Page = 2
> logins, paging, err := api.GetAccessLogs(params)
>
> // After
> params := slack.NewAccessLogParameters()
> params.Limit = 100
> logins, nextCursor, err := api.GetAccessLogs(params)
> // Use nextCursor for the next page: params.Cursor = nextCursor
> ```

### Fixed

- **`WorkflowButtonBlockElement` missing from `UnmarshalJSON`** — `workflow_button` blocks
Expand Down
4 changes: 2 additions & 2 deletions examples/reactions/reactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ func main() {

// List all of the users reactions.
listParams := slack.NewListReactionsParameters()
fmt.Printf("Listing reactions with params: User=%q, TeamID=%q, Count=%d, Page=%d, Full=%v\n",
listParams.User, listParams.TeamID, listParams.Count, listParams.Page, listParams.Full)
fmt.Printf("Listing reactions with params: User=%q, TeamID=%q, Cursor=%q, Limit=%d, Full=%v\n",
listParams.User, listParams.TeamID, listParams.Cursor, listParams.Limit, listParams.Full)
listReactions, _, err := api.ListReactions(listParams)
if err != nil {
fmt.Printf("Error listing reactions: %v\n", err)
Expand Down
20 changes: 15 additions & 5 deletions examples/stars/stars.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,37 @@ package main
import (
"flag"
"fmt"
"os"

"github.com/slack-go/slack"
)

func main() {
var (
apiToken string
debug bool
debug bool
team string
)

flag.StringVar(&apiToken, "token", "YOUR_TOKEN_HERE", "Your Slack API Token")
// Get token from environment variable
apiToken := os.Getenv("SLACK_USER_TOKEN")
if apiToken == "" {
fmt.Println("SLACK_USER_TOKEN environment variable is required")
os.Exit(1)
}

flag.BoolVar(&debug, "debug", false, "Show JSON output")
flag.StringVar(&team, "team", "", "Team ID (required for Enterprise Grid)")
flag.Parse()

api := slack.New(apiToken, slack.OptionDebug(debug))

// Get all stars for the usr.
// Get all stars for the user.
params := slack.NewStarsParameters()
params.TeamID = team

starredItems, _, err := api.GetStarred(params)
if err != nil {
fmt.Printf("Error getting stars: %s\n", err)
fmt.Printf("Error getting stars: %v\n", err)
return
}
for _, s := range starredItems {
Expand Down
36 changes: 16 additions & 20 deletions reactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,29 +70,25 @@ func (res getReactionsResponseFull) extractReactedItem() ReactedItem {
}

const (
DEFAULT_REACTIONS_USER = ""
DEFAULT_REACTIONS_COUNT = 100
DEFAULT_REACTIONS_PAGE = 1
DEFAULT_REACTIONS_FULL = false
DEFAULT_REACTIONS_USER = ""
DEFAULT_REACTIONS_FULL = false
)

// ListReactionsParameters is the inputs to find all reactions by a user.
type ListReactionsParameters struct {
User string
TeamID string
Count int
Page int
Cursor string
Limit int
Full bool
}

// NewListReactionsParameters initializes the inputs to find all reactions
// performed by a user.
func NewListReactionsParameters() ListReactionsParameters {
return ListReactionsParameters{
User: DEFAULT_REACTIONS_USER,
Count: DEFAULT_REACTIONS_COUNT,
Page: DEFAULT_REACTIONS_PAGE,
Full: DEFAULT_REACTIONS_FULL,
User: DEFAULT_REACTIONS_USER,
Full: DEFAULT_REACTIONS_FULL,
}
}

Expand All @@ -112,8 +108,8 @@ type listReactionsResponseFull struct {
Reactions []ItemReaction
} `json:"comment"`
}
Paging `json:"paging"`
SlackResponse
ResponseMetadata `json:"response_metadata"`
}

func (res listReactionsResponseFull) extractReactedItems() []ReactedItem {
Expand Down Expand Up @@ -253,13 +249,13 @@ func (api *Client) GetReactionsContext(ctx context.Context, item ItemRef, params

// ListReactions returns information about the items a user reacted to.
// For more details, see ListReactionsContext documentation.
func (api *Client) ListReactions(params ListReactionsParameters) ([]ReactedItem, *Paging, error) {
func (api *Client) ListReactions(params ListReactionsParameters) ([]ReactedItem, string, error) {
return api.ListReactionsContext(context.Background(), params)
}

// ListReactionsContext returns information about the items a user reacted to with a custom context.
// Slack API docs: https://api.slack.com/methods/reactions.list
func (api *Client) ListReactionsContext(ctx context.Context, params ListReactionsParameters) ([]ReactedItem, *Paging, error) {
func (api *Client) ListReactionsContext(ctx context.Context, params ListReactionsParameters) ([]ReactedItem, string, error) {
values := url.Values{
"token": {api.token},
}
Expand All @@ -269,11 +265,11 @@ func (api *Client) ListReactionsContext(ctx context.Context, params ListReaction
if params.TeamID != "" {
values.Add("team_id", params.TeamID)
}
if params.Count != DEFAULT_REACTIONS_COUNT {
values.Add("count", strconv.Itoa(params.Count))
if params.Cursor != "" {
values.Add("cursor", params.Cursor)
}
if params.Page != DEFAULT_REACTIONS_PAGE {
values.Add("page", strconv.Itoa(params.Page))
if params.Limit != 0 {
values.Add("limit", strconv.Itoa(params.Limit))
}
if params.Full {
values.Add("full", strconv.FormatBool(params.Full))
Expand All @@ -282,12 +278,12 @@ func (api *Client) ListReactionsContext(ctx context.Context, params ListReaction
response := &listReactionsResponseFull{}
err := api.postMethod(ctx, "reactions.list", values, response)
if err != nil {
return nil, nil, err
return nil, "", err
}

if err := response.Err(); err != nil {
return nil, nil, err
return nil, "", err
}

return response.extractReactedItems(), &response.Paging, nil
return response.extractReactedItems(), response.ResponseMetadata.Cursor, nil
}
30 changes: 14 additions & 16 deletions reactions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ func (rh *reactionsHandler) accumulateFormValue(k string, r *http.Request) {

func (rh *reactionsHandler) handler(w http.ResponseWriter, r *http.Request) {
rh.accumulateFormValue("channel", r)
rh.accumulateFormValue("count", r)
rh.accumulateFormValue("cursor", r)
rh.accumulateFormValue("file", r)
rh.accumulateFormValue("file_comment", r)
rh.accumulateFormValue("full", r)
rh.accumulateFormValue("limit", r)
rh.accumulateFormValue("name", r)
rh.accumulateFormValue("page", r)
rh.accumulateFormValue("timestamp", r)
rh.accumulateFormValue("user", r)
w.Header().Set("Content-Type", "application/json")
Expand Down Expand Up @@ -429,11 +429,8 @@ func TestSlack_ListReactions(t *testing.T) {
}
}
],
"paging": {
"count": 100,
"total": 4,
"page": 1,
"pages": 1
"response_metadata": {
"next_cursor": "dXNlcjpVMDYxTkZUVDI="
}}`
want := []ReactedItem{
{
Expand Down Expand Up @@ -463,17 +460,18 @@ func TestSlack_ListReactions(t *testing.T) {
},
}
wantParams := map[string]string{
"user": "User",
"count": "200",
"page": "2",
"full": "true",
"user": "User",
"cursor": "somecursor",
"limit": "200",
"full": "true",
}
wantCursor := "dXNlcjpVMDYxTkZUVDI="
params := NewListReactionsParameters()
params.User = "User"
params.Count = 200
params.Page = 2
params.Cursor = "somecursor"
params.Limit = 200
params.Full = true
got, paging, err := api.ListReactions(params)
got, nextCursor, err := api.ListReactions(params)
if err != nil {
t.Fatalf("Unexpected error: %s", err)
}
Expand All @@ -490,7 +488,7 @@ func TestSlack_ListReactions(t *testing.T) {
if !reflect.DeepEqual(rh.gotParams, wantParams) {
t.Errorf("Got params %#v, want %#v", rh.gotParams, wantParams)
}
if reflect.DeepEqual(paging, Paging{}) {
t.Errorf("Want paging data, got empty struct")
if nextCursor != wantCursor {
t.Errorf("Got cursor %q, want %q", nextCursor, wantCursor)
}
}
Loading
Loading