How use sessions with Whats app cloud api? - ruby

Need to build chat bot with whatsapp, so i use Whats app cloud api + Sinatrarb.
When i need to send the session its sends perfectually, but its doesnt work
class WhatsAppSender < Sinatra::Base
configure :development do
register Sinatra::Reloader
enable :sessions
set :session_secret, "secret"
set :session_store, Rack::Session::Pool
end
configure do
enable :sessions
set :session_secret, "secret"
set :session_store, Rack::Session::Pool
end
post '/bot' do
request.body.rewind
body = JSON.parse request.body.read
# puts body
puts session[:answer]
if body['entry'][0]['changes'][0]['value'].include?("messages")
user_text = body['entry'][0]['changes'][0]['value']['messages'][0]['text']['body']
case
when user_text == "hi"
# puts session[:answer]
response = HTTP.auth("Bearer mytoken")
.headers(:accept => "application/json")
.post("https://graph.facebook.com/v14.0/myid/messages",
:json => { messaging_product: "whatsapp",
recipient_type: "individual",
to: "mynumber",
type: "text",
some_text: "some text",
text: { preview_url:
false,
body: "hi man"}
})
session[:answer] = "booking_amount"
puts response
when session[:answer] == "booking_amount"
puts "session works"
when user_text.downcase == "d"
session.clear
puts "cleared"
end
end
end
end
then i inspect request, sinatra session works fine, set the cookie
Set-Cookie rack.session=BAh7CEkiD3Nlc3Npb25faWQGOgZFVG86HVJhY2s6OlNlc3Npb246OlNlc3Npb25JZAY6D0BwdWJsaWNfaWRJIkViNThiYmJjMjdmYjI4MGU0ZTMxMDY4NzE4MDllOWVhYTBlNTVlM2UwMjg4ZWE3OWRiMjVmYTlkNThmZjczNzI3BjsARkkiCWNzcmYGOwBGSSIxbEJydTFnUm5tSTVCOVZUT1pZelNwSFY3a3ZUNGxiVmVHS2FlZVFvYVJsOD0GOwBGSSINdHJhY2tpbmcGOwBGewZJIhRIVFRQX1VTRVJfQUdFTlQGOwBUSSItNDJiNzI3MTFjNTdmZDA5YTk1MjY0NmY0N2Q0YWJjMjk0ODk5OTZhMQY7AEY%3D--f88a49537f00d65faf60da839b05d847d47f288d; path=/; HttpOnly
But its doesn't work... Maybe i should use another language or framework? please help.

Related

Sent emails with Action Mailer

I am trying to send an email to example#gmail.com with Action Mailer (Ruby on Rails). The method sendactivation is correctly executed and the message "Email sent" is displayed. However, I never receive any email. Actually, the output "Test" is never printed. My webapp is hosted on Heroku Cedar-10.
class UsersController < ApplicationController
def sendactivation
UserMailer.welcome_email()
render :json => {
:result => "Email sent"
}
end
end
end
class UserMailer < ActionMailer::Base
def welcome_email()
mail(to: "example#gmail.com",
body: "Hello",
content_type: "text/html",
subject: "Already rendered!")
puts "Test"
end
end
This is the configuration I have on my config/environment/production.rb. Actually I wanted to send it with Office 365 but I suppose it is easier to debug with a Gmail account.
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: 'smtp.gmail.com',
port: 587,
user_name: 'example#gmail.com',
password: '########',
authentication: 'plain',
enable_starttls_auto: true }
What am I doing wrong? Is there anything I need to change on my Gmail configuration?
ANSWER: In addition to the marked answer, I needed to set the "from" address in the welcome_email method.
Call method deliver:
UserMailer.welcome_email.deliver
UserMailer.welcome_email.deliver_now
From the Rails Guide: See section 2.1.4
class SendWeeklySummary
  def run
    User.find_each do |user|
      UserMailer.weekly_summary(user).deliver_now
    end
  end
end

How to test the request (not response) of a Rack middleware?

