defmodule WeChat.Work.ChatRobot do
@moduledoc """
群机器人
在终端某个群组添加机器人之后,创建者可以在机器人详情页看的该机器人特有的webhookurl。
开发者可以按以下说明a向这个地址发起HTTP POST 请求,即可实现给该群组发送消息。
当前自定义机器人支持文本(text)、markdown(markdown)、图片(image)、图文(news)四种消息类型。
机器人的text/markdown类型消息支持在content中使用<@userid>扩展语法来@群成员
消息发送频率限制: 每个机器人发送的消息不能超过20条/分钟。
"""
import WeChat.Utils, only: [default_adapter: 0]
alias Tesla.Multipart
@type webhook_url :: String.t()
@typedoc "调用接口凭证, 机器人webhookurl中的key参数"
@type key :: String.t()
@typedoc """
消息类型
- `text`: 文本消息
- `image`: 图片消息
- `file`: 文件消息
- `news`: 图文消息
- `markdown`: markdown消息
- `template_card`: 模板卡片消息
"""
@type msg_type :: String.t()
@type msg :: map
@type content :: String.t()
@type opts :: Enumerable.t()
@typedoc "文件id,通过文件上传接口获取"
@type media_id :: String.t()
@typep file_path :: Path.t()
@typep filename :: String.t()
@typep file_data :: binary
@doc """
发送消息 -
[官方文档](https://developer.work.weixin.qq.com/document/path/91770#如何使用群机器人){:target="_blank"}
"""
@spec send(webhook_url, msg_type, msg) :: Tesla.Env.result()
def send(webhook_url, msg_type, msg) do
Tesla.client([Tesla.Middleware.JSON, Tesla.Middleware.Logger], default_adapter())
|> Tesla.post(webhook_url, %{"msgtype" => msg_type, msg_type => msg})
end
@doc """
发送文本消息 -
[官方文档](https://developer.work.weixin.qq.com/document/path/91770#文本类型){:target="_blank"}
"""
@spec send_text(webhook_url, content, opts) :: WeChat.response()
def send_text(webhook_url, content, opts \\ []) do
send(webhook_url, "text", Map.new(opts) |> Map.put("content", content))
end
@doc """
发送图片消息 -
[官方文档](https://developer.work.weixin.qq.com/document/path/91770#图片类型){:target="_blank"}
- `base64`: 图片内容的 `base64` 编码
- `md5`: 图片内容(base64编码前)的 `md5` 值
**注:图片(base64编码前)最大不能超过2M,支持JPG,PNG格式**
"""
@spec send_image(webhook_url, base64 :: String.t(), md5 :: String.t()) :: WeChat.response()
def send_image(webhook_url, base64, md5) do
send(webhook_url, "image", %{"base64" => base64, "md5" => md5})
end
@spec send_image(webhook_url, image_data :: binary) :: WeChat.response()
def send_image(webhook_url, image_data) do
base64 = Base.encode64(image_data)
md5 = :crypto.hash(:md5, image_data)
send_image(webhook_url, base64, md5)
end
@doc """
发送文件消息 -
[官方文档](https://developer.work.weixin.qq.com/document/path/91770#文件类型){:target="_blank"}
"""
@spec send_file(webhook_url, Material.media_id()) :: WeChat.response()
def send_file(webhook_url, media_id) do
send(webhook_url, "file", %{"media_id" => media_id})
end
@doc """
发送图文消息 -
[官方文档](https://developer.work.weixin.qq.com/document/path/91770#图文类型){:target="_blank"}
"""
@spec send_news(webhook_url, msg) :: WeChat.response()
def send_news(webhook_url, msg) do
send(webhook_url, "news", msg)
end
@doc """
发送markdown消息 -
[官方文档](https://developer.work.weixin.qq.com/document/path/91770#markdown类型){:target="_blank"}
"""
@spec send_markdown(webhook_url, content) :: WeChat.response()
def send_markdown(webhook_url, content) do
send(webhook_url, "markdown", %{"content" => content})
end
@doc """
发送模板卡片消息 -
[官方文档](https://developer.work.weixin.qq.com/document/path/91770#模板卡片类型){:target="_blank"}
"""
@spec send_template_card(webhook_url, msg) :: WeChat.response()
def send_template_card(webhook_url, msg) do
send(webhook_url, "template_card", msg)
end
@doc """
文件上传接口 -
[官方文档](https://developer.work.weixin.qq.com/document/path/91770#文件上传接口){:target="_blank"}
"""
@spec upload_file(key, file_path) :: Tesla.Env.result()
def upload_file(key, file_path) do
Multipart.new()
|> Multipart.add_file(file_path, name: "media", detect_content_type: true)
|> _upload_file(key)
end
@doc """
文件上传接口 -
[官方文档](https://developer.work.weixin.qq.com/document/path/91770#文件上传接口){:target="_blank"}
"""
@spec upload_file(key, filename, file_data) :: Tesla.Env.result()
def upload_file(key, filename, file_data) do
Multipart.new()
|> Multipart.add_file_content(file_data, filename, name: "media", detect_content_type: true)
|> _upload_file(key)
end
defp _upload_file(multipart, key) do
Tesla.client([Tesla.Middleware.DecodeJson, Tesla.Middleware.Logger], default_adapter())
|> Tesla.post("https://qyapi.weixin.qq.com/cgi-bin/webhook/upload_media", multipart,
query: [key: key, type: "file"]
)
end
end