12/08/2018, 13:41

Sử dụng gem ChatWork

Hiện tại ChatWork đã cho phép sử dụng API của họ cho đối tượng chính là lập trình viên. Qua việc sử dụng API, một số tác vụ như: Thêm thành viên vào một danh sách các group chat Gửi tin nhắn thông báo cho các thành viên trong một group chat khi task được cập nhật ... đều có thể được tự ...

Hiện tại ChatWork đã cho phép sử dụng API của họ cho đối tượng chính là lập trình viên. Qua việc sử dụng API, một số tác vụ như:

  • Thêm thành viên vào một danh sách các group chat
  • Gửi tin nhắn thông báo cho các thành viên trong một group chat khi task được cập nhật
  • ...

đều có thể được tự động hoá, thay vì phải thực hiện một cách thủ công. Với mục đích bổ sung và mở rộng một bài viết về cách sử dụng ChatWork API trong Ruby, sau đây mình xin giới thiệu cách sử dụng gem ChatWork trong một ứng dụng Rails, để có thể tích hợp chức năng của ChatWork vào Rails một cách đơn giản và hiệu quả hơn.

  • Đầu tiên ta sẽ cần phải đăng ký sử dụng ChatWork API tại đây. Theo kinh nghiệm của mình thì yêu cầu sử dụng API sẽ được chấp nhận sau khoảng 4-5h. Sau khi đã nhận được một email thông báo, ta có thể bắt đầu sinh ra API token để sử dụng trong ứng dụng của mình.

alt

  • Sơ lược về API token: Như API documentation giải thích thì mỗi API request đều cần phải chứa một API token trong HTTP header. API token là cách để ChatWork xác thực rằng chính mình là người đã gửi yêu cầu thực thi một hành động nào đó. Dĩ nhiên là với API token thì mình chỉ có thể thực hiện những hành động mà tài khoản của mình có quyền; mình sẽ không thể gửi tin nhắn vào một group chat mà mình không là thành viên chẳng hạn.

  • Khi sử dụng gem ChatWork cũng vậy, trước khi có thể sử dụng bất kỳ một phương thức nào của gem, ta cũng đều phải gán API token đó vào ChatWork.api_key.

  • Bây giờ ta có thể cái đặt gem ChatWork:

Thêm dòng dưới vào Gemfile

gem "chatwork"

rồi chạy Bundle

$ bundle

Cách dễ nhất để bắt đầu thử nghiệm với gem ChatWork là sử dụng Rails console:

$ rails c

Việc đầu tiên cần làm là gán API token của mình cho biến ChatWork.api_key:

irb(main):001:0> ChatWork.api_key = "YOUR_API_TOKEN"
=> "YOUR_API_TOKEN"
  • Chú ý: ChatWork.api_key mặc định nhận giá trị nil, nhưng nếu tồn tại một biến môi trường (environment variable) với tên CHATWORK_API_TOKEN thì giá trị của biến ấy sẽ được gán luôn cho ChatWork.api_key khi chạy Rails console. Trích đoạn code của gem:
def api_key
  @api_key || ENV['CHATWORK_API_TOKEN']
end

GET thông tin cá nhân

irb(main):002:0> ChatWork::Me.get
=> {"account_id"=>1700484, "room_id"=>43643696, "name"=>"Tran Trung Hieu", "chatwork_id"=>"framgiavn_hieutt", "organization_id"=>829296, "organization_name"=>"Framgia Vietnam", "department"=>"Education", "title"=>"Intern Ruby", "url"=>"", "introduction"=>"", "mail"=>"kagoromo@gmail.com / tran.trung.hieu@framgia.com", "tel_organization"=>"", "tel_extension"=>"", "tel_mobile"=>"01696441994", "skype"=>"hieuhedspik57a", "facebook"=>"HieuTT.5246", "twitter"=>"", "avatar_image_url"=>"https://tky-chat-work-appdata.s3.amazonaws.com/avatar/948/948256.rsz.jpg"}
irb(main):003:0>

Có thể thấy kết quả trả về của #get là một hash chứa các thông tin cá nhân của mình. Đáng lưu ý nhất là khoá account_id vì đây là một thông tin bị ẩn khi ta sử dụng ChatWork. Profile, Personal Settings, Admin Settings... không hề hiển thị account_id; cách duy nhất mà mình biết để có thể thấy được account_id của một người là quote lại một tin nhắn có To đến người đó.

alt

Cũng cần nói thêm là room_id ở trên là id của một group chat đặc biệt có tên là My Chat (Nói là đặc biệt vì My Chat được tự động tạo ra khi ta tạo tài khoản và không cho phép ta thêm thành viên khác vào). Đúng vậy, khi mình mở My Chat lên và nhìn thấy URL có dạng như thế này https://www.chatwork.com/#!rid43643696 thì số đằng sau rid chính là room_id của My Chat, chứ không phải là account_id như mình đã từng nghĩ.

GET thông tin group chat

