# coding: utf-8 require 'cgi' require 'rails' require 'active_model' require 'active_record' require 'active_support' require 'blsm-mp-wx/version' require 'blsm-mp-wx/model/active_record' require 'blsm-mp-wx/model/vd_mp_wx' require 'blsm-mp-wx/model/vd_mp_msg' require 'json' require 'faraday' module BlsmMpWx ERROR_CODES = { 404 => {code: 404, msg: '未知的公众号,如有疑问,请联系xi.liu@abcomb.com'} } class << self attr_accessor :APP_ID attr_accessor :APP_ID_2 #根据app_id获取access_token #系统会根据当前的access_token即过期时间,自动更新并返回 #开发者无需关心这里的access_token怎么更新 #===Parameters # * +app_id+ -公众号的appid def access_token(app_id=nil) app_id ||= self.APP_ID app = VdMpWx.where(app_id: app_id).first return nil unless app return app.access_token unless app.access_token_expired? #没有过期,直接返回 response = Faraday.new(:url => 'https://api.weixin.qq.com').get do |req| req.url '/cgi-bin/token' req.params[:appid] = app.app_id req.params[:secret] = app.app_secret req.params[:grant_type] = 'client_credential' end json_obj = parse_json(response.body) return nil unless json_obj return nil unless json_obj.has_key?('access_token') access_token = json_obj['access_token'] app.save_access_token(access_token, json_obj['expires_in']) access_token end #获取jsapi全局唯一票据 def js_api_ticket(app_id=nil) app_id ||= self.APP_ID access_token = access_token(app_id) app = VdMpWx.where(app_id: app_id).first return nil unless access_token return nil unless app return app.js_api_ticket unless app.js_api_ticket_expired? #没有过期,直接返回 response = Faraday.new(:url => 'https://api.weixin.qq.com').get do |req| req.url '/cgi-bin/ticket/getticket' req.params[:access_token] = access_token req.params[:type] = 'jsapi' end json_obj = parse_json(response.body) return nil unless json_obj return nil unless json_obj.has_key?('ticket') ticket = json_obj['ticket'] app.save_js_api_ticket(ticket, json_obj['expires_in']) ticket end #发送普通消息 #文本消息: # { # "touser":"OPENID", # "msgtype":"text", # "text": # { # "content":"Hello World" # } # } #图文消息: # { # "touser":"OPENID", # "msgtype":"news", # "news": # { # "articles": [ # { # "title":"Happy Day", # "description":"Is Really A Happy Day", # "url":"URL", # "picurl":"PIC_URL" # }, # { # "title":"Happy Day", # "description":"Is Really A Happy Day", # "url":"URL", # "picurl":"PIC_URL" # } # ] # } # } def send_msg(app_id=nil, openid, msg) app_id ||= self.APP_ID access_token = access_token(app_id) return nil unless access_token return nil unless openid return nil unless msg[:touser]==openid response = Faraday.new(:url => 'https://api.weixin.qq.com').post do |req| req.url '/cgi-bin/message/custom/send' req.params[:access_token] = access_token req.headers['Content-Type'] = 'application/json' req.body = msg.to_json req end json_obj = parse_json(response.body) return nil unless json_obj json_obj['errcode']==0 end #JSAPI签名package def js_api_sign_package(app_id=nil, url) app_id ||= self.APP_ID ticket = js_api_ticket(app_id) timestamp = Time.new.to_i nonce_str = Digest::MD5.hexdigest(Time.new.to_i.to_s + Random.rand(99999).to_s) string = "jsapi_ticket=#{ticket}&noncestr=#{nonce_str}×tamp=#{timestamp}&url=#{url}" signature = Digest::SHA1.hexdigest(string) { appId: app_id, nonceStr: nonce_str, timestamp: timestamp, url: url, signature: signature, rawString: string } end #获取用户的基本信息(包括UnionID机制) def gen_wx_user_info(app_id=nil, openid) app_id ||= self.APP_ID access_token = access_token(app_id) return nil unless access_token response = Faraday.new(:url => 'https://api.weixin.qq.com').get do |req| req.url '/cgi-bin/user/info' req.params[:openid] = openid req.params[:access_token] = access_token end json_obj = parse_json(response.body) puts "#{json_obj}" return nil unless json_obj return json_obj.inject({}) { |memo, (key, v)| memo[key.to_s.to_sym]=v; memo } if json_obj.has_key?('openid') nil end #生成永久二维码ticket def gen_forever_qr_ticket(app_id=nil, scene_id) app_id ||= self.APP_ID access_token = access_token(app_id) return nil unless access_token response = Faraday.new(:url => 'https://api.weixin.qq.com').post do |req| req.url '/cgi-bin/qrcode/create' req.params[:access_token] = access_token req.body="{\"action_name\": \"QR_LIMIT_SCENE\", \"action_info\": {\"scene\": {\"scene_id\": #{scene_id}}}}" end json_obj = parse_json(response.body) return nil unless json_obj return nil unless json_obj.has_key?('ticket') json_obj['ticket'] end #长链接转短连接 def gen_short_url(app_id=nil, long_url) app_id ||= self.APP_ID access_token = access_token(app_id) return nil unless access_token response = Faraday.new(:url => 'https://api.weixin.qq.com').post do |req| req.url '/cgi-bin/shorturl' req.headers['Content-Type'] = 'application/json' data = { action: 'long2short', long_url: long_url } req.params[:long_url] = long_url req.params[:access_token] = access_token req.body = data.to_json end json_obj = parse_json(response.body) return nil unless json_obj return nil unless json_obj.has_key?('short_url') json_obj['short_url'] end #创建消息,存储到消息队列中 #====Parameters # * +app_id+ - 公众号的唯一标识 # * +openid+ - 发送给用户的openid # * +content+ - 消息内容 # * +msg_name+ - 消息种类:new_order(新订单通知)、balance(结算通知)、score_change(积分变动通知)、custom(普通消息) # new_order => content: {touser:'openid',order_id:''} 系统自动优先使用模板消息发送通知 # balance => content: {touser:'openid',clearing_id} 系统自动优先使用模板消息发送通知 # score_change => content: {touser:'',change:5,total:25,content:'邀请他人。。。。'} def create_msg(app_id=nil, openid, content, msg_name) app_id ||= self.APP_ID return nil unless openid return nil unless content[:touser]==openid return nil unless %w(new_order balance score_change custom).include?(msg_name) VdMpMsg.create({ app_id: app_id, openid: openid, content: content.to_json, msg_name: msg_name, template: %w(new_order balance score_change).include?(msg_name), status: 'none' }) end private #解析json类型的数据,并将最后的数据转为hash或array # +json_data_str+ 要转换的json数据 def parse_json(json_data_str) begin return JSON.parse(json_data_str) rescue end nil end end end