<commit_before>require 'rails_helper'

RSpec.describe DiscourseChat::Provider::SlackProvider::SlackTranscript do

  let(:messages_fixture) {
    [
      {
        "type": "message",
        "user": "U6JSSESES",
        "text": "Yeah, should make posting slack transcripts much easier",
        "ts": "1501801665.062694"
      },
      {
          "type": "message",
          "user": "U5Z773QLS",
          "text": "Oooh a new discourse plugin???",
          "ts": "1501801643.056375"
      },
      {
          "type": "message",
          "user": "U6E2W7R8C",
          "text": "Which one?",
          "ts": "1501801634.053761"
      },
      {
          "type": "message",
          "user": "U6JSSESES",
          "text": "So, who's interested in the new <https://meta.discourse.org|discourse plugin>?",
          "ts": "1501801629.052212"
      },
      {
            "text": "",
            "username": "Test Community",
            "bot_id": "B6C6JNUDN",
            "attachments": [
                {
                    "author_name": "@david",
                    "fallback": "Discourse can now be integrated with Mattermost! - @david",
                    "text": "Hey <http://localhost/groups/team|@team>, what do you think about this?",
                    "title": "Discourse can now be integrated with Mattermost! [Announcements] ",
                    "id": 1,
                    "title_link": "http://localhost:3000/t/discourse-can-now-be-integrated-with-mattermost/51/4",
                    "color": "283890",
                    "mrkdwn_in": [
                        "text"
                    ]
                }
            ],
            "type": "message",
            "subtype": "bot_message",
            "ts": "1501615820.949638"
        },
        {
            "type": "message",
            "user": "U5Z773QLS",
            "text": "Let’s try some *bold text*",
            "ts": "1501093331.439776"
        },

    ]
  }

  let(:transcript) { described_class.new(channel_name: "#general", channel_id: "G1234") }
  before do
    SiteSetting.chat_integration_slack_access_token = "abcde"
  end

  describe 'loading users' do
    it 'loads users correctly' do
      stub_request(:post, "https://slack.com/api/users.list")
        .with(body: { token: "abcde" })
        .to_return(status: 200, body: { ok: true, members: [{ id: "U5Z773QLS", name: "awesomeguy", profile: { image_24: "https://example.com/avatar" } }] }.to_json)

      expect(transcript.load_user_data).to be_truthy
    end

    it 'handles failed connection' do
      stub_request(:post, "https://slack.com/api/users.list")
        .to_return(status: 500, body: '')

      expect(transcript.load_user_data).to be_falsey
    end

    it 'handles slack failure' do
      stub_request(:post, "https://slack.com/api/users.list")
        .to_return(status: 200, body: { ok: false }.to_json)

      expect(transcript.load_user_data).to be_falsey
    end
  end

  context 'with loaded users' do
    before do
      stub_request(:post, "https://slack.com/api/users.list")
        .to_return(status: 200, body: { ok: true, members: [{ id: "U5Z773QLS", name: "awesomeguy", profile: { image_24: "https://example.com/avatar" } }] }.to_json)
      transcript.load_user_data
    end

    describe 'loading history' do
      it 'loads messages correctly' do
        stub_request(:post, "https://slack.com/api/channels.history")
          .with(body: hash_including(token: "abcde", channel: 'G1234'))
          .to_return(status: 200, body: { ok: true, messages: messages_fixture }.to_json)

          expect(transcript.load_chat_history).to be_truthy
      end

      it 'handles failed connection' do
        stub_request(:post, "https://slack.com/api/channels.history")
          .to_return(status: 500, body: {}.to_json)

          expect(transcript.load_chat_history).to be_falsey
      end

      it 'handles slack failure' do
        stub_request(:post, "https://slack.com/api/channels.history")
          .to_return(status: 200, body: { ok: false }.to_json)

          expect(transcript.load_chat_history).to be_falsey
      end
    end

    context 'with loaded messages' do
      before do
        stub_request(:post, "https://slack.com/api/channels.history")
          .with(body: hash_including(token: "abcde", channel: 'G1234'))
          .to_return(status: 200, body: { ok: true, messages: messages_fixture }.to_json)
        transcript.load_chat_history
      end

      it 'loads in chronological order' do # API presents in reverse chronological
        expect(transcript.messages.first.ts).to eq('1501093331.439776')
      end

      it 'handles bold text' do
        expect(transcript.messages.first.text).to eq("Let’s try some **bold text**")
      end

      it 'handles links' do
        expect(transcript.messages[2].text).to eq("So, who's interested in the new [discourse plugin](https://meta.discourse.org)?")
      end

      it 'includes attachments' do
        expect(transcript.messages[1].attachments.first).to eq("Discourse can now be integrated with Mattermost! - @david")
      end

      it 'can generate URL' do
        expect(transcript.messages.first.url).to eq("https://slack.com/archives/G1234/p1501093331439776")
      end

      it 'gives correct first and last messages' do
        expect(transcript.first_message_number).to eq(0)
        expect(transcript.last_message_number).to eq(transcript.messages.length - 1)

        expect(transcript.first_message.ts).to eq('1501093331.439776')
        expect(transcript.last_message.ts).to eq('1501801665.062694')
      end

      it 'can change first and last messages by index' do
        expect(transcript.set_first_message_by_index(999)).to be_falsey
        expect(transcript.set_first_message_by_index(1)).to be_truthy

        expect(transcript.set_last_message_by_index(-2)).to be_truthy

        expect(transcript.first_message.ts).to eq('1501615820.949638')
        expect(transcript.last_message.ts).to eq('1501801643.056375')
      end

      it 'can change first and last messages by ts' do
        expect(transcript.set_first_message_by_ts('blah')).to be_falsey
        expect(transcript.set_first_message_by_ts('1501615820.949638')).to be_truthy

        expect(transcript.set_last_message_by_ts('1501801629.052212')).to be_truthy

        expect(transcript.first_message_number).to eq(1)
        expect(transcript.last_message_number).to eq(2)
      end

      it 'can guess the first message' do
        expect(transcript.guess_first_message(skip_messages:1)).to eq(true)
        expect(transcript.first_message.ts).to eq('1501801629.052212')
      end

      it 'handles usernames correctly' do
        expect(transcript.first_message.username).to eq('awesomeguy') # Normal user
        expect(transcript.messages[2].username).to eq(nil) # Unknown normal user
        expect(transcript.messages[1].username).to eq('Test Community') # Bot user
      end

      it 'handles avatars correctly' do
        expect(transcript.first_message.avatar).to eq("https://example.com/avatar") # Normal user
        expect(transcript.messages[1].avatar).to eq(nil) # Bot user
      end

      it 'creates a transcript correctly' do
        transcript.set_last_message_by_index(1)

        text = transcript.build_transcript

        # Rubocop doesn't like this, but we really do need trailing whitespace in the string<commit_msg>Correct rubocop offence<commit_after>require 'rails_helper'

