diff --git a/slackevents/inner_events.go b/slackevents/inner_events.go index 7366e08b..bc584260 100644 --- a/slackevents/inner_events.go +++ b/slackevents/inner_events.go @@ -551,6 +551,104 @@ type UserProfileChangedEvent struct { EventTs string `json:"event_ts"` } +// SharedChannelInviteApprovedEvent is sent if your invitation has been approved +type SharedChannelInviteApprovedEvent struct { + Type string `json:"type"` + Invite *SharedInvite `json:"invite"` + Channel *slack.Conversation `json:"channel"` + ApprovingTeamID string `json:"approving_team_id"` + TeamsInChannel []*SlackEventTeam `json:"teams_in_channel"` + ApprovingUser *SlackEventUser `json:"approving_user"` + EventTs string `json:"event_ts"` +} + +// SharedChannelInviteAcceptedEvent is sent if external org accepts a Slack Connect channel invite +type SharedChannelInviteAcceptedEvent struct { + Type string `json:"type"` + ApprovalRequired bool `json:"approval_required"` + Invite *SharedInvite `json:"invite"` + Channel *SharedChannel `json:"channel"` + TeamsInChannel []*SlackEventTeam `json:"teams_in_channel"` + AcceptingUser *SlackEventUser `json:"accepting_user"` + EventTs string `json:"event_ts"` + RequiresSponsorship bool `json:"requires_sponsorship,omitempty"` +} + +// SharedChannelInviteDeclinedEvent is sent if external or internal org declines the Slack Connect invite +type SharedChannelInviteDeclinedEvent struct { + Type string `json:"type"` + Invite *SharedInvite `json:"invite"` + Channel *SharedChannel `json:"channel"` + DecliningTeamID string `json:"declining_team_id"` + TeamsInChannel []*SlackEventTeam `json:"teams_in_channel"` + DecliningUser *SlackEventUser `json:"declining_user"` + EventTs string `json:"event_ts"` +} + +// SharedChannelInviteReceivedEvent is sent if a bot or app is invited to a Slack Connect channel +type SharedChannelInviteReceivedEvent struct { + Type string `json:"type"` + Invite *SharedInvite `json:"invite"` + Channel *SharedChannel `json:"channel"` + EventTs string `json:"event_ts"` +} + +// SlackEventTeam is a struct for teams in ShareChannel events +type SlackEventTeam struct { + ID string `json:"id"` + Name string `json:"name"` + Icon *SlackEventIcon `json:"icon,omitempty"` + AvatarBaseURL string `json:"avatar_base_url,omitempty"` + IsVerified bool `json:"is_verified"` + Domain string `json:"domain"` + DateCreated int `json:"date_created"` + RequiresSponsorship bool `json:"requires_sponsorship,omitempty"` + // TeamID string `json:"team_id,omitempty"` +} + +// SlackEventIcon is a struct for icons in ShareChannel events +type SlackEventIcon struct { + ImageDefault bool `json:"image_default,omitempty"` + Image34 string `json:"image_34,omitempty"` + Image44 string `json:"image_44,omitempty"` + Image68 string `json:"image_68,omitempty"` + Image88 string `json:"image_88,omitempty"` + Image102 string `json:"image_102,omitempty"` + Image132 string `json:"image_132,omitempty"` + Image230 string `json:"image_230,omitempty"` +} + +// SlackEventUser is a struct for users in ShareChannel events +type SlackEventUser struct { + ID string `json:"id"` + TeamID string `json:"team_id"` + Name string `json:"name"` + Updated int `json:"updated,omitempty"` + Profile *slack.UserProfile `json:"profile,omitempty"` + WhoCanShareContactCard string `json:"who_can_share_contact_card,omitempty"` +} + +// SharedChannel is a struct for shared channels in ShareChannel events +type SharedChannel struct { + ID string `json:"id"` + IsPrivate bool `json:"is_private"` + IsIm bool `json:"is_im"` + Name string `json:"name,omitempty"` +} + +// SharedInvite is a struct for shared invites in ShareChannel events +type SharedInvite struct { + ID string `json:"id"` + DateCreated int `json:"date_created"` + DateInvalid int `json:"date_invalid"` + InvitingTeam *SlackEventTeam `json:"inviting_team,omitempty"` + InvitingUser *SlackEventUser `json:"inviting_user,omitempty"` + RecipientEmail string `json:"recipient_email,omitempty"` + RecipientUserID string `json:"recipient_user_id,omitempty"` + IsSponsored bool `json:"is_sponsored,omitempty"` + IsExternalLimited bool `json:"is_external_limited,omitempty"` +} + type EventsAPIType string const ( @@ -614,6 +712,14 @@ const ( ReactionRemoved = EventsAPIType("reaction_removed") // TeamJoin A new user joined the workspace TeamJoin = EventsAPIType("team_join") + // Slack connect app or bot invite received + SharedChannelInviteReceived = EventsAPIType("shared_channel_invite_received") + // Slack connect channel invite approved + SharedChannelInviteApproved = EventsAPIType("shared_channel_invite_approved") + // Slack connect channel invite declined + SharedChannelInviteDeclined = EventsAPIType("shared_channel_invite_declined") + // Slack connect channel invite accepted by an end user + SharedChannelInviteAccepted = EventsAPIType("shared_channel_invite_accepted") // TokensRevoked APP's API tokes are revoked TokensRevoked = EventsAPIType("tokens_revoked") // EmojiChanged A custom emoji has been added or changed @@ -638,43 +744,47 @@ const ( // implementations. The structs should be instances of the unmarshalling // target for the matching event type. var EventsAPIInnerEventMapping = map[EventsAPIType]interface{}{ - AppMention: AppMentionEvent{}, - AppHomeOpened: AppHomeOpenedEvent{}, - AppUninstalled: AppUninstalledEvent{}, - ChannelCreated: ChannelCreatedEvent{}, - ChannelDeleted: ChannelDeletedEvent{}, - ChannelArchive: ChannelArchiveEvent{}, - ChannelUnarchive: ChannelUnarchiveEvent{}, - ChannelLeft: ChannelLeftEvent{}, - ChannelRename: ChannelRenameEvent{}, - ChannelIDChanged: ChannelIDChangedEvent{}, - FileChange: FileChangeEvent{}, - FileDeleted: FileDeletedEvent{}, - FileShared: FileSharedEvent{}, - FileUnshared: FileUnsharedEvent{}, - GroupDeleted: GroupDeletedEvent{}, - GroupArchive: GroupArchiveEvent{}, - GroupUnarchive: GroupUnarchiveEvent{}, - GroupLeft: GroupLeftEvent{}, - GroupRename: GroupRenameEvent{}, - GridMigrationFinished: GridMigrationFinishedEvent{}, - GridMigrationStarted: GridMigrationStartedEvent{}, - LinkShared: LinkSharedEvent{}, - Message: MessageEvent{}, - MemberJoinedChannel: MemberJoinedChannelEvent{}, - MemberLeftChannel: MemberLeftChannelEvent{}, - PinAdded: PinAddedEvent{}, - PinRemoved: PinRemovedEvent{}, - ReactionAdded: ReactionAddedEvent{}, - ReactionRemoved: ReactionRemovedEvent{}, - TeamJoin: TeamJoinEvent{}, - TokensRevoked: TokensRevokedEvent{}, - EmojiChanged: EmojiChangedEvent{}, - WorkflowStepExecute: WorkflowStepExecuteEvent{}, - MessageMetadataPosted: MessageMetadataPostedEvent{}, - MessageMetadataUpdated: MessageMetadataUpdatedEvent{}, - MessageMetadataDeleted: MessageMetadataDeletedEvent{}, - TeamAccessGranted: TeamAccessGrantedEvent{}, - TeamAccessRevoked: TeamAccessRevokedEvent{}, - UserProfileChanged: UserProfileChangedEvent{}, + AppMention: AppMentionEvent{}, + AppHomeOpened: AppHomeOpenedEvent{}, + AppUninstalled: AppUninstalledEvent{}, + ChannelCreated: ChannelCreatedEvent{}, + ChannelDeleted: ChannelDeletedEvent{}, + ChannelArchive: ChannelArchiveEvent{}, + ChannelUnarchive: ChannelUnarchiveEvent{}, + ChannelLeft: ChannelLeftEvent{}, + ChannelRename: ChannelRenameEvent{}, + ChannelIDChanged: ChannelIDChangedEvent{}, + FileChange: FileChangeEvent{}, + FileDeleted: FileDeletedEvent{}, + FileShared: FileSharedEvent{}, + FileUnshared: FileUnsharedEvent{}, + GroupDeleted: GroupDeletedEvent{}, + GroupArchive: GroupArchiveEvent{}, + GroupUnarchive: GroupUnarchiveEvent{}, + GroupLeft: GroupLeftEvent{}, + GroupRename: GroupRenameEvent{}, + GridMigrationFinished: GridMigrationFinishedEvent{}, + GridMigrationStarted: GridMigrationStartedEvent{}, + LinkShared: LinkSharedEvent{}, + Message: MessageEvent{}, + MemberJoinedChannel: MemberJoinedChannelEvent{}, + MemberLeftChannel: MemberLeftChannelEvent{}, + PinAdded: PinAddedEvent{}, + PinRemoved: PinRemovedEvent{}, + ReactionAdded: ReactionAddedEvent{}, + ReactionRemoved: ReactionRemovedEvent{}, + SharedChannelInviteApproved: SharedChannelInviteApprovedEvent{}, + SharedChannelInviteAccepted: SharedChannelInviteAcceptedEvent{}, + SharedChannelInviteDeclined: SharedChannelInviteDeclinedEvent{}, + SharedChannelInviteReceived: SharedChannelInviteReceivedEvent{}, + TeamJoin: TeamJoinEvent{}, + TokensRevoked: TokensRevokedEvent{}, + EmojiChanged: EmojiChangedEvent{}, + WorkflowStepExecute: WorkflowStepExecuteEvent{}, + MessageMetadataPosted: MessageMetadataPostedEvent{}, + MessageMetadataUpdated: MessageMetadataUpdatedEvent{}, + MessageMetadataDeleted: MessageMetadataDeletedEvent{}, + TeamAccessGranted: TeamAccessGrantedEvent{}, + TeamAccessRevoked: TeamAccessRevokedEvent{}, + UserProfileChanged: UserProfileChangedEvent{}, } diff --git a/slackevents/inner_events_test.go b/slackevents/inner_events_test.go index f21f66be..20b8bff5 100644 --- a/slackevents/inner_events_test.go +++ b/slackevents/inner_events_test.go @@ -2,7 +2,10 @@ package slackevents import ( "encoding/json" + "fmt" "testing" + + "github.com/stretchr/testify/assert" ) func TestAppMention(t *testing.T) { @@ -376,19 +379,31 @@ func TestThreadBroadcastEvent(t *testing.T) { func TestMemberJoinedChannelEvent(t *testing.T) { rawE := []byte(` - { - "type": "member_joined_channel", - "user": "W06GH7XHN", - "channel": "C0698JE0H", - "channel_type": "C", - "team": "T024BE7LD", - "inviter": "U123456789" + { + "type": "member_joined_channel", + "user": "W06GH7XHN", + "channel": "C0698JE0H", + "channel_type": "C", + "team": "T024BE7LD", + "inviter": "U123456789" } `) - err := json.Unmarshal(rawE, &MemberJoinedChannelEvent{}) + evt := MemberJoinedChannelEvent{} + err := json.Unmarshal(rawE, &evt) if err != nil { t.Error(err) } + + expected := MemberJoinedChannelEvent{ + Type: "member_joined_channel", + User: "W06GH7XHN", + Channel: "C0698JE0H", + ChannelType: "C", + Team: "T024BE7LD", + Inviter: "U123456789", + } + + assert.Equal(t, expected, evt) } func TestMemberLeftChannelEvent(t *testing.T) { @@ -914,3 +929,572 @@ func TestUserProfileChanged(t *testing.T) { t.Fail() } } + +func TestSharedChannelInvite(t *testing.T) { + rawE := []byte(` + { + "token": "whatever", + "team_id": "whatever", + "api_app_id": "whatever", + "event": { + "type": "shared_channel_invite_received", + "invite": { + "id": "I028YDERZSQ", + "date_created": 1626876000, + "date_invalid": 1628085600, + "inviting_team": { + "id": "T12345678", + "name": "Corgis", + "icon": {}, + "is_verified": false, + "domain": "corgis", + "date_created": 1480946400 + }, + "inviting_user": { + "id": "U12345678", + "team_id": "T12345678", + "name": "crus", + "updated": 1608081902, + "profile": { + "real_name": "Corgis Rus", + "display_name": "Corgis Rus", + "real_name_normalized": "Corgis Rus", + "display_name_normalized": "Corgis Rus", + "team": "T12345678", + "avatar_hash": "gcfh83a4c72k", + "email": "corgisrus@slack-corp.com", + "image_24": "https://placekitten.com/24/24", + "image_32": "https://placekitten.com/32/32", + "image_48": "https://placekitten.com/48/48", + "image_72": "https://placekitten.com/72/72", + "image_192": "https://placekitten.com/192/192", + "image_512": "https://placekitten.com/512/512" + } + }, + "recipient_user_id": "U87654321" + }, + "channel": { + "id": "C12345678", + "is_private": false, + "is_im": false, + "name": "test-slack-connect" + }, + "event_ts": "1626876010.000100" + } + } + `) + + evt := &EventsAPICallbackEvent{} + err := json.Unmarshal(rawE, evt) + if err != nil { + t.Fatal(err) + } + + parsedEvent, err := parseInnerEvent(evt) + if err != nil { + t.Fatal(err) + } + + actual, ok := parsedEvent.InnerEvent.Data.(*SharedChannelInviteReceivedEvent) + if !ok { + t.Fail() + } + + if actual.Invite.ID != "I028YDERZSQ" { + t.Fail() + } + + if actual.Invite.InvitingTeam.ID != "T12345678" { + t.Fail() + } + + if actual.Invite.InvitingUser.ID != "U12345678" { + t.Fail() + } + + if actual.Invite.RecipientUserID != "U87654321" { + t.Fail() + } + + if actual.Channel.ID != "C12345678" { + t.Fail() + } + + if parsedEvent.InnerEvent.Type != "shared_channel_invite_received" { + t.Fail() + } + +} + +// Test that the shared_channel_invite_accepted event can be unmarshalled +func TestSharedChannelAccepted(t *testing.T) { + rawE := []byte(` + { + "token": "whatever", + "team_id": "whatever", + "api_app_id": "whatever", + "event": { + "type": "shared_channel_invite_accepted", + "approval_required": false, + "invite": { + "id": "I028YDERZSQ", + "date_created": 1626876000, + "date_invalid": 1628085600, + "inviting_team": { + "id": "T12345678", + "name": "Corgis", + "icon": { + "image_default": true, + "image_34": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-34.png", + "image_44": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-44.png", + "image_68": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-68.png", + "image_88": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-88.png", + "image_102": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-102.png", + "image_230": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-230.png", + "image_132": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-132.png" + }, + "is_verified": false, + "domain": "corgis", + "date_created": 1480946400 + }, + "inviting_user": { + "id": "U12345678", + "team_id": "T12345678", + "name": "crus", + "updated": 1608081902, + "profile": { + "real_name": "Corgis Rus", + "display_name": "Corgis Rus", + "real_name_normalized": "Corgis Rus", + "display_name_normalized": "Corgis Rus", + "team": "T12345678", + "avatar_hash": "gcfh83a4c72k", + "email": "corgisrus@slack-corp.com", + "image_24": "https://placekitten.com/24/24", + "image_32": "https://placekitten.com/32/32", + "image_48": "https://placekitten.com/48/48", + "image_72": "https://placekitten.com/72/72", + "image_192": "https://placekitten.com/192/192", + "image_512": "https://placekitten.com/512/512" + } + }, + "recipient_email": "golden@doodle.com", + "recipient_user_id": "U87654321" + }, + "channel": { + "id": "C12345678", + "is_private": false, + "is_im": false, + "name": "test-slack-connect" + }, + "teams_in_channel": [ + { + "id": "T12345678", + "name": "Corgis", + "icon": { + "image_default": true, + "image_34": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-34.png", + "image_44": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-44.png", + "image_68": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-68.png", + "image_88": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-88.png", + "image_102": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-102.png", + "image_230": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-230.png", + "image_132": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-132.png" + }, + "is_verified": false, + "domain": "corgis", + "date_created": 1626789600 + } + ], + "accepting_user": { + "id": "U87654321", + "team_id": "T87654321", + "name": "golden", + "updated": 1624406113, + "profile": { + "real_name": "Golden Doodle", + "display_name": "Golden", + "real_name_normalized": "Golden Doodle", + "display_name_normalized": "Golden", + "team": "T87654321", + "avatar_hash": "g717728b118x", + "email": "golden@doodle.com", + "image_24": "https://placekitten.com/24/24", + "image_32": "https://placekitten.com/32/32", + "image_48": "https://placekitten.com/48/48", + "image_72": "https://placekitten.com/72/72", + "image_192": "https://placekitten.com/192/192", + "image_512": "https://placekitten.com/512/512" + } + }, + "event_ts": "1626877800.000000" + } + } + `) + + evt := &EventsAPICallbackEvent{} + err := json.Unmarshal(rawE, evt) + if err != nil { + t.Fatal(err) + } + + parsedEvent, err := parseInnerEvent(evt) + if err != nil { + t.Fatal(err) + } + + actual, ok := parsedEvent.InnerEvent.Data.(*SharedChannelInviteAcceptedEvent) + if !ok { + t.Fail() + } + + if actual.Invite.ID != "I028YDERZSQ" { + t.Fail() + } + + if actual.Invite.InvitingTeam.ID != "T12345678" { + t.Fail() + } + + if actual.Invite.InvitingUser.ID != "U12345678" { + t.Fail() + } + + if actual.Invite.RecipientUserID != "U87654321" { + t.Fail() + } + + if actual.Channel.ID != "C12345678" { + t.Fail() + } + + if actual.Channel.Name != "test-slack-connect" { + t.Fail() + fmt.Println(actual.Channel.Name + ", does not match the test name.") + } + + if actual.AcceptingUser.ID != "U87654321" { + t.Fail() + } + + if actual.AcceptingUser.Profile.RealName != "Golden Doodle" { + t.Fail() + } + + if parsedEvent.InnerEvent.Type != "shared_channel_invite_accepted" { + t.Fail() + } + +} + +// Test that the shared_channel_invite_declined event can be unmarshalled +func TestSharedChannelApproved(t *testing.T) { + rawE := []byte(` + { + "token": "whatever", + "team_id": "whatever", + "api_app_id": "whatever", + "event": { + "type": "shared_channel_invite_approved", + "invite": { + "id": "I01354X80CA", + "date_created": 1626876000, + "date_invalid": 1628085600, + "inviting_team": { + "id": "T12345678", + "name": "Corgis", + "icon": { + "image_default": true, + "image_34": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-34.png", + "image_44": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-44.png", + "image_68": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-68.png", + "image_88": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-88.png", + "image_102": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-102.png", + "image_230": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-230.png", + "image_132": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-132.png" + }, + "is_verified": false, + "domain": "corgis", + "date_created": 1480946400 + }, + "inviting_user": { + "id": "U12345678", + "team_id": "T12345678", + "name": "crus", + "updated": 1608081902, + "profile": { + "real_name": "Corgis Rus", + "display_name": "Corgis Rus", + "real_name_normalized": "Corgis Rus", + "display_name_normalized": "Corgis Rus", + "team": "T12345678", + "avatar_hash": "gcfh83a4c72k", + "email": "corgisrus@slack-corp.com", + "image_24": "https://placekitten.com/24/24", + "image_32": "https://placekitten.com/32/32", + "image_48": "https://placekitten.com/48/48", + "image_72": "https://placekitten.com/72/72", + "image_192": "https://placekitten.com/192/192", + "image_512": "https://placekitten.com/512/512" + } + }, + "recipient_email": "golden@doodle.com", + "recipient_user_id": "U87654321" + }, + "channel": { + "id": "C12345678", + "is_private": false, + "is_im": false, + "name": "test-slack-connect" + }, + "approving_team_id": "T87654321", + "teams_in_channel": [ + { + "id": "T12345678", + "name": "Corgis", + "icon": { + "image_default": true, + "image_34": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-34.png", + "image_44": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-44.png", + "image_68": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-68.png", + "image_88": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-88.png", + "image_102": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-102.png", + "image_230": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-230.png", + "image_132": "https://a.slack-edge.com/80588/img/avatars-teams/ava_0011-132.png" + }, + "is_verified": false, + "domain": "corgis", + "date_created": 1626789600 + } + ], + "approving_user": { + "id": "U012A3CDE", + "team_id": "T87654321", + "name": "spengler", + "updated": 1624406532, + "profile": { + "real_name": "Egon Spengler", + "display_name": "Egon", + "real_name_normalized": "Egon Spengler", + "display_name_normalized": "Egon", + "team": "T87654321", + "avatar_hash": "g216425b1681", + "email": "spengler@ghostbusters.example.com", + "image_24": "https://placekitten.com/24/24", + "image_32": "https://placekitten.com/32/32", + "image_48": "https://placekitten.com/48/48", + "image_72": "https://placekitten.com/72/72", + "image_192": "https://placekitten.com/192/192", + "image_512": "https://placekitten.com/512/512" + } + }, + "event_ts": "1626881400.000000" + } + } + `) + + evt := &EventsAPICallbackEvent{} + err := json.Unmarshal(rawE, evt) + if err != nil { + t.Fatal(err) + } + + parsedEvent, err := parseInnerEvent(evt) + if err != nil { + t.Fatal(err) + } + + actual, ok := parsedEvent.InnerEvent.Data.(*SharedChannelInviteApprovedEvent) + if !ok { + t.Fail() + } + + if actual.Invite.ID != "I01354X80CA" { + t.Fail() + } + + if actual.Invite.InvitingTeam.ID != "T12345678" { + t.Fail() + } + + if actual.Invite.InvitingUser.ID != "U12345678" { + t.Fail() + } + + if actual.Invite.RecipientUserID != "U87654321" { + t.Fail() + } + + if actual.Channel.ID != "C12345678" { + t.Fail() + } + + if actual.ApprovingTeamID != "T87654321" { + t.Fail() + } + + if actual.ApprovingUser.Name != "spengler" { + t.Fail() + } + + if actual.ApprovingUser.Profile.RealName != "Egon Spengler" { + t.Fail() + } + + if actual.TeamsInChannel[0].ID != "T12345678" { + t.Fail() + } + + if parsedEvent.InnerEvent.Type != "shared_channel_invite_approved" { + t.Fail() + } + +} + +func TestSharedChannelDeclined(t *testing.T) { + rawE := []byte(` + { + "token": "whatever", + "team_id": "whatever", + "api_app_id": "whatever", + "event": { + "type": "shared_channel_invite_declined", + "invite": { + "id": "I01354X80CA", + "date_created": 1626876000, + "date_invalid": 1628085600, + "inviting_team": { + "id": "T12345678", + "name": "Corgis", + "icon": {}, + "is_verified": false, + "domain": "corgis", + "date_created": 1480946400 + }, + "inviting_user": { + "id": "U12345678", + "team_id": "T12345678", + "name": "crus", + "updated": 1608081902, + "profile": { + "real_name": "Corgis Rus", + "display_name": "Corgis Rus", + "real_name_normalized": "Corgis Rus", + "display_name_normalized": "Corgis Rus", + "team": "T12345678", + "avatar_hash": "gcfh83a4c72k", + "email": "corgisrus@slack-corp.com", + "image_24": "https://placekitten.com/24/24", + "image_32": "https://placekitten.com/32/32", + "image_48": "https://placekitten.com/48/48", + "image_72": "https://placekitten.com/72/72", + "image_192": "https://placekitten.com/192/192", + "image_512": "https://placekitten.com/512/512" + } + }, + "recipient_email": "golden@doodle.com" + }, + "channel": { + "id": "C12345678", + "is_private": false, + "is_im": false, + "name": "test-slack-connect" + }, + "declining_team_id": "T87654321", + "teams_in_channel": [ + { + "id": "T12345678", + "name": "Corgis", + "icon": {}, + "is_verified": false, + "domain": "corgis", + "date_created": 1626789600 + } + ], + "declining_user": { + "id": "U012A3CDE", + "team_id": "T87654321", + "name": "spengler", + "updated": 1624406532, + "profile": { + "real_name": "Egon Spengler", + "display_name": "Egon", + "real_name_normalized": "Egon Spengler", + "display_name_normalized": "Egon", + "team": "T87654321", + "avatar_hash": "g216425b1681", + "email": "spengler@ghostbusters.example.com", + "image_24": "https://placekitten.com/24/24", + "image_32": "https://placekitten.com/32/32", + "image_48": "https://placekitten.com/48/48", + "image_72": "https://placekitten.com/72/72", + "image_192": "https://placekitten.com/192/192", + "image_512": "https://placekitten.com/512/512" + } + }, + "event_ts": "1626881400.000000" + } + } + `) + + evt := &EventsAPICallbackEvent{} + err := json.Unmarshal(rawE, evt) + if err != nil { + t.Fatal(err) + } + + parsedEvent, err := parseInnerEvent(evt) + if err != nil { + t.Fatal(err) + } + + actual, ok := parsedEvent.InnerEvent.Data.(*SharedChannelInviteDeclinedEvent) + if !ok { + t.Fail() + } + + if actual.Invite.ID != "I01354X80CA" { + t.Fail() + } + + if actual.Invite.InvitingTeam.ID != "T12345678" { + t.Fail() + } + + if actual.Invite.InvitingUser.ID != "U12345678" { + t.Fail() + } + + if actual.Invite.RecipientEmail != "golden@doodle.com" { + t.Fail() + } + + if actual.Channel.ID != "C12345678" { + t.Fail() + } + + if actual.DecliningTeamID != "T87654321" { + t.Fail() + } + + if actual.DecliningUser.Name != "spengler" { + t.Fail() + } + + if actual.DecliningUser.Profile.RealName != "Egon Spengler" { + t.Fail() + } + + if actual.TeamsInChannel[0].ID != "T12345678" { + t.Fail() + } + + if actual.EventTs != "1626881400.000000" { + t.Fail() + } + + if parsedEvent.InnerEvent.Type != "shared_channel_invite_declined" { + t.Fail() + } + +} diff --git a/slackevents/parsers.go b/slackevents/parsers.go index 96ba5681..4daac8b1 100644 --- a/slackevents/parsers.go +++ b/slackevents/parsers.go @@ -117,7 +117,7 @@ func parseInnerEvent(e *EventsAPICallbackEvent) (EventsAPIEvent, error) { e.EnterpriseID, nil, EventsAPIInnerEvent{}, - }, fmt.Errorf("Inner Event does not exist! %s", iE.Type) + }, fmt.Errorf("inner Event does not exist! %s", iE.Type) } t := reflect.TypeOf(v) recvEvent := reflect.New(t).Interface() @@ -192,7 +192,7 @@ func ParseEvent(rawEvent json.RawMessage, opts ...Option) (EventsAPIEvent, error } if !cfg.TokenVerified { - return EventsAPIEvent{}, errors.New("Invalid verification token") + return EventsAPIEvent{}, errors.New("invalid verification token") } if e.Type == CallbackEvent { diff --git a/users.go b/users.go index a3b4c066..a3d32b24 100644 --- a/users.go +++ b/users.go @@ -17,31 +17,32 @@ const ( // UserProfile contains all the information details of a given user type UserProfile struct { - FirstName string `json:"first_name"` - LastName string `json:"last_name"` + FirstName string `json:"first_name,omitempty"` + LastName string `json:"last_name,omitempty"` RealName string `json:"real_name"` RealNameNormalized string `json:"real_name_normalized"` DisplayName string `json:"display_name"` DisplayNameNormalized string `json:"display_name_normalized"` - Email string `json:"email"` - Skype string `json:"skype"` - Phone string `json:"phone"` + AvatarHash string `json:"avatar_hash"` + Email string `json:"email,omitempty"` + Skype string `json:"skyp,omitempty"` + Phone string `json:"phone,omitempty"` Image24 string `json:"image_24"` Image32 string `json:"image_32"` Image48 string `json:"image_48"` Image72 string `json:"image_72"` Image192 string `json:"image_192"` Image512 string `json:"image_512"` - ImageOriginal string `json:"image_original"` - Title string `json:"title"` + ImageOriginal string `json:"image_original,omitempty"` + Title string `json:"title,omitempty"` BotID string `json:"bot_id,omitempty"` ApiAppID string `json:"api_app_id,omitempty"` StatusText string `json:"status_text,omitempty"` StatusEmoji string `json:"status_emoji,omitempty"` StatusEmojiDisplayInfo []UserProfileStatusEmojiDisplayInfo `json:"status_emoji_display_info,omitempty"` - StatusExpiration int `json:"status_expiration"` + StatusExpiration int `json:"status_expiration,omitempty"` Team string `json:"team"` - Fields UserProfileCustomFields `json:"fields"` + Fields UserProfileCustomFields `json:"fields,omitempty"` } type UserProfileStatusEmojiDisplayInfo struct {