shixian-weixin_authorize 1.6.2

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.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +2 -0
  3. data/.gitignore +18 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +11 -0
  6. data/Gemfile +17 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +67 -0
  9. data/Rakefile +1 -0
  10. data/lib/weixin_authorize/api/custom.rb +124 -0
  11. data/lib/weixin_authorize/api/data_cube.rb +8 -0
  12. data/lib/weixin_authorize/api/groups.rb +49 -0
  13. data/lib/weixin_authorize/api/mass.rb +78 -0
  14. data/lib/weixin_authorize/api/media.rb +136 -0
  15. data/lib/weixin_authorize/api/menu.rb +36 -0
  16. data/lib/weixin_authorize/api/oauth.rb +38 -0
  17. data/lib/weixin_authorize/api/qrcode.rb +57 -0
  18. data/lib/weixin_authorize/api/template.rb +34 -0
  19. data/lib/weixin_authorize/api/user.rb +47 -0
  20. data/lib/weixin_authorize/api.rb +3 -0
  21. data/lib/weixin_authorize/carrierwave/weixin_uploader.rb +4 -0
  22. data/lib/weixin_authorize/client.rb +86 -0
  23. data/lib/weixin_authorize/config.rb +29 -0
  24. data/lib/weixin_authorize/handler/exceptions.rb +7 -0
  25. data/lib/weixin_authorize/handler/global_code.rb +89 -0
  26. data/lib/weixin_authorize/handler/result_handler.rb +52 -0
  27. data/lib/weixin_authorize/handler.rb +3 -0
  28. data/lib/weixin_authorize/js_ticket/object_store.rb +21 -0
  29. data/lib/weixin_authorize/js_ticket/redis_store.rb +41 -0
  30. data/lib/weixin_authorize/js_ticket/store.rb +40 -0
  31. data/lib/weixin_authorize/token/object_store.rb +25 -0
  32. data/lib/weixin_authorize/token/redis_store.rb +35 -0
  33. data/lib/weixin_authorize/token/store.rb +72 -0
  34. data/lib/weixin_authorize/version.rb +3 -0
  35. data/lib/weixin_authorize.rb +81 -0
  36. data/spec/1_fetch_access_token_spec.rb +43 -0
  37. data/spec/2_fetch_jsticket_spec.rb +10 -0
  38. data/spec/api/custom_spec.rb +58 -0
  39. data/spec/api/groups_spec.rb +54 -0
  40. data/spec/api/mass_spec.rb +70 -0
  41. data/spec/api/media_spec.rb +70 -0
  42. data/spec/api/medias/favicon.ico +0 -0
  43. data/spec/api/medias/ruby-logo.jpg +0 -0
  44. data/spec/api/menu_spec.rb +26 -0
  45. data/spec/api/qrcode_spec.rb +22 -0
  46. data/spec/api/template_spec.rb +40 -0
  47. data/spec/api/user_spec.rb +26 -0
  48. data/spec/spec_helper.rb +130 -0
  49. data/weixin_authorize.gemspec +34 -0
  50. metadata +202 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ddd647e674ab2c8f834c42540dee573fb95c5c333e0d19d8e9aa18ac2fb1a0c4