I can see how to test the response of a rack middleware, but how to test the request?
That is, how to test when the middleware changes the request going to the app?
Working in RSpec and Sinatra.
I presume you're meaning testing whether it's changing env...
A middleware goes something like:
class Foo
def initialize(app)
#app = app
end
def call(env)
# do stuff with env ...
status, headers, response = #app.call(env)
# do stuff with status, headers and response
[status, headers, response]
end
end
You could initialize it with a bogus app (or a lambda, for that matter) that returns a dummy response after doing some tests:
class FooTester
attr_accessor :env
def call(env)
# check that env == #env and whatever else you need here
[200, {}, '']
end
end
#Denis's answer would work, but I'd personally prefer an alternative, which is to put the middleware in a bare Rack app (be it Sinatra or whatever) and just pass the request on as the response and test that. It's how most Rack middleware is specced. That, and unit testing the internals of the middleware.
For example, it's what I've done here with a fork of Rack Clicky
Edit: testing middleware separately from the main app.
require 'lib/rack/mymiddelware.rb'
require 'sinatra/base'
describe "My Middleware" do
let(:app) {
Sinatra.new do
use MyMiddleware
get('/') { request.env.inspect }
end
}
let(:expected) { "Something you expect" }
before do
get "/"
end
subject { last_response.body }
it { should == expected }
end

Standardizing api responses in a modular Sinatra application

I'm developing an api as a modular Sinatra web application and would like to standardize the responses that are returned without having to do so explicitly. I thought this could be achieved by using middleware but it fails in most scenarios. The below sample application is what I have so far.
config.ru
require 'sinatra/base'
require 'active_support'
require 'rack'
class Person
attr_reader :name, :surname
def initialize(name, surname)
#name, #surname = name, surname
end
end
class MyApp < Sinatra::Base
enable :dump_errors, :raise_errors
disable :show_exceptions
get('/string') do
"Hello World"
end
get('/hash') do
{"person" => { "name" => "john", "surname" => "smith" }}
end
get('/array') do
[1,2,3,4,5,6,7, "232323", '3245235']
end
get('/object') do
Person.new('simon', 'hernandez')
end
get('/error') do
raise 'Failure of some sort'
end
end
class ResponseMiddleware
def initialize(app)
#app = app
end
def call(env)
begin
status, headers, body = #app.call(env)
response = {'status' => 'success', 'data' => body}
format(status, headers, response)
rescue ::Exception => e
response = {'status' => 'error', 'message' => e.message}
format(500, {'Content-Type' => 'application/json'}, response)
end
end
def format(status, headers, response)
result = ActiveSupport::JSON.encode(response)
headers["Content-Length"] = result.length.to_s
[status, headers, result]
end
end
use ResponseMiddleware
run MyApp
Examples (in JSON):
/string
Expected: {"status":"success","data":"Hello World"}
Actual: {"status":"success","data":["Hello World"]}
/hash (works)
Expected: {"status":"success","data":{"person":{"name":"john","surname":"smith"}}}
Actual: {"status":"success","data":{"person":{"name":"john","surname":"smith"}}}
/array
Expected: {"status":"success","data": [1,2,3,4,5,6,7,"232323","3245235"]}
Actual: {"status":"error","message":"wrong number of arguments (7 for 1)"}
/object
Expected: {"status":"success","data":{"name":"simon","surname":"hernandez"}}
Actual: {"status":"success","data":[]}
/error (works)
Expected: {"status":"error","message":"Failure of some sort"}
Actual: {"status":"error","message":"Failure of some sort"}
If you execute the code, you will see that /hash and /error give back the required responses, but the rest do not. Ideally, I would not like to change anything in the MyApp class. It's currently being built on top of Sinatra 1.3.3, ActiveSupport 3.2.9 and Rack 1.4.1.
With some help from #sinatra on irc.freenode.org, I managed to get it down to what I want. I added the following to MyApp:
def route_eval
result = catch(:halt) { super }
throw :halt, {"result" => result}
end
I then changed the following line in ResponseMiddleware:
response = {'status' => 'success', 'data' => body}
to
response = {'status' => 'success', 'data' => body["result"]}
and all my test cases passed.

