wxapi 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a96de275aacbda637fb5d2f52229cbfae165c168f7b657dd5c6608b742805e20
4
+ data.tar.gz: 0e4e7d0888413af25fa4392b9f5a4b7adfabbc8782721eb6fdd900392f3f3ccc
5
+ SHA512:
6
+ metadata.gz: 6050182becc85a57cab38778ae027fe22497a26ee33366c36c95edcb1b4736cf72f5f6ff1f42421d908a4b7d907df1259430cfe1cba38a364d6c98d1816d0b08
7
+ data.tar.gz: e8522ae70f8312f1cc18b039b99e51be5e5c782ff46b7b70cb7ca0a3e16a473993fbd63f248d18e284777acb316a4f93ebbad0c3f7a8976b0322a4975ebd6074
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in wechat_public_api.gemspec
6
+ gemspec
7
+
8
+ gem "rest-client", "~> 2.1"
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 zhangS2
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # 简介
2
+
3
+ 基于ruby的微信公众号开发的API,包含对微信公众号菜单栏、客服消息、模板消息、帐号管理等接口的封装。
4
+
5
+ API长期更新维护,建议使用最新版本。
6
+
7
+ ## 安装
8
+
9
+ 添加 Gemfile:
10
+
11
+ ```ruby
12
+ gem 'wxapi'
13
+ ```
14
+
15
+ 执行 bundle:
16
+
17
+ $ bundle install
18
+
19
+ 或者直接通过 gem 安装:
20
+
21
+ $ gem install wxapi
22
+
23
+
24
+
25
+ 项目最早来源于 https://index.ruby-china.com/gems/wechat_public_api
26
+ 我在原项目的基础上进行了一些修改和优化,使其更加符合微信公众号开发的规范,增加了更多的扩展性。
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
3
+
4
+
5
+ task :upload do |t|
6
+ sh "gem build wxapi.gemspec"
7
+ sh "gem push wxapi-#{WxApi::VERSION}.gem"
8
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "wx_api"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/lib/wx_api.rb ADDED
@@ -0,0 +1,41 @@
1
+ require "wxapi/version"
2
+ require "wxapi/menu"
3
+ require "wxapi/kf_message"
4
+ require "wxapi/templet_message"
5
+ require "wxapi/access_token"
6
+ require "wxapi/account"
7
+ require "wxapi/aes"
8
+ require "wxapi/utils"
9
+ require "wxapi/user"
10
+ require "wxapi/material"
11
+
12
+ class WxApi
13
+ include AccessToken
14
+ include Account
15
+ include Aes
16
+ include Kf
17
+ include Material
18
+ include Menu
19
+ include Tp
20
+ include User
21
+ include Utils
22
+
23
+ # 默认不缓存 access_token, access_token_cache = True 缓存
24
+ # @param <hash> aoptions
25
+ # => example
26
+ # wechat_api = WechatPublicApi.new appid: 'xx', app_secret: 'xx', access_token_cache: true
27
+ # wechat_api.app_id -- get appid
28
+ #
29
+ # api.get_access_token
30
+ #
31
+
32
+ attr_accessor :app_id, :app_secret, :access_token_cache
33
+ attr_accessor :prefix
34
+ def initialize(options={})
35
+ @app_id = options[:app_id]
36
+ @app_secret = options[:app_secret]
37
+ @access_token_cache = options[:access_token_cache]
38
+ @prefix = options[:api_prefix]
39
+ @prefix="https://api.weixin.qq.com" if @prefix.nil?
40
+ end
41
+ end
@@ -0,0 +1,45 @@
1
+ #####################################################
2
+ # 获得微信公众号的 access_token (Get wechat public access_token)
3
+ # Created by zhangmingxin
4
+ # Date: 2018-05-17
5
+ # Wechat number: zmx119966
6
+ ####################################################
7
+
8
+ class WxApi
9
+ module AccessToken
10
+
11
+ ###
12
+ # 获取 access_token
13
+ # 判断access_token_cache,决定是否需要缓存数据
14
+ # @return <string> nil or access_token
15
+ def get_access_token()
16
+ appid = @app_id
17
+ secret = @app_secret
18
+ access_token_cache = @access_token_cache
19
+
20
+ unless access_token_cache
21
+ response = HTTParty.get("#{prefix}/cgi-bin/token?grant_type=client_credential&appid=#{appid}&secret=#{secret}").body
22
+ response_body = (JSON.parse response)
23
+
24
+ # 抛出异常
25
+ throw response_body['errmsg'] unless response_body['access_token']
26
+
27
+ return response_body['access_token']
28
+ end
29
+
30
+ _cache_key = "#{appid}_access_token"
31
+ _cached_access_token = $redis.get _cache_key
32
+ if _cached_access_token == nil or _cached_access_token == ''
33
+ response = HTTParty.get("#{prefix}/cgi-bin/token?grant_type=client_credential&appid=#{appid}&secret=#{secret}").body
34
+ response_body = (JSON.parse response)
35
+
36
+ # 抛出异常
37
+ throw response_body['errmsg'] unless response_body['access_token']
38
+
39
+ _cached_access_token = response_body['access_token']
40
+ $redis.set _cache_key, _cached_access_token, ex: 2.minutes
41
+ end
42
+ _cached_access_token
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,112 @@
1
+ #####################################################
2
+ # 微信公众号帐号管理 (带参二维码获得)
3
+ # Created by zhangmingxin
4
+ # Date: 2018-05-18
5
+ # Wechat number: zmx119966
6
+ ####################################################
7
+
8
+ class WxApi
9
+ module Account
10
+ ###
11
+ # 获取临时场景带惨二维码,30天有效
12
+ # @param <int> sceneid -- 场景值ID,临时二维码时为32位非0整型,永久二维码时最大值为100000(目前参数只支持1--100000)
13
+ # @return <string> url -- 二维码网址
14
+ #
15
+ def get_qrscene(sceneid)
16
+ access_token = get_access_token()
17
+
18
+ # 获取ticket
19
+ uri = URI.parse("#{prefix}/cgi-bin/qrcode/create?access_token=#{access_token}")
20
+ post_data = {
21
+ 'expire_seconds' => 2592000,
22
+ 'action_name' => 'QR_SCENE',
23
+ 'action_info' => {'scene' => {'scene_id' => sceneid}}}
24
+ http = Net::HTTP.new(uri.host, uri.port)
25
+ http.use_ssl = true
26
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
27
+ request = Net::HTTP::Post.new("/cgi-bin/qrcode/create?access_token=#{access_token}")
28
+ request.add_field('Content-Type', 'application/json')
29
+ request.body = post_data.to_json
30
+ response = http.request(request)
31
+ content = JSON.parse(response.body)
32
+ ticket = content['ticket']
33
+
34
+ # 通过ticket换取二维码
35
+ "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=#{ticket}"
36
+ end
37
+
38
+ ###
39
+ # 获取永久二维码
40
+ # @param <int> sceneid -- 场景值ID,临时二维码时为32位非0整型,永久二维码时最大值为100000(目前参数只支持1--100000)
41
+ # @return <string> url -- 二维码网址
42
+ #
43
+ def get_qrsrtscene(sceneid)
44
+ access_token = get_access_token()
45
+
46
+ # 获取ticket
47
+ uri = URI.parse("#{prefix}/cgi-bin/qrcode/create?access_token=#{access_token}")
48
+ post_data = {
49
+ 'action_name' => 'QR_LIMIT_STR_SCENE',
50
+ 'action_info' => {'scene' => {'scene_id' => sceneid}}}
51
+ http = Net::HTTP.new(uri.host, uri.port)
52
+ http.use_ssl = true
53
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
54
+ request = Net::HTTP::Post.new("/cgi-bin/qrcode/create?access_token=#{access_token}")
55
+ request.add_field('Content-Type', 'application/json')
56
+ request.body = post_data.to_json
57
+ response = http.request(request)
58
+ content = JSON.parse(response.body)
59
+ ticket = content['ticket']
60
+
61
+ # 通过ticket换取二维码
62
+ "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=#{ticket}"
63
+ end
64
+
65
+ ###
66
+ # 保存带参数二维码到指定位置
67
+ # @param <string> path -- 例如: "#{Rails.root}/public/qrcode"
68
+ # @param <string> filename -- 文件名,可选参数,默认不填写则使用时间戳+随机数的方式命名
69
+ #
70
+ # @return <string> path -- 二维码的保存路径
71
+ def save_qrcode(path, *filename)
72
+ # 判断是否需要新建文件
73
+ unless File.exist?(path)
74
+ FileUtils.makedirs(path)
75
+ end
76
+
77
+ if filename
78
+ path = "#{path}/#{filename}"
79
+ else
80
+ path = "#{path}/#{Time.now.to_i.to_s}_#{rand 1000.9999}"
81
+ end
82
+
83
+ File.open(path, 'wb') do |f|
84
+ f.write(HTTParty.get(url).body)
85
+ end
86
+
87
+ path
88
+ end
89
+
90
+ ###
91
+ # @param <string> longurl -- 需要被压缩的url
92
+ #
93
+ # @return <json> shorturl -- 返回短链接 {"errcode":0,"errmsg":"ok","short_url":"http:\/\/w.url.cn\/s\/AvCo6Ih"}
94
+ # if false
95
+ # @return {"errcode":40013,"errmsg":"invalid appid"}
96
+ #
97
+ def get_shorturl(longurl)
98
+ access_token = get_access_token()
99
+ uri = URI.parse("#{prefix}/cgi-bin/shorturl?access_token=#{access_token}")
100
+ post_data = {action: "long2short", long_url: longurl}
101
+ http = Net::HTTP.new(uri.host, uri.port)
102
+ http.use_ssl = true
103
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
104
+ request = Net::HTTP::Post.new("/cgi-bin/shorturl?access_token=#{access_token}")
105
+ request.add_field('Content-Type', 'application/json')
106
+ request.body = post_data.to_json
107
+ response = http.request(request)
108
+
109
+ JSON.parse(response.body)
110
+ end
111
+ end
112
+ end
data/lib/wxapi/aes.rb ADDED
@@ -0,0 +1,41 @@
1
+ #####################################################
2
+ # 消息加密解密
3
+ # Created by zhangmingxin
4
+ # Date: 2018-05-18
5
+ # Wechat number: zmx119966
6
+ ####################################################
7
+
8
+ class WxApi
9
+ module Aes
10
+ # 解密
11
+ def decrypt(key, dicrypted_string)
12
+ cipher = OpenSSL::Cipher::AES.new(256, :CBC)
13
+ cipher.decrypt
14
+ cipher.key = key
15
+ cipher.iv = '0000000000000000'
16
+ cipher.padding = 0
17
+ cipher.update(dicrypted_string) << cipher.final
18
+ end
19
+
20
+ # 加密
21
+ def encrypt(aes_key, text, app_id)
22
+ text = text.force_encoding("ASCII-8BIT")
23
+ random = SecureRandom.hex(8)
24
+ msg_len = [text.length].pack("N")
25
+ text = "#{random}#{msg_len}#{text}#{app_id}"
26
+ text = WxAuth.encode(text)
27
+ text = handle_cipher(:encrypt, aes_key, text)
28
+ Base64.encode64(text)
29
+ end
30
+
31
+ private
32
+ def handle_cipher(action, aes_key, text)
33
+ cipher = OpenSSL::Cipher.new('AES-256-CBC')
34
+ cipher.send(action)
35
+ cipher.padding = 0
36
+ cipher.key = aes_key
37
+ cipher.iv = aes_key[0...16]
38
+ cipher.update(text) + cipher.final
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,143 @@
1
+ #####################################################
2
+ # 客服消息管理 (about kf_account message)
3
+ # Created by zhangmingxin
4
+ # Date: 2018-05-17
5
+ # Wechat number: zmx119966
6
+ ####################################################
7
+
8
+ class WxApi
9
+ module Kf
10
+
11
+ ###
12
+ # execute post
13
+ # => example
14
+ # message = {
15
+ # touser: openid,
16
+ # msgtype: 'text',
17
+ # text: {content: content},
18
+ # customservice:{
19
+ # kf_account: 'xxxxxxxx'
20
+ # }
21
+ # }
22
+ #
23
+ # @param <JSON> message
24
+ #
25
+ def post_customer_message(message)
26
+ # get access_token
27
+ access_token = get_access_token()
28
+
29
+ uri = URI.parse("#{prefix}/cgi-bin/message/custom/send?access_token=#{access_token}")
30
+ http = Net::HTTP.new(uri.host, uri.port)
31
+ http.use_ssl = true
32
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
33
+ request = Net::HTTP::Post.new("/cgi-bin/message/custom/send?access_token=#{access_token}")
34
+ request.add_field('Content-Type', 'application/json')
35
+ request.body = message.to_json.gsub(/\\u([0-9a-z]{4})/) {|s| [$1.to_i(16)].pack("U")}
36
+ response = http.request(request)
37
+ JSON.parse(response.body)
38
+ end
39
+
40
+ ###
41
+ # @param <string> openid -- 用户的openid
42
+ # @param <string> content -- 需要发送的客服消息内容
43
+ #
44
+ # 发送文字消息
45
+ def kf_text_message(openid, content, kf_account=nil)
46
+
47
+ custom_message = {
48
+ touser: openid,
49
+ msgtype: 'text',
50
+ text: {content: content}
51
+ }
52
+
53
+ if kf_account
54
+ custom_message.merge({customservice:{account: kf_account}})
55
+ end
56
+
57
+ post_customer_message custom_message
58
+ end
59
+
60
+ ###
61
+ # @param <string> media_id -- 发送的图片/语音/视频/图文消息(点击跳转到图文消息页)的媒体ID
62
+ #
63
+ # 发送图片消息
64
+ def kf_image_message(openid, media_id, kf_account=nil)
65
+
66
+ custom_message = {
67
+ touser: openid,
68
+ msgtype: 'image',
69
+ image: {media_id: media_id}
70
+ }
71
+
72
+ if kf_account
73
+ custom_message.merge({customservice:{account: kf_account}})
74
+ end
75
+
76
+ post_customer_message custom_message
77
+ end
78
+
79
+ # 发送图文消息(点击跳转到图文消息页面)
80
+ def kf_mpnews_message(openid, media_id, kf_account=nil)
81
+ custom_message = {
82
+ touser: openid,
83
+ msgtype: 'mpnews',
84
+ mpnews: {media_id: media_id}
85
+ }
86
+ if kf_account
87
+ custom_message.merge({customservice:{account: kf_account}})
88
+ end
89
+
90
+ post_customer_message custom_message
91
+ end
92
+
93
+ ###
94
+ # @param <JSON> articles -- 图文消息列表
95
+ # => example
96
+ # articles = [
97
+ # {
98
+ # "title":"Happy Day",
99
+ # "description":"Is Really A Happy Day",
100
+ # "url":"URL",
101
+ # "picurl":"PIC_URL"
102
+ # },
103
+ # {
104
+ # "title":"Happy Day",
105
+ # "description":"Is Really A Happy Day",
106
+ # "url":"URL",
107
+ # "picurl":"PIC_URL"
108
+ # }
109
+ # ]
110
+ #
111
+ # 发送图文消息(点击跳转到外链)
112
+ def kf_news_message(openid, articles, kf_account=nil)
113
+ custom_message = {
114
+ touser: openid,
115
+ msgtype: 'news',
116
+ news: {
117
+ articles: articles
118
+ }
119
+ }
120
+
121
+ if kf_account
122
+ custom_message.merge({customservice:{account: kf_account}})
123
+ end
124
+ post_customer_message custom_message
125
+ end
126
+
127
+ # 发送语音消息
128
+ def kf_voice_message(openid, media_id, kf_account=nil)
129
+
130
+ custom_message = {
131
+ touser: openid,
132
+ msgtype: 'voice',
133
+ voice: {
134
+ media_id: media_id
135
+ }
136
+ }
137
+ if kf_account
138
+ custom_message.merge({customservice:{account: kf_account}})
139
+ end
140
+ post_customer_message custom_message
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,48 @@
1
+ #####################################################
2
+ # 微信公众号素材管理
3
+ # Created by zhangmingxin
4
+ # Date: 2018-05-18
5
+ # Wechat number: zmx119966
6
+ ####################################################
7
+
8
+ class WxApi
9
+ module Material
10
+ ###
11
+ # 获得临时图片素材的 media_id
12
+ # @param <string> file_path -- 图片素材的路径
13
+ #
14
+ # @return <json> {"type":"TYPE","media_id":"MEDIA_ID","created_at":123456789}
15
+ # if false
16
+ # @return <json> {"errcode":40004,"errmsg":"invalid media type"}
17
+ #
18
+ def upload_image_media(file_path)
19
+ # request access_token
20
+ access_token = get_access_token()
21
+ response = RestClient.post("#{prefix}/cgi-bin/media/upload",
22
+ {
23
+ access_token: access_token,
24
+ type: 'image',
25
+ media: File.new(file_path, 'rb')})
26
+ JSON.parse(response)
27
+ end
28
+
29
+ ###
30
+ # 新增永久图片素材
31
+ # @param <string> file_path -- 图片素材的路径
32
+ #
33
+ # @return <json> {"type":"TYPE","media_id":"MEDIA_ID","created_at":123456789}
34
+ # if false
35
+ # @return <json> {"errcode":40004,"errmsg":"invalid media type"}
36
+ #
37
+ def upload_image_material(file_path)
38
+ # request access_token
39
+ access_token = get_access_token()
40
+ response = RestClient.post('https://api.weixin.qq.com/cgi-bin/material/add_material',
41
+ {
42
+ access_token: access_token,
43
+ type: 'image',
44
+ media: File.new(file_path, 'rb')})
45
+ JSON.parse(response)
46
+ end
47
+ end
48
+ end
data/lib/wxapi/menu.rb ADDED
@@ -0,0 +1,72 @@
1
+ #####################################################
2
+ # 公众号自定义菜单栏模块 (about wechat public menu)
3
+ # Created by zhangmingxin
4
+ # Date: 2018-05-17
5
+ # Wechat number: zmx119966
6
+ ####################################################
7
+
8
+ class WxApi
9
+ module Menu
10
+ ###
11
+ # create wechat public menu
12
+ # @param <json> post_data
13
+ #
14
+ # => post_data example
15
+ # {
16
+ # "button": [
17
+ # {
18
+ # "type": "view",
19
+ # "name": "",
20
+ # "url": "",
21
+ # "sub_button": []
22
+ # },
23
+ # {
24
+ # "type": "click",
25
+ # "name": "",
26
+ # "key": "menu_3",
27
+ # "sub_button": []
28
+ # }
29
+ # ]
30
+ # }
31
+ #
32
+ # if success
33
+ # @return <JSON> {"errcode"=>0, "errmsg"=>"ok"}
34
+ # if failed
35
+ # @return <JSON> {"errcode"=>40166, "errmsg"=>"...."}
36
+ #
37
+ def create_menu(post_data)
38
+ # request access_token
39
+ access_token = get_access_token()
40
+ post_data = post_data.to_json.gsub(/\\u([0-9a-z]{4})/) {|s| [$1.to_i(16)].pack("U")}
41
+
42
+ uri = URI.parse("#{prefix}/cgi-bin/menu/create?access_token=#{access_token}")
43
+ http = Net::HTTP.new(uri.host, uri.port)
44
+ http.use_ssl = true
45
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
46
+ request = Net::HTTP::Post.new("/cgi-bin/menu/create?access_token=#{access_token}")
47
+ request.add_field('Content-Type', 'application/json')
48
+ request.body = post_data
49
+ response = http.request(request)
50
+ (JSON.parse response.body)
51
+ end
52
+
53
+ # get wechat public menu list
54
+ def query_menu()
55
+ # request access_token
56
+ access_token = get_access_token()
57
+ response = HTTParty.get("#{prefix}/cgi-bin/menu/get?access_token=#{access_token}").body
58
+ (JSON.parse response)
59
+ end
60
+
61
+ ###
62
+ # delete wechat query from access_token
63
+ # @return <JSON> {"errcode"=>0, "errmsg"=>"ok"}
64
+ #
65
+ def delete_menu()
66
+ # request access_token
67
+ access_token = get_access_token
68
+ response = HTTParty.get("#{prefix}/cgi-bin/menu/delete?access_token=#{access_token}").body
69
+ (JSON.parse response)
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,103 @@
1
+ #####################################################
2
+ # 微信公众号模板消息相关接口 (About templet message of wechat public)
3
+ # Created by zhangmingxin
4
+ # Date: 2018-05-17
5
+ # Wechat number: zmx119966
6
+ ####################################################
7
+
8
+ class WxApi
9
+ module Tp
10
+ ###
11
+ # @param <JSON> message
12
+ # @param <string> url_params -- 消息路径
13
+ # 发送模板消息接口
14
+ def post_template_message(message, url_params)
15
+ # get access_token
16
+ access_token = get_access_token()
17
+
18
+ uri = URI.parse("#{prefix}/cgi-bin/message/template/#{url_params}?access_token=#{access_token}")
19
+ http = Net::HTTP.new(uri.host, uri.port)
20
+ http.use_ssl = true
21
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
22
+ request = Net::HTTP::Post.new("/cgi-bin/message/template/#{url_params}?access_token=#{access_token}")
23
+ request.add_field('Content-Type', 'application/json')
24
+ # 部分字符转换为json后 成为unicode编码
25
+ request.body = message.to_json.gsub(/\\u([0-9a-z]{4})/) {|s| [$1.to_i(16)].pack("U")}
26
+ response = http.request(request)
27
+ JSON.parse(response.body)
28
+ end
29
+
30
+ ###
31
+ # @param <string> openid -- 用户的openid
32
+ # @param <string> templet_id -- 微信公众号后台提供的模板ID
33
+ # @param <string> url -- 模板跳转链接
34
+ # @param <string> appid -- 小程序的appid
35
+ # @param <string> pagepath -- 小程序页面路径 (eq: /index/index)
36
+ # @param <JSON> data -- 模板数据
37
+ # => data example
38
+ # data = {
39
+ # "first": {
40
+ # "value":"恭喜你购买成功!",
41
+ # "color":"#173177"
42
+ # },
43
+ # "keyword1":{
44
+ # "value":"巧克力",
45
+ # "color":"#173177"
46
+ # },
47
+ # "keyword2": {
48
+ # "value":"39.8元",
49
+ # "color":"#173177"
50
+ # },
51
+ # "keyword3": {
52
+ # "value":"2014年9月22日",
53
+ # "color":"#173177"
54
+ # },
55
+ # "remark":{
56
+ # "value":"欢迎再次购买!",
57
+ # "color":"#173177"
58
+ # }
59
+ # }
60
+ # 小程序模板消息
61
+ def tp_miniprogram_message(openid, templet_id, url, appid, pagepath, data)
62
+ message = {
63
+ 'touser': openid,
64
+ 'template_id': templet_id,
65
+ 'url': url,
66
+ "miniprogram":{
67
+ "appid": appid,
68
+ "pagepath": pagepath
69
+ },
70
+ 'data': data
71
+ }
72
+
73
+ post_template_message message, 'send'
74
+ end
75
+
76
+ # 普通的模板消息,不跳转小程序
77
+ def tp_general_message(openid, templet_id, url, data)
78
+ message = {
79
+ 'touser': openid,
80
+ 'template_id': templet_id,
81
+ 'url': url,
82
+ 'data': data
83
+ }
84
+ post_template_message message, 'send'
85
+ end
86
+
87
+ # 删除模板
88
+ def tp_delete_template(templet_id)
89
+ message = {
90
+ 'template_id': template_id
91
+ }
92
+ post_template_message message, 'del_private_template'
93
+ end
94
+
95
+ # 获得模板列表
96
+ def tp_get_all()
97
+ access_token = get_access_token()
98
+ response = RestClient.get("#{prefix}cgi-bin/template/get_all_private_template?access_token=#{access_token}").body
99
+ response_body = (JSON.parse response)
100
+ response_body
101
+ end
102
+ end
103
+ end
data/lib/wxapi/user.rb ADDED
@@ -0,0 +1,41 @@
1
+ #####################################################
2
+ # 公众号用户管理
3
+ # Created by zhangmingxin
4
+ # Date: 2018-05-18
5
+ # Wechat number: zmx119966
6
+ ####################################################
7
+
8
+ class WxApi
9
+ module User
10
+ # 获取用户信息
11
+ # @return <JSON>
12
+ # {
13
+ # "subscribe": 1,
14
+ # "openid": "o6_bmjrPTlm6_2sgVt7hMZOPfL2M",
15
+ # "nickname": "Band",
16
+ # "sex": 1,
17
+ # "language": "zh_CN",
18
+ # "city": "广州",
19
+ # "province": "广东",
20
+ # "country": "中国",
21
+ # "headimgurl":"http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
22
+ # "subscribe_time": 1382694957,
23
+ # "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
24
+ # "remark": "",
25
+ # "groupid": 0,
26
+ # "tagid_list":[128,2],
27
+ # "subscribe_scene": "ADD_SCENE_QR_CODE",
28
+ # "qr_scene": 98765,
29
+ # "qr_scene_str": ""
30
+ # }
31
+ #
32
+ # if failed
33
+ # {"errcode":40013,"errmsg":"invalid appid"}
34
+ #
35
+ def get_userinfo(openid)
36
+ # request access_token
37
+ access_token = get_access_token()
38
+ JSON.parse RestClient.get("#{prefix}/cgi-bin/user/info?access_token=#{access_token}&openid=#{openid}&lang=zh_CN").body
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,12 @@
1
+ #####################################################
2
+ # 基于微信公众号的小工具,公用
3
+ # Created by zhangmingxin
4
+ # Date: 2018-05-18
5
+ # Wechat number: zmx119966
6
+ ####################################################
7
+
8
+ class WxApi
9
+ module Utils
10
+ # todo
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ class WxApi
2
+ VERSION = "1.0.0"
3
+ end
data/wxapi.gemspec ADDED
@@ -0,0 +1,39 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "wxapi/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "wxapi"
8
+ spec.version = WxApi::VERSION
9
+ spec.authors = ["黄滚 twitter: @hg_nohair"]
10
+ spec.email = ["xurenlu@gmail.com"]
11
+
12
+ spec.summary = %q{微信公众号开发API,包含对微信公众号菜单栏、客服消息、模板消息、帐号管理等接口的封装,API长期更新维护,建议使用最新版本.}
13
+ spec.description = %q{微信公众号开发API,包含对微信公众号菜单栏、客服消息、模板消息、帐号管理等接口的封装,API长期更新维护,建议使用最新版本,开发者使用文档:https://yuque.com/qianlansedehei/wechat_public_api}
14
+ spec.homepage = "https://github.com/xurenlu/wxapi"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ # if spec.respond_to?(:metadata)
20
+ # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
21
+ # else
22
+ # raise "RubyGems 2.0 or newer is required to protect against " \
23
+ # "public gem pushes."
24
+ # end
25
+
26
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
27
+ f.match(%r{^(test|spec|features)/})
28
+ end
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
+
33
+ spec.add_development_dependency "bundler"
34
+ spec.add_development_dependency "rake", "~> 10.0"
35
+ spec.add_development_dependency "redis"
36
+ spec.add_development_dependency "json"
37
+ spec.add_development_dependency "rest-client"
38
+ spec.add_development_dependency 'unf_ext', '~> 0.0.7.5'
39
+ end
metadata ADDED
@@ -0,0 +1,146 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wxapi
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - '黄滚 twitter: @hg_nohair'
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-02-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: redis
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: json
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rest-client
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: unf_ext
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.0.7.5
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.0.7.5
97
+ description: 微信公众号开发API,包含对微信公众号菜单栏、客服消息、模板消息、帐号管理等接口的封装,API长期更新维护,建议使用最新版本,开发者使用文档:https://yuque.com/qianlansedehei/wechat_public_api
98
+ email:
99
+ - xurenlu@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - Gemfile
106
+ - LICENSE.txt
107
+ - README.md
108
+ - Rakefile
109
+ - bin/console
110
+ - bin/setup
111
+ - lib/wx_api.rb
112
+ - lib/wxapi/access_token.rb
113
+ - lib/wxapi/account.rb
114
+ - lib/wxapi/aes.rb
115
+ - lib/wxapi/kf_message.rb
116
+ - lib/wxapi/material.rb
117
+ - lib/wxapi/menu.rb
118
+ - lib/wxapi/templet_message.rb
119
+ - lib/wxapi/user.rb
120
+ - lib/wxapi/utils.rb
121
+ - lib/wxapi/version.rb
122
+ - wxapi.gemspec
123
+ homepage: https://github.com/xurenlu/wxapi
124
+ licenses:
125
+ - MIT
126
+ metadata: {}
127
+ post_install_message:
128
+ rdoc_options: []
129
+ require_paths:
130
+ - lib
131
+ required_ruby_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ required_rubygems_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ requirements: []
142
+ rubygems_version: 3.5.4
143
+ signing_key:
144
+ specification_version: 4
145
+ summary: 微信公众号开发API,包含对微信公众号菜单栏、客服消息、模板消息、帐号管理等接口的封装,API长期更新维护,建议使用最新版本.
146
+ test_files: []