4
+ data.tar.gz: e8cbff4304ee920df15650f45f1bfa56c36bb4c043ec9c5eff2517afd43fb6a8
5
+ SHA512:
6
+ metadata.gz: bb8604f9768539c9518f156a07e349e7e90052e555c0c83d6eb80bf3331a82e20c3266a70ec2047e6f9128f6be96682e26ecf28c3787ffaad14ef358109db595
7
+ data.tar.gz: 680c307d76fe3c5c0faf6232ac43ba66afc197fe9c734da1bada9a76e4727f0830ed2826c43556dcc59b4b769557823e7e4dd9c5acedc1d5a8956639f2c79464
data/.coveralls.yml ADDED
@@ -0,0 +1,2 @@
1
+ service_name: travis-pro
2
+ repo_token: aAaaYkiZrS6MHUIbKFdM1b5EnevvVZ4MQ
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *DS_Store
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation --color spec --drb
2
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ bundler_args: --without development
3
+ rvm:
4
+ - 2.0.0
5
+ script:
6
+ - bundle exec rspec spec
7
+ services:
8
+ - redis
9
+ addons:
10
+ code_climate:
11
+ repo_token: c91fecbbd9e414e7cc3ad7a7d99207145de0ac65a3368de09e8c19295343d399
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source 'https://rubygems.org'
2
+
3
+ group :test, :development do
4
+ gem "rspec"
5
+ gem 'redis-namespace'
6
+ gem 'simplecov', '~> 0.7.1', :require => false
7
+ gem "codeclimate-test-reporter", require: nil
8
+ gem 'coveralls', require: false
9
+ # For debugger
10
+ gem "pry-rails"
11
+
12
+ gem "pry-byebug"
13
+ end
14
+
15
+ # Specify your gem's dependencies in weixin_authorize.gemspec
16
+ gemspec
17
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 lanrion
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # WeixinAuthorize
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/weixin_authorize.png)](http://badge.fury.io/rb/weixin_authorize)
4
+ [![Build Status](https://secure.travis-ci.org/lanrion/weixin_authorize.png?branch=master)](http://travis-ci.org/lanrion/weixin_authorize)
5
+ [![Code Climate](https://codeclimate.com/github/lanrion/weixin_authorize.png)](https://codeclimate.com/github/lanrion/weixin_authorize)
6
+ [![Coverage Status](https://codeclimate.com/github/lanrion/weixin_authorize/coverage.png)](https://codeclimate.com/github/lanrion/weixin_authorize)
7
+
8
+ Support using [Redis](http://redis.io) to store `access_token`
9
+
10
+ [Wiki](https://github.com/lanrion/weixin_authorize/wiki)
11
+
12
+ [Getting-Started](https://github.com/lanrion/weixin_authorize/wiki/Getting-Started)
13
+
14
+ [JS SDK](https://github.com/lanrion/weixin_authorize/wiki/js-sdk)
15
+
16
+ ## 已经完成API
17
+
18
+ * 客服消息
19
+ * 模板消息
20
+ * 用户分组管理
21
+ * 用户信息管理
22
+ * Oauth 2授权
23
+ * 二维码生成
24
+ * 自定义菜单
25
+ * 群发消息
26
+ * 多媒体管理
27
+ * JS SDK(ticket支持缓存)
28
+
29
+ ## V2.0开发中:
30
+ https://github.com/lanrion/weixin_authorize/milestones/v2.0-dev
31
+
32
+ 1. 重构API实现,调用方式
33
+ 2. 对token,ticket的管理,提供第三方开发灵活者自助化
34
+ 3. 尝试RestClient的弃用,选择更高效的HTTP client包
35
+ 4. 支持更多的异常处理机制
36
+
37
+ 注意:查看Wiki或者源代码时,请切换对应的版本来查看。Master处于不断更新完善分支。
38
+
39
+ ## How to test
40
+
41
+ Go to https://github.com/lanrion/weixin_authorize/issues/2, apply a weixin sandbox test account and follow this account
42
+
43
+ https://github.com/lanrion/weixin_authorize/blob/master/spec/spec_helper.rb
44
+
45
+ change your infos:
46
+
47
+ ```ruby
48
+ ENV["APPID"]="wxe371e0960de5426a"
49
+ ENV["APPSECRET"]="572b93d3d20aea242692a804243a141b"
50
+ ENV["OPENID"]="oEEoyuEasxionjR5HygmEOQGwRcw"
51
+ ```
52
+
53
+ then run `rspec .`
54
+
55
+ ## Contributing
56
+
57
+ 1. Fork it
58
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
59
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
60
+ 4. Push to the branch (`git push origin my-new-feature`)
61
+ 5. Create new Pull Request
62
+
63
+ ## 捐赠支持
64
+
65
+ 如果你觉得我的gem对你有帮助,欢迎打赏支持,:smile:
66
+
67
+ ![](https://raw.githubusercontent.com/lanrion/my_config/master/imagex/donation_me.png)
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,124 @@
1
+ # encoding: utf-8
2
+ module WeixinAuthorize
3
+ module Api
4
+ module Custom
5
+
6
+ # 发送文本消息
7
+ # {
8
+ # "touser":"OPENID",
9
+ # "msgtype":"text",
10
+ # "text":
11
+ # {
12
+ # "content":"Hello World"
13
+ # }
14
+ # }
15
+ def send_text_custom(to_user, content)
16
+ message = default_options(to_user).merge({text: {content: content}})
17
+ http_post(custom_base_url, message)
18
+ end
19
+
20
+ # 发送图片消息
21
+ # {
22
+ # "touser":"OPENID",
23
+ # "msgtype":"image",
24
+ # "image":
25
+ # {
26
+ # "media_id":"MEDIA_ID"
27
+ # }
28
+ # }
29
+ def send_image_custom(to_user, media_id)
30
+ message = default_options(to_user, "image").merge({image: {media_id: media_id}})
31
+ http_post(custom_base_url, message)
32
+ end
33
+
34
+ # 发送语音消息
35
+ # {
36
+ # "touser":"OPENID",
37
+ # "msgtype":"voice",
38
+ # "voice":
39
+ # {
40
+ # "media_id":"MEDIA_ID"
41
+ # }
42
+ # }
43
+ def send_voice_custom(to_user, media_id)
44
+ message = default_options(to_user, "voice").merge({voice: {media_id: media_id}})
45
+ http_post(custom_base_url, message)
46
+ end
47
+
48
+ # 发送视频消息
49
+ # {
50
+ # "touser":"OPENID",
51
+ # "msgtype":"video",
52
+ # "video":
53
+ # {
54
+ # "media_id":"MEDIA_ID"
55
+ # }
56
+ # }
57
+ def send_video_custom(to_user, media_id, options={})
58
+ video_options = {media_id: media_id}.merge(options)
59
+ message = default_options(to_user, "video").merge({video: video_options})
60
+ http_post(custom_base_url, message)
61
+ end
62
+
63
+ # 发送音乐消息
64
+ # {
65
+ # "touser":"OPENID",
66
+ # "msgtype":"music",
67
+ # "music":
68
+ # {
69
+ # "title":"MUSIC_TITLE",
70
+ # "description":"MUSIC_DESCRIPTION",
71
+ # "musicurl":"MUSIC_URL",
72
+ # "hqmusicurl":"HQ_MUSIC_URL",
73
+ # "thumb_media_id":"THUMB_MEDIA_ID"
74
+ # }
75
+ # }
76
+ def send_music_custom(to_user, media_id, musicurl, hqmusicurl, options={})
77
+ music_options = { thumb_media_id: media_id,
78
+ musicurl: musicurl,
79
+ hqmusicurl: hqmusicurl
80
+ }.merge(options)
81
+ message = default_options(to_user, "music").merge({music: music_options})
82
+ http_post(custom_base_url, message)
83
+ end
84
+
85
+ # 发送图文消息
86
+ # {
87
+ # "touser":"OPENID",
88
+ # "msgtype":"news",
89
+ # "news":{
90
+ # "articles": [
91
+ # {
92
+ # "title":"Happy Day",
93
+ # "description":"Is Really A Happy Day",
94
+ # "url":"URL",
95
+ # "picurl":"PIC_URL"
96
+ # },
97
+ # {
98
+ # "title":"Happy Day",
99
+ # "description":"Is Really A Happy Day",
100
+ # "url":"URL",
101
+ # "picurl":"PIC_URL"
102
+ # }
103
+ # ]
104
+ # }
105
+ # }
106
+ def send_news_custom(to_user, articles=[])
107
+ message = default_options(to_user, "news").merge({news: {articles: articles}})
108
+ http_post(custom_base_url, message)
109
+ end
110
+
111
+ private
112
+
113
+ # https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
114
+ def custom_base_url
115
+ "/message/custom/send"
116
+ end
117
+
118
+ def default_options(to_user, msgtype="text")
119
+ {touser: to_user, msgtype: msgtype}
120
+ end
121
+
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,8 @@
1
+ # encoding: utf-8
2
+ module WeixinAuthorize
3
+ module Api
4
+ module DataCube
5
+
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+ module WeixinAuthorize
3
+ module Api
4
+ module Groups
5
+
6
+ # 创建分组
7
+ # https://api.weixin.qq.com/cgi-bin/groups/create?access_token=ACCESS_TOKEN
8
+ def create_group(group_name)
9
+ create_url = "#{group_base_url}/create"
10
+ http_post(create_url, {group: {name: group_name}})
11
+ end
12
+
13
+ # 查询所有分组
14
+ # https://api.weixin.qq.com/cgi-bin/groups/get?access_token=ACCESS_TOKEN
15
+ def groups
16
+ groups_url = "#{group_base_url}/get"
17
+ http_get(groups_url)
18
+ end
19
+
20
+ # 查询用户所在分组
21
+ # https://api.weixin.qq.com/cgi-bin/groups/getid?access_token=ACCESS_TOKEN
22
+ def get_group_for(openid)
23
+ group_url = "#{group_base_url}/getid"
24
+ http_post(group_url, {openid: openid})
25
+ end
26
+
27
+ # 修改分组名
28
+ # https://api.weixin.qq.com/cgi-bin/groups/update?access_token=ACCESS_TOKEN
29
+ def update_group_name(group_id, new_group_name)
30
+ group_url = "#{group_base_url}/update"
31
+ http_post(group_url, {group: {id: group_id, name: new_group_name}})
32
+ end
33
+
34
+ # 移动用户分组
35
+ # https://api.weixin.qq.com/cgi-bin/groups/members/update?access_token=ACCESS_TOKEN
36
+ def update_group_for_openid(openid, to_groupid)
37
+ group_url = "#{group_base_url}/members/update"
38
+ http_post(group_url, {openid: openid, to_groupid: to_groupid})
39
+ end
40
+
41
+ private
42
+
43
+ def group_base_url
44
+ "/groups"
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,78 @@
1
+ # encoding: utf-8
2
+ module WeixinAuthorize
3
+ module Api
4
+ module Mass
5
+
6
+ MSG_TYPE = ["mpnews", "image", "text", "voice", "mpvideo"]
7
+
8
+ # media_info= {"media_id" media_id}
9
+ # https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token=ACCESS_TOKEN
10
+ def mass_with_group(group_id, media_info, msgtype="mpnews", is_to_all=false)
11
+ group_option = {"filter" => {"group_id" => group_id.to_s, "is_to_all" => is_to_all}}
12
+ media = generate_media(msgtype, media_info, group_option)
13
+
14
+ mass_url = "#{mass_base_url}/sendall"
15
+ http_post(mass_url, media)
16
+ end
17
+
18
+ # https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token=ACCESS_TOKEN
19
+ # if mpvideo,
20
+ # media_info= {"media_id" => media_id, "title" => "title", "description" => "description"}
21
+ def mass_with_openids(openids, media_info, msgtype="mpnews")
22
+ openid_option = {"touser" => openids}
23
+ media = generate_media(msgtype, media_info, openid_option)
24
+ mass_url = "#{mass_base_url}/send"
25
+ http_post(mass_url, media)
26
+ end
27
+
28
+ # 请注意,只有已经发送成功的消息才能删除删除消息只是将消息的图文详情页失效,已经收到的用户,还是能在其本地看到消息卡片。
29
+ # 另外,删除群发消息只能删除图文消息和视频消息,其他类型的消息一经发送,无法删除。
30
+ def mass_delete_with_msgid(msg_id)
31
+ mass_url = "#{mass_base_url}/delete"
32
+ http_post(mass_url, {"msg_id" => msg_id})
33
+ end
34
+
35
+ # 预览接口【订阅号与服务号认证后均可用】
36
+ def mass_preview(openid, media_info, msgtype="mpnews")
37
+ openid_option = {"touser" => openid}
38
+ media = generate_media(msgtype, media_info, openid_option)
39
+ mass_url = "#{mass_base_url}/preview"
40
+ http_post(mass_url, media)
41
+ end
42
+
43
+ # 查询群发消息发送状态【订阅号与服务号认证后均可用】
44
+ def mass_get_status(msg_id)
45
+ mass_url = "#{mass_base_url}/get"
46
+ http_post(mass_url, {"msg_id" => msg_id})
47
+ end
48
+
49
+ private
50
+
51
+ def mass_base_url
52
+ "/message/mass"
53
+ end
54
+
55
+ def generate_media(msgtype, media_info, option)
56
+ msgtype = msgtype.to_s
57
+ raise "#{msgtype} is a valid msgtype" if not MSG_TYPE.include?(msgtype)
58
+ {
59
+ msgtype => convert_media_info(msgtype, media_info),
60
+ "msgtype" => msgtype
61
+ }.merge(option)
62
+ end
63
+
64
+ # 如果用户填写的media信息,是字符串,则转换来符合的数据结构,如果 是hash,则直接使用用户的结构。
65
+ def convert_media_info(msgtype, media_info)
66
+ if media_info.is_a?(String)
67
+ if msgtype == "text"
68
+ return {"content" => media_info}
69
+ else
70
+ return {"media_id" => media_info}
71
+ end
72
+ end
73
+ media_info
74
+ end
75
+
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,136 @@
1
+ # encoding: utf-8
2
+
3
+ module WeixinAuthorize
4
+ module Api
5
+ module Media
6
+ # 上传多媒体文件
7
+ # http请求方式: POST/FORM
8
+ # http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
9
+ # 支持传路径或者文件类型
10
+ def upload_media(media, media_type)
11
+ file = process_file(media)
12
+ upload_media_url = "#{media_base_url}/upload"
13
+ http_post(upload_media_url, {media: file}, {type: media_type}, "file")
14
+ end
15
+
16
+ # 目前仅仅把下载链接返回给第三方开发者,由第三方开发者处理下载
17
+ def download_media_url(media_id)
18
+ download_media_url = WeixinAuthorize.endpoint_url("file", "#{media_base_url}/get")
19
+ params = URI.encode_www_form("access_token" => get_access_token,
20
+ "media_id" => media_id)
21
+ download_media_url += "?#{params}"
22
+ download_media_url
23
+ end
24
+
25
+ # 上传图文消息素材, 主要用于群发消息接口
26
+ # {
27
+ # "articles": [
28
+ # {
29
+ # "thumb_media_id":"mwvBelOXCFZiq2OsIU-p",
30
+ # "author":"xxx",
31
+ # "title":"Happy Day",
32
+ # "content_source_url":"www.qq.com",
33
+ # "content":"content",
34
+ # "digest":"digest"
35
+ # },
36
+ # {
37
+ # "thumb_media_id":"mwvBelOXCFZiq2OsIU-p",
38
+ # "author":"xxx",
39
+ # "title":"Happy Day",
40
+ # "content_source_url":"www.qq.com",
41
+ # "content":"content",
42
+ # "digest":"digest"
43
+ # }
44
+ # ]
45
+ # }
46
+ # Option: author, content_source_url
47
+ def upload_mass_news(news=[])
48
+ upload_news_url = "#{media_base_url}/uploadnews"
49
+ http_post(upload_news_url, {articles: news})
50
+ end
51
+
52
+ # media_id: 需通过基础支持中的上传下载多媒体文件来得到
53
+ # https://file.api.weixin.qq.com/cgi-bin/media/uploadvideo?access_token=ACCESS_TOKEN
54
+
55
+ # return:
56
+ # {
57
+ # "type":"video",
58
+ # "media_id":"IhdaAQXuvJtGzwwc0abfXnzeezfO0NgPK6AQYShD8RQYMTtfzbLdBIQkQziv2XJc",
59
+ # "created_at":1398848981
60
+ # }
61
+ def upload_mass_video(media_id, title="", desc="")
62
+ video_msg = {
63
+ "media_id" => media_id,
64
+ "title" => title,
65
+ "description" => desc
66
+ }
67
+
68
+ http_post("#{media_base_url}/uploadvideo", video_msg)
69
+ end
70
+
71
+ private
72
+
73
+ def media_base_url
74
+ "/media"
75
+ end
76
+
77
+ def process_file(media)
78
+ return media if media.is_a?(File) && jpep?(media)
79
+
80
+ media_url = media
81
+ uploader = WeixinUploader.new
82
+
83
+ if http?(media_url) # remote
84
+ uploader.download!(media_url.to_s)
85
+ else # local
86
+ media_file = media.is_a?(File) ? media : File.new(media_url)
87
+ uploader.cache!(media_file)
88
+ end
89
+ file = process_media(uploader)
90
+ CarrierWave.clean_cached_files! # clear last one day cache
91
+ file
92
+ end
93
+
94
+ def process_media(uploader)
95
+ uploader = covert(uploader)
96
+ uploader.file.to_file
97
+ end
98
+
99
+ # JUST ONLY FOR JPG IMAGE
100
+ def covert(uploader)
101
+ # image process
102
+ unless (uploader.file.content_type =~ /image/).nil?
103
+ if !jpep?(uploader.file)
104
+ require "mini_magick"
105
+ # covert to jpeg
106
+ image = MiniMagick::Image.open(uploader.path)
107
+ image.format("jpg")
108
+ uploader.cache!(File.open(image.path))
109
+ image.destroy! # remove /tmp from MinMagick generate
110
+ end
111
+ end
112
+ uploader
113
+ end
114
+
115
+ def http?(uri)
116
+ return false if !uri.is_a?(String)
117
+ uri = URI.parse(uri)
118
+ uri.scheme =~ /^https?$/
119
+ end
120
+
121
+ def jpep?(file)
122
+ content_type = if file.respond_to?(:content_type)
123
+ file.content_type
124
+ else
125
+ content_type(file.path)
126
+ end
127
+ !(content_type =~ /jpeg/).nil?
128
+ end
129
+
130
+ def content_type(media_path)
131
+ MIME::Types.type_for(media_path).first.content_type
132
+ end
133
+
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+ module WeixinAuthorize
3
+ module Api
4
+ module Menu
5
+
6
+ # 自定义菜单查询接口
7
+ # https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN
8
+ def menu
9
+ get_menu_url = "#{menu_base_url}/get"
10
+ http_get(get_menu_url)
11
+ end
12
+
13
+ # 自定义菜单删除接口
14
+ # https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN
15
+ def delete_menu
16
+ delete_menu_url = "#{menu_base_url}/delete"
17
+ http_get(delete_menu_url)
18
+ end
19
+
20
+ # 自定义菜单创建接口
21
+ # https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN
22
+ def create_menu(menu)
23
+ menu = JSON.load(menu) if menu.is_a?(String)
24
+ create_menu_url = "#{menu_base_url}/create"
25
+ http_post(create_menu_url, menu)
26
+ end
27
+
28
+ private
29
+
30
+ def menu_base_url
31
+ "/menu"
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+ module WeixinAuthorize
3
+ module Api
4
+ module Oauth
5
+
6
+ # 应用授权作用域: scope
7
+ # snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),
8
+ # snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息)
9
+ # default is snsapi_base
10
+ # state 重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值
11
+
12
+ # 如果用户点击同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE。若用户禁止授权,则重定向后不会带上code参数,仅会带上state参数redirect_uri?state=STATE
13
+ def authorize_url(redirect_uri, scope="snsapi_base", state="weixin")
14
+ require "erb"
15
+ redirect_uri = ERB::Util.url_encode(redirect_uri)
16
+ WeixinAuthorize.open_endpoint("/connect/oauth2/authorize?appid=#{app_id}&redirect_uri=#{redirect_uri}&response_type=code&scope=#{scope}&state=#{state}#wechat_redirect")
17
+ end
18
+
19
+ # 首先请注意,这里通过code换取的网页授权access_token,与基础支持中的access_token不同。公众号可通过下述接口来获取网页授权access_token。如果网页授权的作用域为snsapi_base,则本步骤中获取到网页授权access_token的同时,也获取到了openid,snsapi_base式的网页授权流程即到此为止。
20
+
21
+ # 微信通过请求 #authorize_url 方法后,会返回一个code到redirect_uri中
22
+ def get_oauth_access_token(code)
23
+ WeixinAuthorize.http_get_without_token("/sns/oauth2/access_token?appid=#{app_id}&secret=#{app_secret}&code=#{code}&grant_type=authorization_code", {}, "api")
24
+ end
25
+
26
+ # refresh_token: 填写通过access_token获取到的refresh_token参数
27
+ def refresh_oauth2_token(refresh_token)
28
+ WeixinAuthorize.http_get_without_token("/sns/oauth2/refresh_token?appid=#{app_id}&grant_type=refresh_token&refresh_token=#{refresh_token}", {}, "api")
29
+ end
30
+
31
+ # 如果网页授权作用域为snsapi_userinfo,则此时开发者可以通过access_token和openid拉取用户信息了。
32
+ def get_oauth_userinfo(openid, oauth_token, lang="zh_CN")
33
+ WeixinAuthorize.http_get_without_token("/sns/userinfo?access_token=#{oauth_token}&openid=#{openid}&lang=#{lang}", {}, "api")
34
+ end
35
+
36
+ end
37
+ end
38
+ end