irb(main):003:0> ChatWork::Room.get.first
=> {"room_id"=>5126753, "name"=>"FramgiaAll", "type"=>"group", "role"=>"member", "sticky"=>true, "unread_num"=>43, "mention_num"=>0, "mytask_num"=>0, "message_num"=>67101, "file_num"=>358, "task_num"=>12, "icon_path"=>"https://tky-chat-work-appdata.s3.amazonaws.com/icon/38/38686.rsz.png", "last_update_time"=>1469888294}
irb(main):004:0>

Có lẽ không cần giải thích nhiều ngoài một chú ý duy nhất là nếu chạy ChatWork::Room.get thì kết quả trả về sẽ là một mảng các hash kết quả.

GET thông tin thành viên

irb(main):006:0> ChatWork::Member.get(room_id: "5126753").find {|member| member["name"] == "Tran Trung Hieu"}
=> {"account_id"=>1700484, "role"=>"member", "name"=>"Tran Trung Hieu", "chatwork_id"=>"framgiavn_hieutt", "organization_id"=>829296, "organization_name"=>"Framgia Vietnam", "department"=>"Education", "avatar_image_url"=>"https://tky-chat-work-appdata.s3.amazonaws.com/avatar/948/948256.rsz.jpg"}
irb(main):007:0>

ChatWork::Member.get trả lại một mảng các hash thông tin thành viên của group chat có id là 5126753. Ta gọi #find trên mảng kết quả ấy để tìm thành viên có tên là "Tran Trung Hieu" và nhận được kết quả như trên. Chú ý sự khác biệt giữa kết quả khi gọi ChatWork::Me.get và ChatWork::Member.get: ChatWork::Member.get trả lại hash kết quả đã bị giảm lược đi rất nhiều thông tin, ví dụ như địa chỉ mail và số điện thoại.

POST tin nhắn mới vào một group chat

irb(main):008:0> ChatWork::Message.create room_id: "43643696", body: "New message sent with ChatWork API!"
=> {"message_id"=>1359692676}
irb(main):009:0>

alt

Để gửi một tin nhắn mới chỉ cần 2 thông tin là room_id của group chat và body là nội dung tin nhắn. Khá đơn giản đúng không?

Vậy nếu muốn To ai đó thì sao?

irb(main):009:0> ChatWork::Message.create room_id: "43643696", body: "[To:1700484] Tran Trung Hieu
New message sent with a To tag!"
=> {"message_id"=>1359693415}
irb(main):010:0>

alt

Một method to all đơn giản

irb(main):032:0> def to_all room_id
irb(main):033:1>   body = ""
irb(main):034:1>   ChatWork::Member.get(room_id: room_id).each do |member|
irb(main):035:2*     body += "[To:#{member["account_id"]}] "
irb(main):036:2>   end
irb(main):037:1>   body
irb(main):038:1> end
=> :to_all
irb(main):039:0> to_all 5126753
=> "[To:443536] [To:452830] [To:486624] [To:525092] [To:538118] ... "

Trả về một string chứa các thẻ To cho mọi thành viên của một group chat, tương tự như chức năng @all của Chat++

PUT thay đổi danh sách thành viên của một group chat

Hiện tại gem ChatWork chưa định nghĩa #create cho ChatWork::Member nên ta sẽ cần phải tự chỉnh sửa một chút như sau:

irb(main):013:0> module ChatWork
irb(main):014:1>   class Member < Entity
irb(main):015:2>     install_class_operations :create, :get
irb(main):016:2>
irb(main):017:2*     def self.path
irb(main):018:3>       "/rooms/%d/members"
irb(main):019:3>     end
irb(main):020:2>   end
irb(main):021:1> end
=> :path
irb(main):022:0>
irb(main):023:0> ChatWork::Member.create room_id: 54413631, members_admin_ids: "1700484", members_member_ids: "1562784", method: :put
=> {"admin"=>[1700484], "member"=>[1562784], "readonly"=>[]}
irb(main):024:0>

Kết quả sau khi thực hiện ChatWork::Member.create: group chat với id là 54413631 có 2 thành viên, một thành viên có quyền admin với id 1700484 và một thành viên bình thường với id 1562784. Chú ý method: :put và phải nhập ít nhất một thành viên vào danh sách có quyền admin.

Tạo mới một Rails app

$ rails new try-chatwork
Gemfile

gem "chatwork"
$ bundle

Tạo và sửa một số file như sau:

config/routes.rb

root to: "chatwork#index"
post "/chatwork", to: "chatwork#send_message"
app/controllers/chatwork_controller.rb

class ChatworkController < ApplicationController
  def index
  end

  def send_message
    ChatWork.api_key = params[:chatwork_api_token]
    name = ChatWork::Me.get["name"]
    account_id = ChatWork::Me.get["account_id"]
    room_id = ChatWork::Me.get["room_id"]
    message_body = "[To:#{account_id}] #{name}
Well done! You have successfully sent a message using ChatWork's API!"
    ChatWork::Message.create room_id: room_id, body: message_body
    redirect_to :root
  end
