#coding=utf-8 class WechatsController < ActionController::Base wechat_responder include ApplicationHelper # default text responder when no other match on :text do |request, content| request.reply.text "您的意见已收到" # Just echo end # When receive 'help', will trigger this responder on :text, with: 'help' do |request| request.reply.text 'help content' end # When receive 'news', will match and will got count as as parameter on :text, with: /^(\d+) news$/ do |request, count| # Wechat article can only contain max 10 items, large than 10 will dropped. news = (1..count.to_i).each_with_object([]) { |n, memo| memo << { title: 'News title', content: "No. #{n} news content" } } request.reply.news(news) do |article, n, index| # article is return object article.item title: "#{index} #{n[:title]}", description: n[:content], pic_url: 'http://www.baidu.com/img/bdlogo.gif', url: 'http://www.baidu.com/' end end on :event, with: 'subscribe' do |request| default_msg(request) end # When unsubscribe user scan qrcode qrscene_xxxxxx to subscribe in public account # notice user will subscribe public account at same time, so wechat won't trigger subscribe event any more on :scan, with: 'qrscene_xxxxxx' do |request, ticket| request.reply.text "Unsubscribe user #{request[:FromUserName]} Ticket #{ticket}" end # When subscribe user scan scene_id in public account on :scan, with: 'scene_id' do |request, ticket| request.reply.text "Subscribe user #{request[:FromUserName]} Ticket #{ticket}" end # When no any on :scan responder can match subscribe user scaned scene_id on :event, with: 'scan' do |request| if request[:EventKey].present? request.reply.text "event scan got EventKey #{request[:EventKey]} Ticket #{request[:Ticket]}" end end # When enterprise user press menu BINDING_QR_CODE and success to scan bar code on :scan, with: 'BINDING_QR_CODE' do |request, scan_result, scan_type| request.reply.text "User #{request[:FromUserName]} ScanResult #{scan_result} ScanType #{scan_type}" end # Except QR code, wechat can also scan CODE_39 bar code in enterprise account on :scan, with: 'BINDING_BARCODE' do |message, scan_result| if scan_result.start_with? 'CODE_39,' message.reply.text "User: #{message[:FromUserName]} scan barcode, result is #{scan_result.split(',')[1]}" end end # When user click the menu button on :click, with: 'BOOK_LUNCH' do |request, key| request.reply.text "User: #{request[:FromUserName]} click #{key}" end # When user view URL in the menu button on :view, with: 'http://wechat.somewhere.com/view_url' do |request, view| request.reply.text "#{request[:FromUserName]} view #{view}" end # When user sent the imsage on :image do |request| request.reply.image(request[:MediaId]) # Echo the sent image to user end # When user sent the voice on :voice do |request| request.reply.voice(request[:MediaId]) # Echo the sent voice to user end # When user sent the video on :video do |request| nickname = wechat.user(request[:FromUserName])['nickname'] # Call wechat api to get sender nickname request.reply.video(request[:MediaId], title: 'Echo', description: "Got #{nickname} sent video") # Echo the sent video to user end # When user sent location on :location do |request| request.reply.text("Latitude: #{message[:Latitude]} Longitude: #{message[:Longitude]} Precision: #{message[:Precision]}") end on :event, with: 'unsubscribe' do |request| request.reply.success # user can not receive this message end # When user enter the app / agent app on :event, with: 'enter_agent' do |request| request.reply.text "#{request[:FromUserName]} enter agent app now" end # When batch job create/update user (incremental) finished. on :batch_job, with: 'sync_user' do |request, batch_job| request.reply.text "sync_user job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}" end # When batch job replace user (full sync) finished. on :batch_job, with: 'replace_user' do |request, batch_job| request.reply.text "replace_user job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}" end # When batch job invent user finished. on :batch_job, with: 'invite_user' do |request, batch_job| request.reply.text "invite_user job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}" end # When batch job replace department (full sync) finished. on :batch_job, with: 'replace_party' do |request, batch_job| request.reply.text "replace_party job #{batch_job[:JobId]} finished, return code #{batch_job[:ErrCode]}, return message #{batch_job[:ErrMsg]}" end # Any not match above will fail to below on :fallback, respond: 'fallback message' on :click, with: 'FEEDBACK' do |request, key| request.reply.text "如有反馈问题,请直接切入至输入框,发微信给我们即可" end on :click, with: 'MY_NEWS' do |request, key| default_msg(request) end def default_msg(request) uw = user_binded?(request[:FromUserName]) if uw && uw.user ua = user_activity(uw.user) logo = "http://wechat.trustie.net/images/trustie_logo2.png" i = 0 news =[] ua.each do |a| i += 1 activity = process_activity(a) if activity news << {title: activity[0], content: activity[1], picurl: "#{i == 1 ? logo : 'https://www.trustie.net/'+activity[2]}", url: activity[3] } end end request.reply.news(news) do |article, n, index| # article is return object article.item title: "#{n[:content]}", description: n[:title], pic_url: "#{n[:picurl]}", url: n[:url] end else sendBind(request) end end def sendBind(request) news = (1..1).each_with_object([]) { |n, memo| memo << { title: '绑定登录', content: "您还未绑定确实的用户,请先绑定." } } request.reply.news(news) do |article, n, index| # article is return object url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=#{Wechat.config.appid}&redirect_uri=#{login_wechat_url}&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect" article.item title: "#{n[:title]}", description: n[:content], pic_url: 'http://wechat.trustie.net/images/trustie_logo2.png', url: url end end def get_open_id begin raise "非法操作, code不存在" unless params[:code] openid = get_openid_from_code(params[:code]) raise "无法获取到openid" unless openid render :json => {status:0, openid: openid} rescue Exception=>e render :json => {status: -1, msg: e.message} end end def bind begin raise "非法操作, code不存在" unless params[:code] openid = get_openid_from_code(params[:code]) raise "无法获取到openid" unless openid raise "此微信号已绑定用户, 不能得复绑定" if user_binded?(openid) user, last_login_on = User.try_to_login(params[:username], params[:password]) raise "用户名或密码错误,请重新登录" unless user #补全用户信息 raise "此用户已经绑定了公众号" if user.user_wechat UserWechat.create!( openid: openid, user: user ) render :json => {status:0, msg: "绑定成功"} rescue Exception=>e render :json => {status: -1, msg: e.message} end end def login @code = params[:code] #TODO 安全性 render 'wechats/login', layout: 'base_wechat' end private def get_openid_from_code(code) url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=#{Wechat.config.appid}&secret=#{Wechat.config.secret}&code=#{code}&grant_type=authorization_code" logger.debug url body = URI.parse(url).read logger.debug body JSON.parse(body)["openid"] end def user_binded?(openid) uw = UserWechat.where(openid: openid).first end def user_activity(user) @user = user shield_project_ids = ShieldActivity.where("container_type='User' and container_id=#{@user.id} and shield_type='Project'").map(&:shield_id) shield_course_ids = ShieldActivity.where("container_type='User' and container_id=#{@user.id} and shield_type='Course'").map(&:shield_id) @page = params[:page] ? params[:page].to_i + 1 : 0 user_project_ids = (@user.projects.visible.map{|project| project.id}-shield_project_ids).empty? ? "(-1)" : "(" + (@user.projects.visible.map{|project| project.id}-shield_project_ids).join(",") + ")" user_course_ids = (@user.courses.visible.map{|course| course.id}-shield_course_ids).empty? ? "(-1)" : "(" + (@user.courses.visible.map{|course| course.id}-shield_course_ids).join(",") + ")" course_types = "('Message','News','HomeworkCommon','Poll','Course')" project_types = "('Message','Issue','ProjectCreateInfo')" principal_types = "JournalsForMessage" blog_ids = "("+@user.blog.id.to_s+","+((User.watched_by(@user.id).count == 0 )? '0' :User.watched_by(@user.id).map{|u| u.blog.id}.join(','))+")" @user_activities = UserActivity.where("(container_type = 'Project' and container_id in #{user_project_ids} and act_type in #{project_types})" + "or (container_type = 'Course' and container_id in #{user_course_ids} and act_type in #{course_types}) "+ "or (container_type = 'Principal' and act_type= '#{principal_types}' and container_id = #{@user.id}) " + "or (container_type = 'Blog' and act_type= 'BlogComment' and container_id in #{blog_ids})").order('updated_at desc').limit(10).offset(@page * 10) end def process_activity(user_activity) act= user_activity.act case user_activity.container_type.to_s when 'Course' when 'Project' case user_activity.act_type.to_s when 'Issue' [act.project.name.to_s+" | 项目问题", act.subject.to_s, url_to_avatar(act.author),"http://wechat.trustie.net/app.html#/issue/#{act.id}"] end end end end