зеркало из
https://github.com/glebtv/telegram-bot.git
synced 2026-09-08 03:45:52 +03:00
Sessions for UpdatesController
Этот коммит содержится в:
34
README.md
34
README.md
@@ -94,7 +94,7 @@ bot.get_me.class # => Telegram::Bot::Types::User
|
|||||||
```ruby
|
```ruby
|
||||||
class Telegram::WebhookController < Telegram::Bot::UpdatesController
|
class Telegram::WebhookController < Telegram::Bot::UpdatesController
|
||||||
# use callbacks like in any other controllers
|
# use callbacks like in any other controllers
|
||||||
around_action :set_locale
|
around_action :with_locale
|
||||||
|
|
||||||
# Every update can have one of: message, inline_query & chosen_inline_result.
|
# Every update can have one of: message, inline_query & chosen_inline_result.
|
||||||
# Define method with same name to respond to this updates.
|
# Define method with same name to respond to this updates.
|
||||||
@@ -123,7 +123,7 @@ class Telegram::WebhookController < Telegram::Bot::UpdatesController
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_locale(&block)
|
def with_locale(&block)
|
||||||
I18n.with_locale(locale_for_update, &block)
|
I18n.with_locale(locale_for_update, &block)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -150,6 +150,36 @@ class Telegram::WebhookController < Telegram::Bot::UpdatesController
|
|||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
There is support for sessions using `ActiveSupport::Cache` stores.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
# configure store in env files:
|
||||||
|
config.telegram_updates_controller.session_store = :redis_store, {expires_in: 1.month}
|
||||||
|
|
||||||
|
class Telegram::WebhookController < Telegram::Bot::UpdatesController
|
||||||
|
include Telegram::Bot::UpdatesController::Session
|
||||||
|
# You can override global config
|
||||||
|
self.session_store = :file_store
|
||||||
|
|
||||||
|
def write(text = nil, *)
|
||||||
|
session[:text] = text
|
||||||
|
end
|
||||||
|
|
||||||
|
def read
|
||||||
|
session[:text]
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
# By default it uses bot's username and user's id as a session key.
|
||||||
|
# Chat's id is used only when `from` field is empty.
|
||||||
|
# Override `session_key` method to change this behavior.
|
||||||
|
def session_key
|
||||||
|
# In this case session will persist for user only in specific chat:
|
||||||
|
"#{bot.username}:#{chat['id']}:#{from['id']}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
### Routes
|
### Routes
|
||||||
|
|
||||||
Use `telegram_webhooks` helper to add routes. It will create routes for bots
|
Use `telegram_webhooks` helper to add routes. It will create routes for bots
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ module Telegram
|
|||||||
|
|
||||||
ActiveSupport.on_load('telegram.bot.updates_controller') do
|
ActiveSupport.on_load('telegram.bot.updates_controller') do
|
||||||
self.logger = options.logger || Rails.logger
|
self.logger = options.logger || Rails.logger
|
||||||
|
self.session_store = options.session_store || Rails.cache
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ module Telegram
|
|||||||
class UpdatesController < AbstractController::Base
|
class UpdatesController < AbstractController::Base
|
||||||
abstract!
|
abstract!
|
||||||
|
|
||||||
|
require 'telegram/bot/updates_controller/session'
|
||||||
|
require 'telegram/bot/updates_controller/log_subscriber'
|
||||||
|
require 'telegram/bot/updates_controller/instrumentation'
|
||||||
|
|
||||||
include AbstractController::Callbacks
|
include AbstractController::Callbacks
|
||||||
# Redefine callbacks with default terminator.
|
# Redefine callbacks with default terminator.
|
||||||
if ActiveSupport.gem_version >= Gem::Version.new('5')
|
if ActiveSupport.gem_version >= Gem::Version.new('5')
|
||||||
@@ -19,10 +23,8 @@ module Telegram
|
|||||||
end
|
end
|
||||||
|
|
||||||
include AbstractController::Translation
|
include AbstractController::Translation
|
||||||
|
|
||||||
require 'telegram/bot/updates_controller/log_subscriber'
|
|
||||||
require 'telegram/bot/updates_controller/instrumentation'
|
|
||||||
prepend Instrumentation
|
prepend Instrumentation
|
||||||
|
extend Session::ConfigMethods
|
||||||
|
|
||||||
autoload :TypedUpdate, 'telegram/bot/updates_controller/typed_update'
|
autoload :TypedUpdate, 'telegram/bot/updates_controller/typed_update'
|
||||||
|
|
||||||
|
|||||||
72
lib/telegram/bot/updates_controller/session.rb
Обычный файл
72
lib/telegram/bot/updates_controller/session.rb
Обычный файл
@@ -0,0 +1,72 @@
|
|||||||
|
require 'rack/session/abstract/id'
|
||||||
|
require 'active_support/cache'
|
||||||
|
|
||||||
|
module Telegram
|
||||||
|
module Bot
|
||||||
|
class UpdatesController
|
||||||
|
# Add functionality to store data between requests.
|
||||||
|
module Session
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
def process_action(*)
|
||||||
|
super
|
||||||
|
ensure
|
||||||
|
session.commit
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def session
|
||||||
|
@_session ||= SessionHash.new(self.class.session_store, session_key)
|
||||||
|
end
|
||||||
|
|
||||||
|
def session_key
|
||||||
|
"#{bot.username}:#{from ? "from:#{from['id']}" : "chat:#{chat['id']}"}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Rack::Session::Abstract::SessionHash is taken to provide lazy loading.
|
||||||
|
# All methods that access store are overriden to support
|
||||||
|
# ActiveSupport::Cache::Store stores.
|
||||||
|
class SessionHash < Rack::Session::Abstract::SessionHash
|
||||||
|
attr_reader :id
|
||||||
|
|
||||||
|
def initialize(store, id)
|
||||||
|
@store = store
|
||||||
|
@id = id
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
clear
|
||||||
|
@store.delete(id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def exists?
|
||||||
|
return @exists if defined?(@exists)
|
||||||
|
@data = {}
|
||||||
|
@exists = @store.exist? id
|
||||||
|
end
|
||||||
|
|
||||||
|
def load!
|
||||||
|
session = @store.read(id)
|
||||||
|
@data = session ? stringify_keys(session) : {}
|
||||||
|
@loaded = true
|
||||||
|
end
|
||||||
|
|
||||||
|
def commit
|
||||||
|
return unless loaded?
|
||||||
|
data = to_hash.delete_if { |_, v| v.nil? }
|
||||||
|
@store.write(id, data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module ConfigMethods
|
||||||
|
delegate :session_store, to: :config
|
||||||
|
|
||||||
|
def session_store=(store)
|
||||||
|
config.session_store = ActiveSupport::Cache.lookup_store(store)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
43
spec/telegram/bot/updates_controller/session_spec.rb
Обычный файл
43
spec/telegram/bot/updates_controller/session_spec.rb
Обычный файл
@@ -0,0 +1,43 @@
|
|||||||
|
RSpec.describe Telegram::Bot::UpdatesController::Session do
|
||||||
|
include_context 'telegram/bot/updates_controller'
|
||||||
|
let(:controller_class) do
|
||||||
|
described_class = self.described_class
|
||||||
|
Class.new(Telegram::Bot::UpdatesController) do
|
||||||
|
include described_class
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '.action_methods' do
|
||||||
|
subject { controller_class.action_methods }
|
||||||
|
it { should be_empty }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '.dispatch' do
|
||||||
|
subject { ->(*args) { controller_class.dispatch(*args) } }
|
||||||
|
let(:other_bot) { double(username: 'otherBot') }
|
||||||
|
before do
|
||||||
|
controller_class.class_eval do
|
||||||
|
self.session_store = :memory_store
|
||||||
|
|
||||||
|
def write(text)
|
||||||
|
session[:text] = text
|
||||||
|
end
|
||||||
|
|
||||||
|
def read
|
||||||
|
session[:text]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_message(text, from)
|
||||||
|
{'message' => {'text' => text, 'from' => from.stringify_keys}}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'stores session between requests' do
|
||||||
|
subject.call(bot, build_message('/write test', id: 1))
|
||||||
|
expect(subject.call(bot, build_message('/read', id: 1))).to eq 'test'
|
||||||
|
expect(subject.call(bot, build_message('/read', id: 2))).to eq nil
|
||||||
|
expect(subject.call(other_bot, build_message('/read', id: 1))).to eq nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Ссылка в новой задаче
Block a user