Add basic support for thread transcripts
This commit is contained in:
parent
234203dc2b
commit
0ed6343874
|
@ -56,9 +56,16 @@ module DiscourseChat::Provider::SlackProvider
|
|||
Scheduler::Defer.later "Processing slack transcript request" do
|
||||
requested_messages = nil
|
||||
first_message_ts = nil
|
||||
requested_thread_ts = nil
|
||||
|
||||
thread_url_regex = /^https:\/\/\S+\.slack\.com\/archives\/\S+\/p[0-9]{16}\?thread_ts=([0-9]{10}.[0-9]{6})\S*$/
|
||||
slack_url_regex = /^https:\/\/\S+\.slack\.com\/archives\/\S+\/p([0-9]{16})\/?$/
|
||||
if tokens.size > 1 && match = slack_url_regex.match(tokens[1])
|
||||
|
||||
if tokens.size > 2 && tokens[1] == "thread" && match = slack_url_regex.match(tokens[2])
|
||||
requested_thread_ts = match.captures[0].insert(10, '.')
|
||||
elsif tokens.size > 1 && match = thread_url_regex.match(tokens[1])
|
||||
requested_thread_ts = match.captures[0]
|
||||
elsif tokens.size > 1 && match = slack_url_regex.match(tokens[1])
|
||||
first_message_ts = match.captures[0].insert(10, '.')
|
||||
elsif tokens.size > 1
|
||||
begin
|
||||
|
@ -70,7 +77,7 @@ module DiscourseChat::Provider::SlackProvider
|
|||
|
||||
error_message = { text: I18n.t("chat_integration.provider.slack.transcript.error") }
|
||||
|
||||
return error_message unless transcript = SlackTranscript.new(channel_name: channel_name, channel_id: slack_channel_id)
|
||||
return error_message unless transcript = SlackTranscript.new(channel_name: channel_name, channel_id: slack_channel_id, requested_thread_ts: requested_thread_ts)
|
||||
return error_message unless transcript.load_user_data
|
||||
return error_message unless transcript.load_chat_history
|
||||
|
||||
|
|
|
@ -2,9 +2,10 @@ module DiscourseChat::Provider::SlackProvider
|
|||
class SlackTranscript
|
||||
attr_reader :users, :channel_id, :messages
|
||||
|
||||
def initialize(channel_name:, channel_id:)
|
||||
def initialize(channel_name:, channel_id:, requested_thread_ts: nil)
|
||||
@channel_name = channel_name
|
||||
@channel_id = channel_id
|
||||
@requested_thread_ts = requested_thread_ts
|
||||
|
||||
@first_message_index = 0
|
||||
@last_message_index = -1 # We can use negative array indicies to select the last message - fancy!
|
||||
|
@ -30,6 +31,7 @@ module DiscourseChat::Provider::SlackProvider
|
|||
|
||||
# Apply a heuristic to decide which is the first message in the current conversation
|
||||
def guess_first_message(skip_messages: 5) # Can skip the last n messages
|
||||
return true if @requested_thread_ts # Always start thread on first message
|
||||
|
||||
possible_first_messages = @messages[0..-skip_messages]
|
||||
|
||||
|
@ -121,6 +123,8 @@ module DiscourseChat::Provider::SlackProvider
|
|||
secret = DiscourseChat::Helper.save_transcript(post_content)
|
||||
link = "#{Discourse.base_url}/chat-transcript/#{secret}"
|
||||
|
||||
return { text: "<#{link}|#{I18n.t("chat_integration.provider.slack.transcript.post_to_discourse")}>" } if @requested_thread_ts
|
||||
|
||||
{
|
||||
text: "<#{link}|#{I18n.t("chat_integration.provider.slack.transcript.post_to_discourse")}>",
|
||||
attachments: [
|
||||
|
@ -201,7 +205,9 @@ module DiscourseChat::Provider::SlackProvider
|
|||
http = Net::HTTP.new("slack.com", 443)
|
||||
http.use_ssl = true
|
||||
|
||||
req = Net::HTTP::Post.new(URI('https://slack.com/api/conversations.history'))
|
||||
endpoint = @requested_thread_ts ? "replies" : "history"
|
||||
|
||||
req = Net::HTTP::Post.new(URI("https://slack.com/api/conversations.#{endpoint}"))
|
||||
|
||||
data = {
|
||||
token: SiteSetting.chat_integration_slack_access_token,
|
||||
|
@ -209,21 +215,25 @@ module DiscourseChat::Provider::SlackProvider
|
|||
limit: count
|
||||
}
|
||||
|
||||
data[:ts] = @requested_thread_ts if @requested_thread_ts
|
||||
|
||||
req.set_form_data(data)
|
||||
response = http.request(req)
|
||||
return false unless response.kind_of? Net::HTTPSuccess
|
||||
json = JSON.parse(response.body)
|
||||
return false unless json['ok']
|
||||
|
||||
raw_messages = json['messages'].reverse
|
||||
raw_messages = json['messages']
|
||||
raw_messages = raw_messages.reverse unless @requested_thread_ts
|
||||
|
||||
# Build some message objects
|
||||
@messages = []
|
||||
raw_messages.each_with_index do |message, index|
|
||||
# Only load messages
|
||||
next unless message["type"] == "message"
|
||||
# Don't load responses to threads (if ts==thread_ts then it's the thread parent)
|
||||
next if message["thread_ts"] && message["thread_ts"] != message["ts"]
|
||||
|
||||
# Don't load responses to threads unless specifically requested (if ts==thread_ts then it's the thread parent)
|
||||
next if !@requested_thread_ts && message["thread_ts"] && message["thread_ts"] != message["ts"]
|
||||
|
||||
this_message = SlackMessage.new(message, self)
|
||||
@messages << this_message
|
||||
|
|
|
@ -231,6 +231,46 @@ describe 'Slack Command Controller', type: :request do
|
|||
expect(command_stub).to have_been_requested
|
||||
end
|
||||
|
||||
it 'can select by url with thread parameter' do
|
||||
replies_stub = stub_request(:post, "https://slack.com/api/conversations.replies")
|
||||
.with(body: /1501801629\.052212/)
|
||||
.to_return(body: { ok: true, messages: messages_fixture }.to_json)
|
||||
|
||||
command_stub = stub_request(:post, "https://slack.com/commands/1234")
|
||||
.to_return(body: { ok: true }.to_json)
|
||||
|
||||
post "/chat-integration/slack/command.json", params: {
|
||||
text: "post https://sometestslack.slack.com/archives/C6029G78F/p1501201669054212?thread_ts=1501801629.052212",
|
||||
response_url: 'https://hooks.slack.com/commands/1234',
|
||||
channel_name: 'general',
|
||||
channel_id: 'C6029G78F',
|
||||
token: token
|
||||
}
|
||||
|
||||
expect(command_stub).to have_been_requested
|
||||
expect(replies_stub).to have_been_requested
|
||||
end
|
||||
|
||||
it 'can select by thread' do
|
||||
replies_stub = stub_request(:post, "https://slack.com/api/conversations.replies")
|
||||
.with(body: /1501801629\.052212/)
|
||||
.to_return(body: { ok: true, messages: messages_fixture }.to_json)
|
||||
|
||||
command_stub = stub_request(:post, "https://slack.com/commands/1234")
|
||||
.to_return(body: { ok: true }.to_json)
|
||||
|
||||
post "/chat-integration/slack/command.json", params: {
|
||||
text: "post thread https://sometestslack.slack.com/archives/C6029G78F/p1501801629052212",
|
||||
response_url: 'https://hooks.slack.com/commands/1234',
|
||||
channel_name: 'general',
|
||||
channel_id: 'C6029G78F',
|
||||
token: token
|
||||
}
|
||||
|
||||
expect(command_stub).to have_been_requested
|
||||
expect(replies_stub).to have_been_requested
|
||||
end
|
||||
|
||||
it 'can select by count' do
|
||||
command_stub = stub_request(:post, "https://slack.com/commands/1234")
|
||||
.with(body: /1501801629\.052212/)
|
||||
|
|
|
@ -127,6 +127,26 @@ RSpec.describe DiscourseChat::Provider::SlackProvider::SlackTranscript do
|
|||
end
|
||||
end
|
||||
|
||||
context 'with thread_ts specified' do
|
||||
let(:thread_transcript) { described_class.new(channel_name: "#general", channel_id: "G1234", requested_thread_ts: "1501801629.052212") }
|
||||
|
||||
before do
|
||||
stub_request(:post, "https://slack.com/api/conversations.replies")
|
||||
.with(body: hash_including(token: "abcde", channel: 'G1234', ts: "1501801629.052212"))
|
||||
.to_return(status: 200, body: { ok: true, messages: messages_fixture }.to_json)
|
||||
thread_transcript.load_chat_history
|
||||
end
|
||||
|
||||
it 'includes messages in a thread' do
|
||||
expect(thread_transcript.messages.length).to eq(7)
|
||||
end
|
||||
|
||||
it 'loads in chronological order' do # replies API presents messages in actual chronological order
|
||||
expect(thread_transcript.messages.first.ts).to eq('1501801665.062694')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'with loaded messages' do
|
||||
before do
|
||||
stub_request(:post, "https://slack.com/api/conversations.history")
|
||||
|
|
Loading…
Reference in New Issue