RSpec.describe DiscourseChat::Provider::SlackProvider::SlackTranscript do

  let(:messages_fixture) {
    [
      {
        "type": "message",
        "user": "U6JSSESES",
        "text": "Yeah, should make posting slack transcripts much easier",
        "ts": "1501801665.062694"
      },
      {
          "type": "message",
          "user": "U5Z773QLS",
          "text": "Oooh a new discourse plugin???",
          "ts": "1501801643.056375"
      },
      {
          "type": "message",
          "user": "U6E2W7R8C",
          "text": "Which one?",
          "ts": "1501801634.053761"
      },
      {
          "type": "message",
          "user": "U6JSSESES",
          "text": "So, who's interested in the new <https://meta.discourse.org|discourse plugin>?",
          "ts": "1501801629.052212"
      },
      {
            "text": "",
            "username": "Test Community",
            "bot_id": "B6C6JNUDN",
            "attachments": [
                {
                    "author_name": "@david",
                    "fallback": "Discourse can now be integrated with Mattermost! - @david",
                    "text": "Hey <http://localhost/groups/team|@team>, what do you think about this?",
                    "title": "Discourse can now be integrated with Mattermost! [Announcements] ",
                    "id": 1,
                    "title_link": "http://localhost:3000/t/discourse-can-now-be-integrated-with-mattermost/51/4",
                    "color": "283890",
                    "mrkdwn_in": [
                        "text"
                    ]
                }
            ],
            "type": "message",
            "subtype": "bot_message",
            "ts": "1501615820.949638"
        },
        {
            "type": "message",
            "user": "U5Z773QLS",
            "text": "Let’s try some *bold text*",
            "ts": "1501093331.439776"
        },

    ]
  }

  let(:transcript) { described_class.new(channel_name: "#general", channel_id: "G1234") }
  before do
    SiteSetting.chat_integration_slack_access_token = "abcde"
  end

  describe 'loading users' do
    it 'loads users correctly' do
      stub_request(:post, "https://slack.com/api/users.list")
        .with(body: { token: "abcde" })
        .to_return(status: 200, body: { ok: true, members: [{ id: "U5Z773QLS", name: "awesomeguy", profile: { image_24: "https://example.com/avatar" } }] }.to_json)

      expect(transcript.load_user_data).to be_truthy
    end

    it 'handles failed connection' do
      stub_request(:post, "https://slack.com/api/users.list")
        .to_return(status: 500, body: '')

      expect(transcript.load_user_data).to be_falsey
    end

    it 'handles slack failure' do
      stub_request(:post, "https://slack.com/api/users.list")
        .to_return(status: 200, body: { ok: false }.to_json)

      expect(transcript.load_user_data).to be_falsey
    end
  end

  context 'with loaded users' do
    before do
      stub_request(:post, "https://slack.com/api/users.list")
        .to_return(status: 200, body: { ok: true, members: [{ id: "U5Z773QLS", name: "awesomeguy", profile: { image_24: "https://example.com/avatar" } }] }.to_json)
      transcript.load_user_data
    end

    describe 'loading history' do
      it 'loads messages correctly' do
        stub_request(:post, "https://slack.com/api/channels.history")
          .with(body: hash_including(token: "abcde", channel: 'G1234'))
          .to_return(status: 200, body: { ok: true, messages: messages_fixture }.to_json)

          expect(transcript.load_chat_history).to be_truthy
      end

      it 'handles failed connection' do
        stub_request(:post, "https://slack.com/api/channels.history")
          .to_return(status: 500, body: {}.to_json)

          expect(transcript.load_chat_history).to be_falsey
      end

      it 'handles slack failure' do
        stub_request(:post, "https://slack.com/api/channels.history")
          .to_return(status: 200, body: { ok: false }.to_json)

          expect(transcript.load_chat_history).to be_falsey
      end
    end

    context 'with loaded messages' do
      before do
        stub_request(:post, "https://slack.com/api/channels.history")
          .with(body: hash_including(token: "abcde", channel: 'G1234'))
          .to_return(status: 200, body: { ok: true, messages: messages_fixture }.to_json)
        transcript.load_chat_history
      end

      it 'loads in chronological order' do # API presents in reverse chronological
        expect(transcript.messages.first.ts).to eq('1501093331.439776')
      end

      it 'handles bold text' do
        expect(transcript.messages.first.text).to eq("Let’s try some **bold text**")
      end

      it 'handles links' do
        expect(transcript.messages[2].text).to eq("So, who's interested in the new [discourse plugin](https://meta.discourse.org)?")
      end

      it 'includes attachments' do
        expect(transcript.messages[1].attachments.first).to eq("Discourse can now be integrated with Mattermost! - @david")
      end

      it 'can generate URL' do
        expect(transcript.messages.first.url).to eq("https://slack.com/archives/G1234/p1501093331439776")
      end

      it 'gives correct first and last messages' do
        expect(transcript.first_message_number).to eq(0)
        expect(transcript.last_message_number).to eq(transcript.messages.length - 1)

        expect(transcript.first_message.ts).to eq('1501093331.439776')
        expect(transcript.last_message.ts).to eq('1501801665.062694')
      end

      it 'can change first and last messages by index' do
        expect(transcript.set_first_message_by_index(999)).to be_falsey
        expect(transcript.set_first_message_by_index(1)).to be_truthy

        expect(transcript.set_last_message_by_index(-2)).to be_truthy

        expect(transcript.first_message.ts).to eq('1501615820.949638')
        expect(transcript.last_message.ts).to eq('1501801643.056375')
      end

      it 'can change first and last messages by ts' do
        expect(transcript.set_first_message_by_ts('blah')).to be_falsey
        expect(transcript.set_first_message_by_ts('1501615820.949638')).to be_truthy

        expect(transcript.set_last_message_by_ts('1501801629.052212')).to be_truthy

        expect(transcript.first_message_number).to eq(1)
        expect(transcript.last_message_number).to eq(2)
      end

      it 'can guess the first message' do
        expect(transcript.guess_first_message(skip_messages: 1)).to eq(true)
        expect(transcript.first_message.ts).to eq('1501801629.052212')
      end

      it 'handles usernames correctly' do
        expect(transcript.first_message.username).to eq('awesomeguy') # Normal user
        expect(transcript.messages[2].username).to eq(nil) # Unknown normal user
        expect(transcript.messages[1].username).to eq('Test Community') # Bot user
      end

      it 'handles avatars correctly' do
        expect(transcript.first_message.avatar).to eq("https://example.com/avatar") # Normal user
        expect(transcript.messages[1].avatar).to eq(nil) # Bot user
      end

      it 'creates a transcript correctly' do
        transcript.set_last_message_by_index(1)

        text = transcript.build_transcript

        # Rubocop doesn't like this, but we really do need trailing whitespace in the string
{'fraction_non_alphanumeric': 0.12661306668468347, 'fraction_numerical': 0.04567258968988582, 'mean_word_length': 2.4959848842701935, 'pattern_counts': {'":': 70, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 28, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2275524', 'n_tokens_mistral': 5158, 'n_tokens_neox': 4572, 'n_words': 978}