From 0de38bf81e662c9697417da4ae6643da2f5475ca Mon Sep 17 00:00:00 2001 From: Simon Oxtoby Date: Sun, 28 Aug 2022 12:46:19 +1000 Subject: [PATCH] Support for Slack Connect invitations --- .../Events/SharedChannelInviteAccepted.cs | 16 ++++ .../Events/SharedChannelInviteApproved.cs | 13 +++ .../Events/SharedChannelInviteDeclined.cs | 13 +++ .../Events/SharedChannelInviteReceived.cs | 8 ++ SlackNet/Objects/ConnectedTeam.cs | 12 +++ SlackNet/Objects/Invite.cs | 13 +++ SlackNet/Objects/InviteChannel.cs | 10 ++ SlackNet/WebApi/ConversationsApi.cs | 94 +++++++++++++++++++ .../Responses/AcceptSharedInviteResponse.cs | 9 ++ .../Responses/ConnectInvitesListResponse.cs | 39 ++++++++ .../WebApi/Responses/InviteSharedResponse.cs | 10 ++ 11 files changed, 237 insertions(+) create mode 100644 SlackNet/Events/SharedChannelInviteAccepted.cs create mode 100644 SlackNet/Events/SharedChannelInviteApproved.cs create mode 100644 SlackNet/Events/SharedChannelInviteDeclined.cs create mode 100644 SlackNet/Events/SharedChannelInviteReceived.cs create mode 100644 SlackNet/Objects/ConnectedTeam.cs create mode 100644 SlackNet/Objects/Invite.cs create mode 100644 SlackNet/Objects/InviteChannel.cs create mode 100644 SlackNet/WebApi/Responses/AcceptSharedInviteResponse.cs create mode 100644 SlackNet/WebApi/Responses/ConnectInvitesListResponse.cs create mode 100644 SlackNet/WebApi/Responses/InviteSharedResponse.cs diff --git a/SlackNet/Events/SharedChannelInviteAccepted.cs b/SlackNet/Events/SharedChannelInviteAccepted.cs new file mode 100644 index 0000000..8153971 --- /dev/null +++ b/SlackNet/Events/SharedChannelInviteAccepted.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace SlackNet.Events +{ + public class SharedChannelInviteAccepted : Event + { + public bool ApprovalRequired { get; set; } + public Invite Invite { get; set; } + public User InvitingUser { get; set; } + public string RecipientEmail { get; set; } + public string RecipientUserId { get; set; } + public InviteChannel Channel { get; set; } + public IList TeamsInChannel { get; set; } = new List(); + public User AcceptingUser { get; set; } + } +} \ No newline at end of file diff --git a/SlackNet/Events/SharedChannelInviteApproved.cs b/SlackNet/Events/SharedChannelInviteApproved.cs new file mode 100644 index 0000000..aebea3a --- /dev/null +++ b/SlackNet/Events/SharedChannelInviteApproved.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace SlackNet.Events +{ + public class SharedChannelInviteApproved : Event + { + public Invite Invite { get; set; } + public InviteChannel Channel { get; set; } + public string ApprovingTeamId { get; set; } + public IList TeamsInChannel { get; set; } = new List(); + public User ApprovingUser { get; set; } + } +} \ No newline at end of file diff --git a/SlackNet/Events/SharedChannelInviteDeclined.cs b/SlackNet/Events/SharedChannelInviteDeclined.cs new file mode 100644 index 0000000..3e83513 --- /dev/null +++ b/SlackNet/Events/SharedChannelInviteDeclined.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace SlackNet.Events +{ + public class SharedChannelInviteDeclined : Event + { + public Invite Invite { get; set; } + public InviteChannel Channel { get; set; } + public string DecliningTeamId { get; set; } + public IList TeamsInChannel { get; set; } = new List(); + public User DecliningUser { get; set; } + } +} \ No newline at end of file diff --git a/SlackNet/Events/SharedChannelInviteReceived.cs b/SlackNet/Events/SharedChannelInviteReceived.cs new file mode 100644 index 0000000..2138e47 --- /dev/null +++ b/SlackNet/Events/SharedChannelInviteReceived.cs @@ -0,0 +1,8 @@ +namespace SlackNet.Events +{ + public class SharedChannelInviteReceived : Event + { + public Invite Invite { get; set; } + public InviteChannel Channel { get; set; } + } +} \ No newline at end of file diff --git a/SlackNet/Objects/ConnectedTeam.cs b/SlackNet/Objects/ConnectedTeam.cs new file mode 100644 index 0000000..5c2b637 --- /dev/null +++ b/SlackNet/Objects/ConnectedTeam.cs @@ -0,0 +1,12 @@ +namespace SlackNet +{ + public class ConnectedTeam + { + public string Id { get; set; } + public string Name { get; set; } + public Icons Icon { get; set; } + public bool IsVerified { get; set; } + public string Domain { get; set; } + public int DateCreated { get; set; } + } +} \ No newline at end of file diff --git a/SlackNet/Objects/Invite.cs b/SlackNet/Objects/Invite.cs new file mode 100644 index 0000000..8869064 --- /dev/null +++ b/SlackNet/Objects/Invite.cs @@ -0,0 +1,13 @@ +namespace SlackNet +{ + public class Invite + { + public string Id { get; set; } + public int DateCreated { get; set; } + public int DateInvalid { get; set; } + public ConnectedTeam InvitingTeam { get; set; } + public User InvitingUser { get; set; } + public string RecipientUserId { get; set; } + public string Link { get; set; } + } +} \ No newline at end of file diff --git a/SlackNet/Objects/InviteChannel.cs b/SlackNet/Objects/InviteChannel.cs new file mode 100644 index 0000000..90ba453 --- /dev/null +++ b/SlackNet/Objects/InviteChannel.cs @@ -0,0 +1,10 @@ +namespace SlackNet +{ + public class InviteChannel + { + public string Id { get; set; } + public bool IsPrivate { get; set; } + public bool IsIm { get; set; } + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/SlackNet/WebApi/ConversationsApi.cs b/SlackNet/WebApi/ConversationsApi.cs index 08faaf7..0b41395 100644 --- a/SlackNet/WebApi/ConversationsApi.cs +++ b/SlackNet/WebApi/ConversationsApi.cs @@ -7,6 +7,28 @@ namespace SlackNet.WebApi { public interface IConversationsApi { + /// + /// Accepts an invitation to a Slack Connect channel. + /// + /// See the Slack documentation for more information. + /// Name of the channel. If the channel does not exist already in your workspace, this name is the one that the channel will take. + /// from the event. + /// ID of the channel that you'd like to accept. Must provide either or . + /// Whether you'd like to use your workspace's free trial to begin using Slack Connect. + /// Whether the channel should be private. + /// The ID of the workspace to accept the channel in. If an org-level token is used to call this method, the argument is required. + /// + Task AcceptSharedInvite(string channelName, string inviteId = null, string channelId = null, bool freeTrialAccepted = false, bool isPrivate = false, string teamId = null, CancellationToken? cancellationToken = null); + + /// + /// Approves an invitation to a Slack Connect channel. + /// + /// See the Slack documentation for more information. + /// ID of the shared channel invite to approve. Subscribe to the event to receive IDs of Slack Connect channel invites that have been accepted and are awaiting approval. + /// The team or enterprise id of the other party involved in the invitation you are approving. + /// + Task ApproveSharedInvite(string inviteId, string targetTeam = null, CancellationToken? cancellationToken = null); + /// /// Archives a conversation. Not all types of conversations can be archived. /// @@ -33,6 +55,15 @@ public interface IConversationsApi /// Task Create(string name, bool isPrivate, CancellationToken? cancellationToken = null); + /// + /// Declines a Slack Connect channel invite. + /// + /// See the Slack documentation for more information. + /// ID of the Slack Connect invite to decline. Subscribe to the event to receive IDs of Slack Connect channel invites that have been accepted and are awaiting approval. + /// The team or enterprise id of the other party involved in the invitation you are declining. + /// + Task DeclineSharedInvite(string inviteId, string targetTeam = null, CancellationToken? cancellationToken = null); + /// /// Fetches a conversation's history of messages and events. /// @@ -69,6 +100,17 @@ public interface IConversationsApi /// Task Invite(string channelId, IEnumerable userIds, CancellationToken? cancellationToken = null); + /// + /// Sends an invitation to a Slack Connect channel. + /// + /// See the Slack documentation for more information. + /// ID of the channel on your team that you'd like to share. + /// Emails to receive this invite. Either or must be provided. + /// User IDs to receive this invite. Either or must be provided. + /// Whether invite is to an external limited member. + /// + Task InviteShared(string channelId, IEnumerable emails, IEnumerable userIds, bool externalLimited = true, CancellationToken? cancellationToken = null); + /// /// Joins an existing conversation. /// @@ -110,6 +152,16 @@ public interface IConversationsApi /// Task List(bool excludeArchived = false, int limit = 100, IEnumerable types = null, string cursor = null, string teamId = null, CancellationToken? cancellationToken = null); + /// + /// Lists shared channel invites that have been generated or received but have not been approved by all parties. + /// + /// See the Slack documentation for more information. + /// Maximum number of invites to return. + /// Set to returned by previous call to list items in subsequent page. + /// Encoded team id for the workspace to retrieve invites for, required if org token is used. + /// + Task ListConnectInvites(int count = 100, string cursor = null, string teamId = null, CancellationToken? cancellationToken = null); + /// /// Sets the read cursor in a channel. /// @@ -230,6 +282,24 @@ public class ConversationsApi : IConversationsApi private readonly ISlackApiClient _client; public ConversationsApi(ISlackApiClient client) => _client = client; + public Task AcceptSharedInvite(string channelName, string inviteId = null, string channelId = null, bool freeTrialAccepted = false, bool isPrivate = false, string teamId = null, CancellationToken? cancellationToken = null) => + _client.Post("conversations.acceptSharedInvite", new Args + { + { "channel_name", channelName }, + { "invite_id", inviteId }, + { "channel_id", channelId }, + { "free_trial_accepted", freeTrialAccepted }, + { "is_private", isPrivate }, + { "team_id", teamId } + }, cancellationToken); + + public Task ApproveSharedInvite(string inviteId, string targetTeam = null, CancellationToken? cancellationToken = null) => + _client.Post("conversations.approveSharedInvite", new Args + { + { "invite_id", inviteId }, + { "target_team", targetTeam } + }, cancellationToken); + public Task Archive(string channelId, CancellationToken? cancellationToken = null) => _client.Post("conversations.archive", new Args { { "channel", channelId } }, cancellationToken); @@ -244,6 +314,13 @@ public async Task Create(string name, bool isPrivate, Cancellation }, cancellationToken).ConfigureAwait(false)) .Channel; + public Task DeclineSharedInvite(string inviteId, string targetTeam = null, CancellationToken? cancellationToken = null) => + _client.Get("conversations.declineSharedInvite", new Args + { + { "invite_id", inviteId }, + { "target_team", targetTeam } + }, cancellationToken); + public Task History(string channelId, string latestTs = null, string oldestTs = null, bool inclusive = false, int limit = 100, string cursor = null, CancellationToken? cancellationToken = null) => _client.Get("conversations.history", new Args { @@ -272,6 +349,15 @@ public async Task Invite(string channelId, IEnumerable use }, cancellationToken).ConfigureAwait(false)) .Channel; + public Task InviteShared(string channelId, IEnumerable emails, IEnumerable userIds, bool externalLimited = true, CancellationToken? cancellationToken = null) => + _client.Get("conversations.inviteShared", new Args() + { + { "channel", channelId }, + { "emails", emails }, + { "user_ids", userIds }, + { "external_limited", externalLimited } + }, cancellationToken); + public Task Join(string channelId, CancellationToken? cancellationToken = null) => _client.Post("conversations.join", new Args { { "channel", channelId } }, cancellationToken); @@ -295,6 +381,14 @@ public Task List(bool excludeArchived = false, int lim { "team_id", teamId } }, cancellationToken); + public Task ListConnectInvites(int count = 100, string cursor = null, string teamId = null, CancellationToken? cancellationToken = null) => + _client.Post("conversations.listConnectInvites", new Args + { + { "count", count }, + { "cursor", cursor }, + { "team_id", teamId } + }, cancellationToken); + public Task Mark(string channelId, string messageTs, CancellationToken? cancellationToken = null) => _client.Post("conversations.mark", new Args { diff --git a/SlackNet/WebApi/Responses/AcceptSharedInviteResponse.cs b/SlackNet/WebApi/Responses/AcceptSharedInviteResponse.cs new file mode 100644 index 0000000..9bedd33 --- /dev/null +++ b/SlackNet/WebApi/Responses/AcceptSharedInviteResponse.cs @@ -0,0 +1,9 @@ +namespace SlackNet.WebApi +{ + public class AcceptSharedInviteResponse + { + public bool ImplicitApproval { get; set; } + public string ChannelId { get; set; } + public string InviteId { get; set; } + } +} \ No newline at end of file diff --git a/SlackNet/WebApi/Responses/ConnectInvitesListResponse.cs b/SlackNet/WebApi/Responses/ConnectInvitesListResponse.cs new file mode 100644 index 0000000..24bfbf6 --- /dev/null +++ b/SlackNet/WebApi/Responses/ConnectInvitesListResponse.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; + +namespace SlackNet.WebApi +{ + public class ConnectInvitesListResponse + { + public IList Invites { get; set; } + public ResponseMetadata ResponseMetadata { get; set; } = new(); + } + + public class PendingInvite + { + public string Direction { get; set; } + public string Status { get; set; } + public int DateLastUpdated { get; set; } + public string InviteType { get; set; } + public Invite Invite { get; set; } + public InviteChannel Channel { get; set; } + public IList Acceptances { get; set; } = new List(); + } + + public class InviteAcceptance + { + public string ApprovalStatus { get; set; } + public int DateAccepted { get; set; } + public int DateInvalid { get; set; } + public int DateLastUpdated { get; set; } + public ConnectedTeam AcceptingTeam { get; set; } + public User AcceptingUser { get; set; } + public IList Reviews { get; set; } = new List(); + } + + public class InviteReview + { + public string Type { get; set; } + public int DateReview { get; set; } + public ConnectedTeam ReviewingTeam { get; set; } + } +} \ No newline at end of file diff --git a/SlackNet/WebApi/Responses/InviteSharedResponse.cs b/SlackNet/WebApi/Responses/InviteSharedResponse.cs new file mode 100644 index 0000000..ba9b2c1 --- /dev/null +++ b/SlackNet/WebApi/Responses/InviteSharedResponse.cs @@ -0,0 +1,10 @@ +namespace SlackNet.WebApi +{ + public class InviteSharedResponse + { + public string InviteId { get; set; } + public bool IsLegacySharedChannel { get; set; } + public string ConfCode { get; set; } + public string Url { get; set; } + } +} \ No newline at end of file