module Sinatra::Wechat::Endpoint

Public Instance Methods

wechat(endpoint = '/', wechat_token: '', validate_msg: true, &block) click to toggle source
# File lib/sinatra/wechat.rb, line 35
def wechat(endpoint = '/', wechat_token: '', validate_msg: true, &block)
  # XXX: 'before' doesn't work in Padrino framework
  # seems like Padrino has redefined before, and make it incompatible with original one
  # use a proc instead.
  validation = Proc.new {
    if validate_msg then
      raw = [wechat_token, params[:timestamp], params[:nonce]].compact.sort.join
      halt 403 unless Digest::SHA1.hexdigest(raw) == params[:signature]
    end
  }

  get endpoint do
    instance_eval &validation
    content_type 'text/plain'
    params[:echostr]
  end

  dispatcher = DispatcherBuilder.new(&block)

  post endpoint do
    instance_eval &validation

    body = request.body.read || ""
    halt 400 if body.empty?  # bad request, cannot handle this kind of message

    xmldoc = Nokogiri::XML(body).root
    values = xmldoc.element_children.each_with_object(Hash.new) do |e, v|
      name = e.name.gsub(/(.)([A-Z])/,'\1_\2').downcase
      # rename 'Location_X' to 'location__x' then to 'location_x'
      name = name.gsub(/(_{2,})/,'_')
      v[name.to_sym] = e.content
    end
    _, handler = dispatcher.dispatch!(values)
    halt 404 unless handler

    request[:wechat_values] = values
    instance_eval(&handler)
  end
  self
end