diff --git a/lib/stream-chat/channel.rb b/lib/stream-chat/channel.rb index f910695..ed91ed7 100644 --- a/lib/stream-chat/channel.rb +++ b/lib/stream-chat/channel.rb @@ -360,6 +360,41 @@ def delete_image(url) @client.delete("#{self.url}/image", params: { url: url }) end + # Creates or updates a draft message for this channel. + # + # @param [StringKeyHash] message The draft message content + # @param [String] user_id The ID of the user creating/updating the draft + # @return [StreamChat::StreamResponse] + sig { params(message: StringKeyHash, user_id: String).returns(StreamChat::StreamResponse) } + def create_draft(message, user_id) + payload = { message: add_user_id(message, user_id) } + @client.post("#{url}/draft", data: payload) + end + + # Deletes a draft message for this channel. + # + # @param [String] user_id The ID of the user deleting the draft + # @param [String] parent_id Optional parent message ID for thread drafts + # @return [StreamChat::StreamResponse] + sig { params(user_id: String, parent_id: T.nilable(String)).returns(StreamChat::StreamResponse) } + def delete_draft(user_id, parent_id: nil) + params = { user_id: user_id } + params[:parent_id] = parent_id if parent_id + @client.delete("#{url}/draft", params: params) + end + + # Gets a draft message for this channel. + # + # @param [String] user_id The ID of the user getting the draft + # @param [String] parent_id Optional parent message ID for thread drafts + # @return [StreamChat::StreamResponse] + sig { params(user_id: String, parent_id: T.nilable(String)).returns(StreamChat::StreamResponse) } + def get_draft(user_id, parent_id: nil) + params = { user_id: user_id } + params[:parent_id] = parent_id if parent_id + @client.get("#{url}/draft", params: params) + end + private sig { params(payload: StringKeyHash, user_id: String).returns(StringKeyHash) } diff --git a/lib/stream-chat/client.rb b/lib/stream-chat/client.rb index 2c0e13f..00fa892 100644 --- a/lib/stream-chat/client.rb +++ b/lib/stream-chat/client.rb @@ -783,6 +783,22 @@ def create_command(command) post('commands', data: command) end + # Queries draft messages for the current user. + # + # @param [String] user_id The ID of the user to query drafts for + # @param [StringKeyHash] filter Optional filter conditions for the query + # @param [Array] sort Optional sort parameters + # @param [Hash] options Additional query options + # @return [StreamChat::StreamResponse] + sig { params(user_id: String, filter: T.nilable(StringKeyHash), sort: T.nilable(T::Array[StringKeyHash]), options: T.untyped).returns(StreamChat::StreamResponse) } + def query_drafts(user_id, filter: nil, sort: nil, **options) + data = { user_id: user_id } + data['filter'] = filter if filter + data['sort'] = sort if sort + data.merge!(options) if options + post('drafts/query', data: data) + end + # Gets a comamnd. sig { params(name: String).returns(StreamChat::StreamResponse) } def get_command(name) diff --git a/spec/channel_spec.rb b/spec/channel_spec.rb index e5873c6..0962463 100644 --- a/spec/channel_spec.rb +++ b/spec/channel_spec.rb @@ -430,4 +430,65 @@ def loop_times(times) # Verify the custom field was unset expect(updated_msg['message']).not_to include 'custom_field' end + + it 'can create draft message' do + draft_message = { 'text' => 'This is a draft message' } + response = @channel.create_draft(draft_message, @random_user[:id]) + + expect(response).to include 'draft' + expect(response['draft']['message']['text']).to eq 'This is a draft message' + expect(response['draft']['channel_cid']).to eq @channel.cid + end + + it 'can get draft message' do + # First create a draft + draft_message = { 'text' => 'This is a draft to retrieve' } + @channel.create_draft(draft_message, @random_user[:id]) + + # Then get the draft + response = @channel.get_draft(@random_user[:id]) + + expect(response).to include 'draft' + expect(response['draft']['message']['text']).to eq 'This is a draft to retrieve' + expect(response['draft']['channel_cid']).to eq @channel.cid + end + + it 'can delete draft message' do + # First create a draft + draft_message = { 'text' => 'This is a draft to delete' } + @channel.create_draft(draft_message, @random_user[:id]) + + # Then delete the draft + @channel.delete_draft(@random_user[:id]) + + # Verify it's deleted by trying to get it + expect { @channel.get_draft(@random_user[:id]) }.to raise_error(StreamChat::StreamAPIException) + end + + it 'can create and manage thread draft' do + # First create a parent message + msg = @channel.send_message({ 'text' => 'Parent message' }, @random_user[:id]) + parent_id = msg['message']['id'] + + # Create a draft reply + draft_reply = { 'text' => 'This is a draft reply', 'parent_id' => parent_id } + response = @channel.create_draft(draft_reply, @random_user[:id]) + + expect(response).to include 'draft' + expect(response['draft']['message']['text']).to eq 'This is a draft reply' + expect(response['draft']['parent_id']).to eq parent_id + + # Get the draft reply + response = @channel.get_draft(@random_user[:id], parent_id: parent_id) + + expect(response).to include 'draft' + expect(response['draft']['message']['text']).to eq 'This is a draft reply' + expect(response['draft']['parent_id']).to eq parent_id + + # Delete the draft reply + @channel.delete_draft(@random_user[:id], parent_id: parent_id) + + # Verify it's deleted + expect { @channel.get_draft(@random_user[:id], parent_id: parent_id) }.to raise_error(StreamChat::StreamAPIException) + end end diff --git a/spec/client_spec.rb b/spec/client_spec.rb index cd4f87b..d5b394d 100644 --- a/spec/client_spec.rb +++ b/spec/client_spec.rb @@ -782,6 +782,51 @@ def loop_times(times) list_resp = @client.list_imports({ limit: 1 }) expect(list_resp['import_tasks'].length).to eq 1 end + + it 'can query drafts' do + # Create multiple drafts in different channels + draft1 = { 'text' => 'Draft in channel 1' } + @channel.create_draft(draft1, @random_user[:id]) + + # Create another channel with a draft + channel2 = @client.channel('messaging', data: { 'members' => @random_users.map { |u| u[:id] } }) + channel2.create(@random_user[:id]) + + draft2 = { 'text' => 'Draft in channel 2' } + channel2.create_draft(draft2, @random_user[:id]) + + # Sort by created_at + sort = [{ 'field' => 'created_at', 'direction' => 1 }] + response = @client.query_drafts(@random_user[:id], sort: sort) + expect(response['drafts']).not_to be_empty + expect(response['drafts'].length).to eq(2) + expect(response['drafts'][0]['channel']['id']).to eq(@channel.id) + expect(response['drafts'][1]['channel']['id']).to eq(channel2.id) + + # Query for a specific channel + response = @client.query_drafts(@random_user[:id], filter: { 'channel_cid' => @channel.cid }) + expect(response['drafts']).not_to be_empty + expect(response['drafts'].length).to eq(1) + expect(response['drafts'][0]['channel']['id']).to eq(@channel.id) + + # Query all drafts for the user + response = @client.query_drafts(@random_user[:id]) + expect(response['drafts']).not_to be_empty + expect(response['drafts'].length).to eq(2) + + # Paginate + response = @client.query_drafts(@random_user[:id], sort: sort, limit: 1) + expect(response['drafts']).not_to be_empty + expect(response['drafts'].length).to eq(1) + expect(response['drafts'][0]['channel']['id']).to eq(@channel.id) + + # Cleanup + begin + channel2.delete + rescue StandardError + # Ignore errors if channel is already deleted + end + end end describe 'permissions' do