Commit 7494c7379cc67f48fa44fb6f41aa3956f75cfe5e
Exists in
master
Merge pull request #4 from lanrion/send-message
Send message
Showing
15 changed files
with
393 additions
and
70 deletions
Show diff stats
.gitignore
README.md
... | ... | @@ -78,4 +78,23 @@ group_client.oauth.authorize_url("http://2458023e.ngrok.com", "state") |
78 | 78 | group_client.oauth.get_user_info("code", "app_id") |
79 | 79 | ``` |
80 | 80 | |
81 | +## 发送消息 | |
82 | + | |
83 | +```ruby | |
84 | + # params: (users, parties, tags, agent_id, content, safe=0) | |
85 | + # users, parties, tags 如果是多个用户,传数组,如果是全部,则直接传 "@all" | |
86 | + group_client.message.send_text("@all", "@all", "@all", app_id, text_message) | |
87 | +``` | |
88 | +**其他发送消息方法请查看 api/message.rb** | |
89 | + | |
90 | +## 上传多媒体文件 | |
91 | +```ruby | |
92 | +# params: media, media_type | |
93 | +group_client.media.upload(image_jpg_file, "image") | |
94 | + | |
95 | +# 获取下载链接 | |
96 | +# 返回一个URL,请开发者自行使用此url下载 | |
97 | +group_client.media.get_media_by_id(media_id) | |
98 | +``` | |
99 | + | |
81 | 100 | ... | ... |
lib/qy_wechat_api.rb
1 | 1 | # encoding: utf-8 |
2 | 2 | |
3 | 3 | require "rest-client" |
4 | + | |
5 | +require "carrierwave" | |
6 | +require "qy_wechat_api/carrierwave/qy_wechat_api_uploader" | |
7 | + | |
4 | 8 | require 'yajl/json_gem' |
5 | 9 | |
6 | 10 | require "qy_wechat_api/client" |
... | ... | @@ -13,29 +17,15 @@ module QyWechatApi |
13 | 17 | OK_CODE = 0.freeze |
14 | 18 | |
15 | 19 | class << self |
16 | - # for test | |
17 | - def corpid | |
18 | - "wxb9ce1d023fe6eb69" | |
19 | - end | |
20 | - | |
21 | - # for test | |
22 | - def corpsecret | |
23 | - "UOofFIah4PVLmkG8xMH3lpDxj6NTnQSKMrFt-HubiPB4kjB09EmTVcUjgNeermps" | |
24 | - end | |
25 | 20 | |
26 | 21 | def http_get_without_token(url, params={}) |
27 | 22 | get_api_url = ENDPOINT_URL + url |
28 | - puts get_api_url | |
29 | - puts params | |
30 | 23 | load_json(RestClient.get(get_api_url, params: params)) |
31 | 24 | end |
32 | 25 | |
33 | 26 | def http_post_without_token(url, payload={}, params={}) |
34 | 27 | post_api_url = ENDPOINT_URL + url |
35 | - puts post_api_url | |
36 | - puts payload | |
37 | - puts params | |
38 | - payload = JSON.dump(payload) | |
28 | + payload = JSON.dump(payload) if !payload[:media].is_a?(File) | |
39 | 29 | load_json(RestClient.post(post_api_url, payload, params: params)) |
40 | 30 | end |
41 | 31 | ... | ... |
lib/qy_wechat_api/api/media.rb
... | ... | @@ -4,12 +4,16 @@ module QyWechatApi |
4 | 4 | module Api |
5 | 5 | class Media < Base |
6 | 6 | |
7 | - def upload | |
8 | - | |
7 | + # 媒体文件类型,分别有图片(image)、语音(voice)、视频(video),普通文件(file) | |
8 | + # media: 支持传路径或者文件实例 | |
9 | + def upload(media, media_type) | |
10 | + file = process_file(media) | |
11 | + http_post("upload", {media: file}, {type: media_type}) | |
9 | 12 | end |
10 | 13 | |
14 | + # 返回一个URL,请开发者自行使用此url下载 | |
11 | 15 | def get_media_by_id(media_id) |
12 | - | |
16 | + http_get("get", {media_id: media_id}) | |
13 | 17 | end |
14 | 18 | |
15 | 19 | private |
... | ... | @@ -18,6 +22,62 @@ module QyWechatApi |
18 | 22 | "/media" |
19 | 23 | end |
20 | 24 | |
25 | + def process_file(media) | |
26 | + return media if media.is_a?(File) && jpep?(media) | |
27 | + | |
28 | + media_url = media | |
29 | + uploader = QyWechatApiUploader.new | |
30 | + | |
31 | + if http?(media_url) # remote | |
32 | + uploader.download!(media_url.to_s) | |
33 | + else # local | |
34 | + media_file = media.is_a?(File) ? media : File.new(media_url) | |
35 | + uploader.cache!(media_file) | |
36 | + end | |
37 | + file = process_media(uploader) | |
38 | + CarrierWave.clean_cached_files! # clear last one day cache | |
39 | + file | |
40 | + end | |
41 | + | |
42 | + def process_media(uploader) | |
43 | + uploader = covert(uploader) | |
44 | + uploader.file.to_file | |
45 | + end | |
46 | + | |
47 | + # JUST ONLY FOR JPG IMAGE | |
48 | + def covert(uploader) | |
49 | + # image process | |
50 | + unless (uploader.file.content_type =~ /image/).nil? | |
51 | + if !jpep?(uploader.file) | |
52 | + require "mini_magick" | |
53 | + # covert to jpeg | |
54 | + image = MiniMagick::Image.open(uploader.path) | |
55 | + image.format("jpg") | |
56 | + uploader.cache!(File.open(image.path)) | |
57 | + image.destroy! # remove /tmp from MinMagick generate | |
58 | + end | |
59 | + end | |
60 | + uploader | |
61 | + end | |
62 | + | |
63 | + def http?(uri) | |
64 | + return false if !uri.is_a?(String) | |
65 | + uri = URI.parse(uri) | |
66 | + uri.scheme =~ /^https?$/ | |
67 | + end | |
68 | + | |
69 | + def jpep?(file) | |
70 | + content_type = if file.respond_to?(:content_type) | |
71 | + file.content_type | |
72 | + else | |
73 | + content_type(file.path) | |
74 | + end | |
75 | + !(content_type =~ /jpeg/).nil? | |
76 | + end | |
77 | + | |
78 | + def content_type(media_path) | |
79 | + MIME::Types.type_for(media_path).first.content_type | |
80 | + end | |
21 | 81 | end |
22 | 82 | end |
23 | 83 | end | ... | ... |
lib/qy_wechat_api/api/menu.rb
... | ... | @@ -3,56 +3,6 @@ module QyWechatApi |
3 | 3 | module Api |
4 | 4 | class Menu < Base |
5 | 5 | |
6 | - # for example: | |
7 | - MENU = '{ | |
8 | - "button": [ | |
9 | - { | |
10 | - "name": "扫码", | |
11 | - "sub_button": [ | |
12 | - { | |
13 | - "type": "scancode_waitmsg", | |
14 | - "name": "扫码带提示", | |
15 | - "key": "rselfmenu_0_0", | |
16 | - "sub_button": [ ] | |
17 | - }, | |
18 | - { | |
19 | - "type": "scancode_push", | |
20 | - "name": "扫码推事件", | |
21 | - "key": "rselfmenu_0_1", | |
22 | - "sub_button": [ ] | |
23 | - } | |
24 | - ] | |
25 | - }, | |
26 | - { | |
27 | - "name": "发图", | |
28 | - "sub_button": [ | |
29 | - { | |
30 | - "type": "pic_sysphoto", | |
31 | - "name": "系统拍照发图", | |
32 | - "key": "rselfmenu_1_0", | |
33 | - "sub_button": [ ] | |
34 | - }, | |
35 | - { | |
36 | - "type": "pic_photo_or_album", | |
37 | - "name": "拍照或者相册发图", | |
38 | - "key": "rselfmenu_1_1", | |
39 | - "sub_button": [ ] | |
40 | - }, | |
41 | - { | |
42 | - "type": "pic_weixin", | |
43 | - "name": "微信相册发图", | |
44 | - "key": "rselfmenu_1_2", | |
45 | - "sub_button": [ ] | |
46 | - } | |
47 | - ] | |
48 | - }, | |
49 | - { | |
50 | - "name": "发送位置", | |
51 | - "type": "location_select", | |
52 | - "key": "rselfmenu_2_0" | |
53 | - } | |
54 | - ] | |
55 | - }' | |
56 | 6 | def create(menu, agent_id) |
57 | 7 | menu = JSON.load(menu) if menu.is_a?(String) |
58 | 8 | http_post("create", menu, {agentid: agent_id}) | ... | ... |
lib/qy_wechat_api/api/message.rb
... | ... | @@ -4,8 +4,94 @@ module QyWechatApi |
4 | 4 | module Api |
5 | 5 | class Message < Base |
6 | 6 | |
7 | - def send | |
7 | + # 发送文本 | |
8 | + def send_text(users, parties, tags, agent_id, content, safe=0) | |
9 | + params = common_params("text", agent_id, users, parties, tags, safe) | |
10 | + params.merge!({text: {content: content}}) | |
11 | + http_post("send", params) | |
12 | + end | |
13 | + | |
14 | + # 发送图片 | |
15 | + def send_image(users, parties, tags, agent_id, media_id, safe=0) | |
16 | + params = common_params("image", agent_id, users, parties, tags, safe) | |
17 | + params.merge!({image: {media_id: media_id}}) | |
18 | + http_post("send", params) | |
19 | + end | |
20 | + | |
21 | + # 发送语音 | |
22 | + def send_voice(users, parties, tags, agent_id, media_id, safe=0) | |
23 | + params = common_params("voice", agent_id, users, parties, tags, safe) | |
24 | + params.merge!({voice: {media_id: media_id}}) | |
25 | + http_post("send", params) | |
26 | + end | |
27 | + | |
28 | + # 发送视频 | |
29 | + # media_options: {title: "title", description: "Description"} | |
30 | + def send_video(users, parties, tags, agent_id, media_id, media_options={}, safe=0) | |
31 | + params = common_params("video", agent_id, users, parties, tags, safe) | |
32 | + params.merge!({ | |
33 | + video: { | |
34 | + media_id: media_id, | |
35 | + title: media_options["title"], | |
36 | + description: media_options["description"], | |
37 | + } | |
38 | + }) | |
39 | + http_post("send", params) | |
40 | + end | |
8 | 41 | |
42 | + # 文件信息 | |
43 | + def send_file(users, parties, tags, agent_id, media_id, safe=0) | |
44 | + params = common_params("file", agent_id, users, parties, tags, safe) | |
45 | + params.merge!({file: {media_id: media_id}}) | |
46 | + http_post("send", params) | |
47 | + end | |
48 | + | |
49 | + # news消息 | |
50 | + # "articles":[ | |
51 | + # { | |
52 | + # "title": "Title", | |
53 | + # "description": "Description", | |
54 | + # "url": "URL", | |
55 | + # "picurl": "PIC_URL" | |
56 | + # }, | |
57 | + # { | |
58 | + # "title": "Title", | |
59 | + # "description": "Description", | |
60 | + # "url": "URL", | |
61 | + # "picurl": "PIC_URL" | |
62 | + # } | |
63 | + # ] | |
64 | + def send_news(users, parties, tags, agent_id, articles, safe=0) | |
65 | + params = common_params("news", agent_id, users, parties, tags, safe) | |
66 | + params.merge!({news: {articles: articles}}) | |
67 | + http_post("send", params) | |
68 | + end | |
69 | + | |
70 | + # mpnews | |
71 | + # articles":[ | |
72 | + # { | |
73 | + # "title": "Title", | |
74 | + # "thumb_media_id": "id", | |
75 | + # "author": "Author", | |
76 | + # "content_source_url": "URL", | |
77 | + # "content": "Content", | |
78 | + # "digest": "Digest description", | |
79 | + # "show_cover_pic": "0" | |
80 | + # }, | |
81 | + # { | |
82 | + # "title": "Title", | |
83 | + # "thumb_media_id": "id", | |
84 | + # "author": "Author", | |
85 | + # "content_source_url": "URL", | |
86 | + # "content": "Content", | |
87 | + # "digest": "Digest description", | |
88 | + # "show_cover_pic": "0" | |
89 | + # } | |
90 | + # ] | |
91 | + def send_mpnews(users, parties, tags, agent_id, articles, safe=0) | |
92 | + params = common_params("mpnews", agent_id, users, parties, tags, safe) | |
93 | + params.merge!({mpnews: {articles: articles}}) | |
94 | + http_post("send", params) | |
9 | 95 | end |
10 | 96 | |
11 | 97 | private |
... | ... | @@ -14,6 +100,24 @@ module QyWechatApi |
14 | 100 | "/message" |
15 | 101 | end |
16 | 102 | |
103 | + # 通用函数 | |
104 | + def common_params(msg_type, agent_id, users=[], parties=[], tags=[], safe=0) | |
105 | + params = { | |
106 | + touser: join(users), | |
107 | + toparty: join(parties), | |
108 | + msgtype: msg_type, | |
109 | + agentid: agent_id, | |
110 | + totag: join(tags) | |
111 | + } | |
112 | + params.merge!({safe: safe}) if msg_type != "news" | |
113 | + params | |
114 | + end | |
115 | + | |
116 | + def join(array, split="|") | |
117 | + return array if array.is_a?(String) | |
118 | + array.join(split) | |
119 | + end | |
120 | + | |
17 | 121 | end |
18 | 122 | end |
19 | 123 | end | ... | ... |
lib/qy_wechat_api/client.rb
qy_wechat_api.gemspec
... | ... | @@ -24,6 +24,9 @@ Gem::Specification.new do |spec| |
24 | 24 | # https://github.com/brianmario/yajl-ruby |
25 | 25 | spec.add_dependency "yajl-ruby", "~> 1.2.0" |
26 | 26 | |
27 | + spec.add_dependency "carrierwave", "~> 0.10.0" | |
28 | + spec.add_dependency 'mini_magick', '~> 3.7.0' | |
29 | + | |
27 | 30 | spec.add_development_dependency "bundler", "~> 1.6" |
28 | 31 | spec.add_development_dependency "rake" |
29 | 32 | end | ... | ... |
... | ... | @@ -0,0 +1,72 @@ |
1 | +require "spec_helper" | |
2 | + | |
3 | +describe QyWechatApi::Api::Media do | |
4 | + | |
5 | + let(:image_jpg_path) do | |
6 | + "#{File.dirname(__FILE__)}/medias/ruby-logo.jpg" | |
7 | + end | |
8 | + | |
9 | + let(:image_ico_path) do | |
10 | + "#{File.dirname(__FILE__)}/medias/favicon.ico" | |
11 | + end | |
12 | + | |
13 | + let(:image_jpg_file) do | |
14 | + File.new(image_jpg_path) | |
15 | + end | |
16 | + | |
17 | + let(:image_ico_file) do | |
18 | + File.new(image_ico_path) | |
19 | + end | |
20 | + | |
21 | + let(:remote_png_path) do | |
22 | + "https://ruby-china-files.b0.upaiyun.com/user/big_avatar/273.jpg" | |
23 | + end | |
24 | + | |
25 | + let(:remote_jpg_path) do | |
26 | + "http://g.hiphotos.baidu.com/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=ce55457e4334970a537e187df4a3baad/03087bf40ad162d99455ef4d13dfa9ec8b13632762d0ed14.jpg" | |
27 | + end | |
28 | + | |
29 | + it "can upload a jpg File image" do | |
30 | + response = $client.media.upload(image_jpg_file, "image") | |
31 | + expect(response.code).to eq(QyWechatApi::OK_CODE) | |
32 | + expect(response.result.keys).to eq(["type", "media_id", "created_at"]) | |
33 | + end | |
34 | + | |
35 | + it "can upload a ico File image" do | |
36 | + response = $client.media.upload(image_ico_file, "image") | |
37 | + expect(response.code).to eq(QyWechatApi::OK_CODE) | |
38 | + expect(response.result.keys).to eq(["type", "media_id", "created_at"]) | |
39 | + end | |
40 | + | |
41 | + it "can upload a local image" do | |
42 | + response = $client.media.upload(image_jpg_path, "image") | |
43 | + expect(response.code).to eq(QyWechatApi::OK_CODE) | |
44 | + expect(response.result.keys).to eq(["type", "media_id", "created_at"]) | |
45 | + end | |
46 | + | |
47 | + it "can upload a local ico image" do | |
48 | + response = $client.media.upload(image_ico_path, "image") | |
49 | + expect(response.code).to eq(QyWechatApi::OK_CODE) | |
50 | + expect(response.result.keys).to eq(["type", "media_id", "created_at"]) | |
51 | + end | |
52 | + | |
53 | + it "can upload a remote png image" do | |
54 | + response = $client.media.upload(remote_png_path, "image") | |
55 | + expect(response.code).to eq(QyWechatApi::OK_CODE) | |
56 | + expect(response.result.keys).to eq(["type", "media_id", "created_at"]) | |
57 | + end | |
58 | + | |
59 | + it "can upload a remote jpg image" do | |
60 | + response = $client.media.upload(remote_jpg_path, "image") | |
61 | + expect(response.code).to eq(QyWechatApi::OK_CODE) | |
62 | + expect(response.result.keys).to eq(["type", "media_id", "created_at"]) | |
63 | + end | |
64 | + | |
65 | + # it "#download_media_url return a String url" do | |
66 | + # image = $client.media.upload(image_ico_path, "image") | |
67 | + # media_id = image.result["media_id"] | |
68 | + # image_url = $client.download_media_url(media_id) | |
69 | + # expect(image_url.class).to eq(String) | |
70 | + # end | |
71 | + | |
72 | +end | ... | ... |
No preview for this file type
7.24 KB
... | ... | @@ -0,0 +1,60 @@ |
1 | +require "spec_helper" | |
2 | + | |
3 | +describe QyWechatApi::Api::Menu do | |
4 | + let(:menu_string) do | |
5 | + '{ | |
6 | + "button": [ | |
7 | + { | |
8 | + "name": "扫码", | |
9 | + "sub_button": [ | |
10 | + { | |
11 | + "type": "scancode_waitmsg", | |
12 | + "name": "扫码带提示", | |
13 | + "key": "rselfmenu_0_0", | |
14 | + "sub_button": [ ] | |
15 | + }, | |
16 | + { | |
17 | + "type": "scancode_push", | |
18 | + "name": "扫码推事件", | |
19 | + "key": "rselfmenu_0_1", | |
20 | + "sub_button": [ ] | |
21 | + } | |
22 | + ] | |
23 | + }, | |
24 | + { | |
25 | + "name": "发图", | |
26 | + "sub_button": [ | |
27 | + { | |
28 | + "type": "pic_sysphoto", | |
29 | + "name": "系统拍照发图", | |
30 | + "key": "rselfmenu_1_0", | |
31 | + "sub_button": [ ] | |
32 | + }, | |
33 | + { | |
34 | + "type": "pic_photo_or_album", | |
35 | + "name": "拍照或者相册发图", | |
36 | + "key": "rselfmenu_1_1", | |
37 | + "sub_button": [ ] | |
38 | + }, | |
39 | + { | |
40 | + "type": "pic_weixin", | |
41 | + "name": "微信相册发图", | |
42 | + "key": "rselfmenu_1_2", | |
43 | + "sub_button": [ ] | |
44 | + } | |
45 | + ] | |
46 | + }, | |
47 | + { | |
48 | + "name": "发送位置", | |
49 | + "type": "location_select", | |
50 | + "key": "rselfmenu_2_0" | |
51 | + } | |
52 | + ] | |
53 | + }' | |
54 | + end | |
55 | + | |
56 | + it "#create" do | |
57 | + response = $client.menu.create(menu_string, 1) | |
58 | + expect(response.code).to eq(QyWechatApi::OK_CODE) | |
59 | + end | |
60 | +end | ... | ... |
... | ... | @@ -0,0 +1,50 @@ |
1 | +require "spec_helper" | |
2 | +describe QyWechatApi::Api::Message do | |
3 | + let(:text_message) do | |
4 | + "text message" | |
5 | + end | |
6 | + | |
7 | + let(:image_path) do | |
8 | + "#{File.dirname(__FILE__)}/medias/ruby-logo.jpg" | |
9 | + end | |
10 | + | |
11 | + let(:image_file) do | |
12 | + File.new(image_path) | |
13 | + end | |
14 | + | |
15 | + it "#send_text_message" do | |
16 | + response = $client.message.send_text("@all", "@all", "@all", 1, text_message) | |
17 | + expect(response.code).to eq(QyWechatApi::OK_CODE) | |
18 | + end | |
19 | + | |
20 | + it "#send_image_message" do | |
21 | + response = $client.media.upload(image_path, "image").result | |
22 | + response = $client.message.send_image("@all", "@all", "@all", 1, response["media_id"]) | |
23 | + expect(response.code).to eq(QyWechatApi::OK_CODE) | |
24 | + end | |
25 | + | |
26 | + | |
27 | + it "#send_news" do | |
28 | + articles = [{ | |
29 | + "title" => "Happy Day", | |
30 | + "description" => "Is Really A Happy Day", | |
31 | + "url" => "http://www.baidu.com", | |
32 | + "picurl" => "http://www.baidu.com/img/bdlogo.gif" | |
33 | + }, | |
34 | + { | |
35 | + "title" => "Happy Day", | |
36 | + "description" => "Is Really A Happy Day", | |
37 | + "url" => "http://www.baidu.com", | |
38 | + "picurl"=> "http://www.baidu.com/img/bdlogo.gif" | |
39 | + }] | |
40 | + response = $client.message.send_news("@all", "@all", "@all", 1, articles) | |
41 | + expect(response.code).to eq(QyWechatApi::OK_CODE) | |
42 | + end | |
43 | + | |
44 | + it "#send_file" do | |
45 | + response = $client.media.upload(image_path, "image").result | |
46 | + response = $client.message.send_file("@all", "@all", "@all", 1, response["media_id"]) | |
47 | + expect(response.code).to eq(QyWechatApi::OK_CODE) | |
48 | + end | |
49 | + | |
50 | +end | ... | ... |
spec/spec_helper.rb
... | ... | @@ -14,6 +14,15 @@ |
14 | 14 | # users commonly want. |
15 | 15 | # |
16 | 16 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration |
17 | +require "qy_wechat_api" | |
18 | +require "pry-rails" | |
19 | + | |
20 | +corpid = "wxb9ce1d023fe6eb69" | |
21 | +corpsecret = "UOofFIah4PVLmkG8xMH3lpDxj6NTnQSKMrFt-HubiPB4kjB09EmTVcUjgNeermps" | |
22 | + | |
23 | + | |
24 | +$client = QyWechatApi::Client.new(corpid, corpsecret) | |
25 | + | |
17 | 26 | RSpec.configure do |config| |
18 | 27 | # rspec-expectations config goes here. You can use an alternate |
19 | 28 | # assertion/expectation library such as wrong or the stdlib/minitest | ... | ... |