【LINEWORKS】特定ルームにメッセージを送る方法（API 2.0対応のRuby版）

# ゴール

Rubyのコードから実行すると、LINEWORKSに登録されたボットが、指定されたルームに任意のメッセージを送ることができます。
![スクリーンショット 2022-12-25 0.44.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524261/ef04c309-455a-f148-d6a0-66ab010dbbe0.png)

# メッセージの送信 - トークルーム指定
LINEWORKS Developersで調べると、以下のAPIを呼び出す必要があるようです。
https://developers.worksmobile.com/jp/reference/bot-channel-message-send?lang=ja
![image (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524261/a58a2fcb-88a4-af9b-3bb9-46cf2148166a.png)
具体的なHTTPリクエストは以下の通りです。
![image (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524261/d21e7416-b7e9-9ff7-9f64-89ddbf23a1ec.png)
それぞれのパラメータを見てみましょう
## Path Parameters
**botId**と**channelId**はLINEWORKS Developer ConsoleとLINEWORKSトークから取得できます。

## Header Parameters
**Authorization**ヘッダに**Access Token**を用いて認証する必要があります。

メッセージを送るコードは以下になります。
``` ruby
def send_message(message)
      uri = URI("https://www.worksapis.com/v1.0/bots/#{bot_id}/channels/#{channel_id}/messages")
      https = Net::HTTP.new(uri.host, uri.port)
      https.use_ssl = true
      https.verify_mode = OpenSSL::SSL::VERIFY_NONE
      request = Net::HTTP::Post.new(uri.request_uri)
      request["Content-Type"] = "application/json"
      request["Authorization"] = "Bearer #{access_token}"
      request.body = JSON.dump({
                                 "content": {
                                   "type": "text",
                                   "text": "<m userId=\"all\">\n#{message}"
                                 }
                               })

      https.request(request)
    end
``` 
### Access Token
https://developers.worksmobile.com/jp/reference/authorization-sa?lang=ja
![image (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524261/bfafa377-34c4-9f78-cf78-a1f14d9c5bad.png)
Access Tokenを取得するためにHTTP Request Bodyに[JWT](https://qiita.com/caovanbi/items/34b5256a755b156d109e)を取得する必要があります。
他のパラメータはLINEWORKS Developer Consoleのアプリリストから取得できます。
Access Tokenを取得するコードは以下になります。
``` ruby
def access_token
  uri = URI("https://auth.worksmobile.com/oauth2/v2.0/token")
  https = Net::HTTP.new(uri.host, uri.port)
  https.use_ssl = true
  https.verify_mode = OpenSSL::SSL::VERIFY_NONE
  request = Net::HTTP::Post.new(uri.request_uri)
  request["Content-Type"] = "application/x-www-form-urlencoded"
  request.set_form_data(
    assertion: json_web_token,
    grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
    client_id: client_id,
    client_secret: client_secret,
    scope: "bot"
  )
  response = https.request(request)
  JSON.parse(response.body)["access_token"]
end
```
### JWTの取得
https://developers.worksmobile.com/jp/reference/authorization-sa?lang=ja
![image (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524261/154a17e6-596b-4000-70f8-a7ec71a0af4f.png)
**Client ID**と**Service Account ID**はLINEWORKS Developer Consoleのアプリリストから取得できます。
JWTを取得するコードは以下になります。
``` ruby
    def json_web_token
      header = { alg: "RS256", typ: "JWT" }
      payload = {
        iss: client_id,
        sub: service_account_id,
        iat: Time.now.to_i,
        exp: Time.now.to_i + 3600
      }
      rsa_private = OpenSSL::PKey::RSA.new(private_key)
      JWT.encode(payload, rsa_private, "RS256", header)
    end
```

全体のコードは以下になります。
``` ruby
# frozen_string_literal: true

module LineWorks
	class LineWorks
	  require "json"
	  require "net/http"
	  require "openssl"
	  require "uri"
	  require "jwt"

	  attr_reader :bot_id, :channel_id, :client_id, :client_secret, :service_account_id, :private_key

	  def initialize(bot_id, channel_id, client_id, client_secret, service_account_id, private_key)
		@bot_id = bot_id
		@channel_id = channel_id
		@client_id = client_id
		@client_secret = client_secret
		@service_account_id = service_account_id
		@private_key = private_key
	  end

	  def json_web_token
		header = { alg: "RS256", typ: "JWT" }
		payload = {
		  iss: client_id,
		  sub: service_account_id,
		  iat: Time.now.to_i,
		  exp: Time.now.to_i + 3600
		}
		rsa_private = OpenSSL::PKey::RSA.new(private_key)
		JWT.encode(payload, rsa_private, "RS256", header)
	  end

	  def access_token
		uri = URI("https://auth.worksmobile.com/oauth2/v2.0/token")
		https = Net::HTTP.new(uri.host, uri.port)
		https.use_ssl = true
		https.verify_mode = OpenSSL::SSL::VERIFY_NONE
		request = Net::HTTP::Post.new(uri.request_uri)
		request["Content-Type"] = "application/x-www-form-urlencoded"
		request.set_form_data(
		  assertion: json_web_token,
		  grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
		  client_id: client_id,
		  client_secret: client_secret,
		  scope: "bot"
		)
		response = https.request(request)
		JSON.parse(response.body)["access_token"]
	  end

	  def send_message(message)
		uri = URI("https://www.worksapis.com/v1.0/bots/#{bot_id}/channels/#{channel_id}/messages")
		https = Net::HTTP.new(uri.host, uri.port)
		https.use_ssl = true
		https.verify_mode = OpenSSL::SSL::VERIFY_NONE
		request = Net::HTTP::Post.new(uri.request_uri)
		request["Content-Type"] = "application/json"
		request["Authorization"] = "Bearer #{access_token}"
		request.body = JSON.dump({
								   "content": {
									 "type": "text",
									 "text": "<m userId=\"all\">\n#{message}"
								   }
								 })

		https.request(request)
	  end
	end
  end

  lw = LineWorks::LineWorks.new("1417802", "141119074", "3nwMQle6RKUmywM0RFHy", "WYCu0VfLlp", "89wl4.serviceaccount@bambi-5", File.read("/Users/caobi/Downloads/private_20221024000243.key"))
  lw.send_message("メリクリスマス")
```
---
参照文献：
https://developers.worksmobile.com/jp/reference/introduction?lang=ja
https://jwt.io/