end
app/views/chatwork/index.html.erb

<% link_to "Send message", {controller: "chatwork", action: "send_message"}, method: :post %>
<%= form_tag "/chatwork", method: :post do %>
  <%=label_tag "chatwork_api_token" %>
  <%=text_field_tag "chatwork_api_token"%>

  <div><%= submit_tag "Send Message" %></div>
<% end %>

Khởi động Rails server

$ rails c

truy cập vào localhost:3000 và màn hình dưới sẽ hiện lên

alt

Click Send Message sau khi đã điền API token vào khung nhập và My Chat của bạn sẽ nhận được một tin nhắn mới!

alt

Điều gì vừa mới xảy ra?

  • Ta đã định nghĩa #send_message trong ChatworkController và đó chính là method thực hiện gửi tin nhắn mới.
  • Đầu tiên, ChatWork.api_key sẽ được gán cho giá trị API token nhận được qua khung nhập trong view.
  • Sau đó, lần lượt GET một số thông tin cần thiết như name, account_id và room_id thông qua ChatWork::Me.get. Vì là ChatWork::Me nên name và account_id sẽ là tên và id tài khoản của chính mình, cũng như room_id sẽ chỉ đến My Chat.
  • Sử dụng các thông tin trên để tạo nên nội dung cho tin nhắn: account_id và room_id tạo nên thẻ To.
  • Tạo tin nhắn mới cho My Chat với ChatWork::Message.create

Mở rộng hơn một chút nào!

Hãy hình dung một hệ thống làm bài thi trực tuyến. Người dùng khi tạo tài khoản sẽ được yêu cầu nhập tên hiển thị trong ChatWork của mình và join vào một group chat tương ứng với môn học mà họ muốn làm bài thi.

def send_score_to_chatwork admin
  ChatWork.api_key = admin.chatwork_api_key
  room_id = subject.chatwork_room_id
  to_account_id = ChatWork::Member.get(room_id: room_id).find {|member|
    member["name"] == user.chatwork_name}["account_id"]
  body = I18n.t "exam.chatwork_message", id: to_account_id, name: user.chatwork_name,
    score: score, total: subject.number_of_questions, subject: subject.content
  ChatWork::Message.create room_id: room_id, body: body
end

Method #send_score_to_chatwork sẽ tìm account_id của người làm bài thi trong group chat của môn học. Vì sao phải thực hiện tìm account_id thông qua name? Như mình đã nói ở trên, để lấy được account_id thì người dùng sẽ phải nhờ ai đó To mình để, hoặc lục lại một tin nhắn đã To mình nào đó để quote. Theo mình nghĩ thì yêu cầu người dùng nhập tên hiển thị sẽ bớt phiền phức hơn cho họ, mặc dù cách làm này có thể dẫn đến một số lỗi khác mình sẽ trình bày ở dưới đây.

Lỗi tiềm tàng

với API token thì mình chỉ có thể thực hiện những hành động mà tài khoản của mình có quyền

vì vậy, nếu mình thực hiện ChatWork::Member.get với room_id của một group chat nào đó mình không là thành viên thì sẽ xảy ra lỗi:

irb(main):030:0> ChatWork::Member.get room_id: 999999999
=> #<ChatWork::APIError: You don't have permission to get members in this room>
irb(main):031:0>
irb(main):032:0* ChatWork::Member.get(room_id: 999999999).class
=> ChatWork::APIError
irb(main):033:0>

Khi xảy ra lỗi, hầu hết các method của gem ChatWork đều trả về một Object thuộc class ChatWork::APIError. Kiểm tra class của kết quả trả về có thể là một cách để xử lý lỗi khi sử dụng gem ChatWork.

Ngoài ra, trong trường hợp tìm kiếm thành viên bằng name trong mảng kết quả của ChatWork::Member.get thì rất có thể xảy ra trường hợp không tìm thấy kết quả, thay vì thông tin của thành viên mà ta cần tìm thì ta sẽ nhận được nil. Cách xử lỹ cùng vẫn là kiểm tra kết quả trước khi sử dụng cho các thao tác tiếp theo.

Một chú ý quan trọng về bảo mật: Chỉ cần có API token của bạn là một người khác có thể làm mọi thứ bạn có quyền làm với tài khoản ChatWork của mình nên việc giữ kín thông tin API token của bản thân là rất quan trọng. Chính vì vậy nên việc lưu trữ API token trong CSDL sẽ không phải là một ý hay, thay vào đó chúng ta có thể lưu API token vào trong biến môi trường CHATWORK_API_TOKEN. API documentation có nói về vấn đề này và khuyến cáo sử dụng phương thức OAuth2 cho web app thay vì API token khi OAuth2 chính thức được ChatWork hỗ trợ.

Hi vọng bài viết này đã giúp cho các bạn hiểu cách sử dụng gem ChatWork. Mong nhận được đóng góp của các bạn về nội dụng cũng như cách viết của bài viết này nhé. Thân!

0