Accessing an EventMachine channel from a Sinatra route

I have a simple Sinatra App running on EventMachine, like this example.
The app is working, now I'd like to allow the routes I'm defining in Sinatra to access the websocket using the EventMachine channel that is created. I naively tried the following, but of course within the Sinatra App, the #channel variable isn't defined, so this doesn't work.
require 'em-websocket'
require 'sinatra'
EventMachine.run do
#channel = EM::Channel.new
class App < Sinatra::Base
get '/' do
erb :index
end
post '/test' do
#channel.push "Post request hit endpoint"
status 200
end
end
EventMachine::WebSocket.start :host => '0.0.0.0', :port => 8080 do |socket|
socket.onopen do
sid = #channel.subscribe { |msg| socket.send msg }
#channel.push "Subscriber ID #{sid} connected!"
socket.onmessage do |msg|
#channel.push "Subscriber <#{sid}> sent message: #{msg}"
end
socket.onclose do
#channel.unsubscribe(sid)
end
end
end
App.run! :port => 3000
end
How could I access the EventMachine channel I've got open within my Sinatra app?
In case others don't know what we're talking about in the comments, here's an example of using a class instance variable in the way I suggested. This runs, but I don't know if it does what's expected:
require 'em-websocket'
require 'sinatra'
require 'haml'
module Example
def self.em_channel
#em_channel ||= EM::Channel.new
end
EventMachine.run do
class App < Sinatra::Base
configure do
enable :inline_templates
end
get '/' do
haml :index
end
get '/test' do
Example.em_channel.push "Test request hit endpoint"
status 200
end
end
EventMachine::WebSocket.start :host => '0.0.0.0', :port => 8080 do |socket|
socket.onopen do
sid = Example.em_channel.subscribe { |msg| socket.send msg }
Example.em_channel.push "Subscriber ID #{sid} connected!"
socket.onmessage do |msg|
Example.em_channel.push "Subscriber <#{sid}> sent message: #{msg}"
end
socket.onclose do
Example.em_channel.unsubscribe(sid)
end
end
end
App.run!
end
end
__END__
## layout
%html
= yield
## index
%div.title Hello world.

Thin, Sinatra, and intercepting static file request to do CAS authentication

I'm using the casrack-the-authenticator gem for CAS authentication. My server is running Thin on top of Sinatra. I've gotten the CAS authentication bit working, but I'm not sure how to tell Rack to intercept "/index.html" requests to confirm the CAS login, and if the user is not allowed to view the page, return a HTTP 403 response instead of serving the actual page. Does anyone have experience with this? Thanks.
My app:
class Foo < Sinatra::Base
enable :sessions
set :public, "public"
use CasrackTheAuthenticator::Simple, :cas_server => "https://my.cas_server.com"
use CasrackTheAuthenticator::RequireCAS
get '/' do
puts "Hello World"
end
end
My rackup file:
require 'foo'
use Rack::CommonLogger
use Rack::Lint
run Foo
Initial attempt at getting Rack to understand authentication in its file service (comments and thoughts welcome):
builder = Rack::Builder.new do
map '/foo/index.html' do
run Proc.new { |env|
user = Rack::Request.new(env).session[CasrackTheAuthenticator::USERNAME_PARAM]
[401, { "Content-Type" => "text/html" }, "CAS Authentication Required"] unless user
# Serve index.html because we detected user
}
end
map '/foo' do
run Foo
end
end
run builder
Casrack-the-Authenticator will put the CAS information into the Rack session. You can pull that out in another piece of Rack middleware or in your Sinatra app.
The following is for a Rails application, but the concept is similar for Sinatra or a Rack middleware:
# in app/controllers/application_controller.rb:
protected
def require_sign_in!
render :nothing => true, :status => 403 unless signed_in?
end
def signed_in?
current_user.present?
end
def current_user
#current_user ||= Person.find_by_username(session[CasrackTheAuthenticator::USERNAME_PARAM])
end

Resources