telegram_workflow 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9f33398c3b33397236392a5b645e39b58827df8e453727fd06496ce0b4479e11
4
- data.tar.gz: 9155e202748c8242adc4f4789623b8c42156658616e545d1aafd2aa4f2f776f7
3
+ metadata.gz: b9e4c2c5c0d7ee686ea3961a0af8c50ae6511c26cbf5ee704f1c3e27dad82e65
4
+ data.tar.gz: 80ce424f3627fb918810020c7811dbbe98713bd87e59280815ca6f7e37d6550f
5
5
  SHA512:
6
- metadata.gz: 4f85e7ab9b297deab054185d03863c8183bf7fbd6a7f1325ec612fa0042ee0999a700e80d91cb5cbed3b945605595904ec1716192b341d39f2402df805ea69f1
7
- data.tar.gz: 67bf8b6d8abc59f26c2e302f989aaa17777303bc3efdfb29844686d35f62994a2257557e7838188292e2fbbecc7eb7d1ad872c3f123eb9eb1b61b686b046a5ba
6
+ metadata.gz: 9ff7be3ead93112c1cb5debbe5f8a62399948057b445b896c4d3a585b660dfa9707569a5e214faa5fa75230b180db76b27167ae4c097ff687f7cec297dda5fa8
7
+ data.tar.gz: 04b307ae0e32fc0a5a76019372d8fed3fc5e70229818a90dbc134da3a5a9da1ce7d01e5ee50f3c41f905931f2fe5157b8bcff5d4c93a59009d9c6ce29dc4ea13
@@ -39,6 +39,6 @@ require "telegram_workflow/stores/file"
39
39
 
40
40
  TelegramWorkflow.__after_configuration do |config|
41
41
  if config.webhook_url
42
- TelegramWorkflow::Client.new.__setup_webhook
42
+ TelegramWorkflow::Client.new.__setup_webhook(config.webhook_url, config.webhook_params)
43
43
  end
44
44
  end
@@ -1,6 +1,6 @@
1
1
  class TelegramWorkflow::Client
2
2
  API_VERSION = "4.9"
3
- WebhookFilePath = Pathname.new("tmp/telegram_workflow/webhook_url.txt")
3
+ WebhookConfigPath = Pathname.new("tmp/telegram_workflow/webhook_config.txt")
4
4
 
5
5
  AVAILABLE_ACTIONS = %i(
6
6
  getUpdates
@@ -90,45 +90,46 @@ class TelegramWorkflow::Client
90
90
 
91
91
  def initialize(chat_id = nil)
92
92
  @chat_id = chat_id
93
- @webhook_url = TelegramWorkflow.config.webhook_url
94
93
  @api_url = "https://api.telegram.org/bot#{TelegramWorkflow.config.api_token}"
95
94
  end
96
95
 
97
96
  def set_webhook(params = {})
98
97
  make_request("setWebhook", params)
99
- cached_webhook_url(new_url: @webhook_url)
98
+ cached_webhook_config(params)
100
99
  end
101
100
 
102
101
  def delete_webhook
103
- make_request("deleteWebhook", {})
104
- cached_webhook_url(new_url: "")
102
+ make_request("deleteWebhook")
103
+ cached_webhook_config({})
105
104
  end
106
105
 
107
- def __setup_webhook
106
+ def __setup_webhook(webhook_url = TelegramWorkflow.config.webhook_url, params = {})
108
107
  TelegramWorkflow.config.logger.info "[TelegramWorkflow] Checking webhook setup..."
109
108
 
110
- if cached_webhook_url != @webhook_url
109
+ webhook_params = { url: webhook_url, allowed_updates: [], **params }
110
+
111
+ if cached_webhook_config != webhook_params
111
112
  TelegramWorkflow.config.logger.info "[TelegramWorkflow] Setting up a new webhook..."
112
- set_webhook(url: @webhook_url)
113
+ set_webhook(webhook_params)
113
114
  end
114
115
  end
115
116
 
116
117
  private
117
118
 
118
- def cached_webhook_url(new_url: nil)
119
- unless WebhookFilePath.exist?
120
- WebhookFilePath.dirname.mkpath
121
- WebhookFilePath.write("")
119
+ def cached_webhook_config(new_config = nil)
120
+ unless WebhookConfigPath.exist?
121
+ WebhookConfigPath.dirname.mkpath
122
+ WebhookConfigPath.write(Marshal.dump({}))
122
123
  end
123
124
 
124
- if new_url.nil?
125
- WebhookFilePath.read
125
+ if new_config.nil?
126
+ Marshal.load(WebhookConfigPath.read)
126
127
  else
127
- WebhookFilePath.write(new_url)
128
+ WebhookConfigPath.write(Marshal.dump(new_config))
128
129
  end
129
130
  end
130
131
 
131
- def make_request(action, params)
132
+ def make_request(action, params = {})
132
133
  has_file_params = params.any? { |_, param| param.is_a?(TelegramWorkflow::InputFile) }
133
134
  request_type = has_file_params ? :form : :json
134
135
 
@@ -21,12 +21,14 @@ module TelegramWorkflow
21
21
  end
22
22
 
23
23
  class Configuration
24
- attr_accessor :session_store, :logger, :client, :start_action, :webhook_url, :api_token
24
+ attr_accessor :session_store, :logger, :client, :start_action, :webhook_url, :api_token,
25
+ :webhook_params
25
26
 
26
27
  REQUIRED_PARAMS = %i(session_store start_action api_token)
27
28
 
28
29
  def initialize
29
30
  @client = TelegramWorkflow::Client
31
+ @webhook_params = {}
30
32
 
31
33
  if defined?(Rails)
32
34
  @session_store = Rails.cache
@@ -1,3 +1,3 @@
1
1
  module TelegramWorkflow
2
- VERSION = "1.3.0"
2
+ VERSION = "1.4.0"
3
3
  end
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
21
21
  # Specify which files should be added to the gem when it is released.
22
22
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
23
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
24
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|example)/}) }
25
25
  end
26
26
  spec.bindir = "exe"
27
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: telegram_workflow
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roman Samoilov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-06-29 00:00:00.000000000 Z
11
+ date: 2020-07-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http
@@ -82,17 +82,6 @@ files:
82
82
  - Rakefile
83
83
  - bin/console
84
84
  - bin/setup
85
- - example/Gemfile
86
- - example/README.md
87
- - example/actions/create_appointment.rb
88
- - example/actions/list_actions.rb
89
- - example/actions/list_appointments.rb
90
- - example/actions/select_doctor.rb
91
- - example/actions/start.rb
92
- - example/client.rb
93
- - example/environment.rb
94
- - example/flow.jpg
95
- - example/main.rb
96
85
  - lib/telegram_workflow.rb
97
86
  - lib/telegram_workflow/action.rb
98
87
  - lib/telegram_workflow/client.rb
@@ -1,2 +0,0 @@
1
- source "https://rubygems.org"
2
- gem "telegram_workflow"
@@ -1,79 +0,0 @@
1
- ## Description
2
-
3
- This is a fully working example of a bot which allows you to book an appointment with a doctor.
4
-
5
- The following diagram will help you understand the bot's flow:
6
- <p>
7
- <img src="https://github.com/rsamoilov/telegram_workflow/blob/master/example/flow.jpg" width="400">
8
- </p>
9
-
10
- ## Running the bot
11
-
12
- First, open [main.rb](main.rb) and configure the bot with your API token:
13
-
14
- ```diff
15
- TelegramWorkflow.configure do |config|
16
- - config.api_token = <YOUR_TOKEN>
17
- + config.api_token = "123456780:ABCDE_my-token"
18
- end
19
- ```
20
-
21
- Next, run the bot:
22
-
23
- ```
24
- bundle
25
- ruby main.rb
26
- ```
27
-
28
- ## Configuration
29
-
30
- Every Bot workflow begins with **`on_message`** callback in a `start_action`.
31
- There's no need to store current user data in session in this example, so we simply redirect to the `ListActions` action, which will be our "main" action.
32
-
33
- ```ruby
34
- class Actions::Start < TelegramWorkflow::Action
35
- def initial
36
- on_message do
37
- redirect_to Actions::ListActions
38
- end
39
- end
40
- end
41
- ```
42
-
43
- Next, the Telegram client can be customized. We want to use Telegram's [InlineKeyboard](https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating) to provide a user with a list of available actions.
44
-
45
- Let's encapsulate this inside our custom client class:
46
-
47
- ```ruby
48
- class Client < TelegramWorkflow::Client
49
- def send_actions(message, actions)
50
- send_message text: message, reply_markup: { inline_keyboard: actions }
51
- end
52
- end
53
- ```
54
-
55
- Now, let's configure the gem:
56
-
57
- ```ruby
58
- TelegramWorkflow.configure do |config|
59
- config.start_action = Actions::Start
60
- config.client = Client
61
- config.session_store = TelegramWorkflow::Stores::File.new
62
- end
63
- ```
64
-
65
- The last configuration parameter here is `session_store`. We are using `TelegramWorkflow::Stores::File` - a built-in implementation of persistent file store.
66
-
67
- [getUpdates](https://core.telegram.org/bots/api#getupdates) method is used in this example to receive the updates:
68
-
69
- ```ruby
70
- TelegramWorkflow.updates.each do |params|
71
- TelegramWorkflow.process(params)
72
- end
73
- ```
74
-
75
- After a user has sent a message, `TelegramWorkflow.process` will initialize the last processed action and step and then call `on_message` callback on it.
76
-
77
- ## Actions
78
-
79
- Check out the bot's code under [actions](actions) folder.
@@ -1,56 +0,0 @@
1
- #
2
- # this is an action to create an appointment;
3
- # each method represents one of the steps for appointment creation;
4
- # for the sake of simplicity, all created appointments are stored in the session
5
- #
6
- class Actions::CreateAppointment < TelegramWorkflow::Action
7
- def initial
8
- on_redirect do
9
- client.send_message text: "Enter patient's name:"
10
- end
11
-
12
- on_message do
13
- flash[:name] = params.message_text
14
- redirect_to :reason
15
- end
16
- end
17
-
18
- def reason
19
- on_redirect do
20
- client.send_message text: "What is the reason for visit?"
21
- end
22
-
23
- on_message do
24
- flash[:reason] = params.message_text
25
- redirect_to :date
26
- end
27
- end
28
-
29
- def date
30
- on_redirect do
31
- client.send_message text: "What date works best for you?"
32
- end
33
-
34
- on_message do
35
- date = Date.parse(params.message_text) rescue nil
36
-
37
- # there's no redirect in case the date is invalid;
38
- # this means that next time a user sends a message, the current action will be executed again
39
- if date
40
- flash[:date] = date
41
- redirect_to :done
42
- else
43
- client.send_message text: "Invalid date format. Please try again."
44
- end
45
- end
46
- end
47
-
48
- # `specialty` parameter is added to flash in previous `Actions::SelectDoctor` action
49
- def done
50
- on_redirect do
51
- (session[:appointments] ||= []) << flash.slice(:name, :reason, :date, :specialty)
52
- client.send_message text: "Your appointment has been created!"
53
- redirect_to Actions::ListActions
54
- end
55
- end
56
- end
@@ -1,28 +0,0 @@
1
- class Actions::ListActions < TelegramWorkflow::Action
2
- def initial
3
- on_redirect do
4
- available_actions = [
5
- [{ text: "Make an appointment", callback_data: "create" }]
6
- ]
7
-
8
- if session[:appointments]&.any?
9
- available_actions.unshift [{ text: "List my appointments", callback_data: "list" }]
10
- end
11
-
12
- # this is the customized client object
13
- client.send_actions "Select an action:", available_actions
14
- end
15
-
16
- # `params.callback_data` here will be one of the identifiers defined as `callback_data` in `available_actions` array
17
- # refer to https://core.telegram.org/bots/api#inlinekeyboardbutton
18
- on_message do
19
- next_action = if params.callback_data == "create"
20
- Actions::SelectDoctor
21
- elsif params.callback_data == "list"
22
- Actions::ListAppointments
23
- end
24
-
25
- redirect_to next_action
26
- end
27
- end
28
- end
@@ -1,13 +0,0 @@
1
- class Actions::ListAppointments < TelegramWorkflow::Action
2
- def initial
3
- on_redirect do
4
- appointments = session[:appointments].map do |app|
5
- "<b>#{app[:name]}</b> on #{app[:date].to_s}"
6
- end
7
-
8
- # refer to https://core.telegram.org/bots/api#sendmessage for the list of available parameters
9
- client.send_message text: appointments.join("\n"), parse_mode: "HTML"
10
- redirect_to Actions::ListActions
11
- end
12
- end
13
- end
@@ -1,19 +0,0 @@
1
- class Actions::SelectDoctor < TelegramWorkflow::Action
2
- def initial
3
- on_redirect do
4
- available_doctors = [
5
- [{ text: "Family Medicine", callback_data: "family" }],
6
- [{ text: "Emergency Medicine", callback_data: "emergency" }],
7
- [{ text: "Pediatrics", callback_data: "pediatrics" }]
8
- ]
9
-
10
- client.send_actions "Select a doctor:", available_doctors
11
- end
12
-
13
- on_message do
14
- # pass `specialty` parameter to the next action
15
- # https://github.com/rsamoilov/telegram_workflow#redirect_toaction_or_class-flash_params--
16
- redirect_to Actions::CreateAppointment, specialty: params.callback_data
17
- end
18
- end
19
- end
@@ -1,9 +0,0 @@
1
- class Actions::Start < TelegramWorkflow::Action
2
- def initial
3
- # we don't need to store current user id in session or make any other setup,
4
- # so just redirect to the `ListActions` action
5
- on_message do
6
- redirect_to Actions::ListActions
7
- end
8
- end
9
- end
@@ -1,5 +0,0 @@
1
- class Client < TelegramWorkflow::Client
2
- def send_actions(message, actions)
3
- send_message text: message, reply_markup: { inline_keyboard: actions }
4
- end
5
- end
@@ -1,13 +0,0 @@
1
- require "telegram_workflow"
2
- require "date"
3
-
4
- module Actions
5
- end
6
-
7
- dependencies = %w(
8
- ./actions/*.rb
9
- ./client.rb
10
- )
11
- dependencies.each do |path|
12
- Dir[path].each { |path| require_relative path }
13
- end
Binary file
@@ -1,17 +0,0 @@
1
- require_relative "environment"
2
-
3
- TelegramWorkflow.configure do |config|
4
- config.start_action = Actions::Start
5
- config.client = Client
6
- config.session_store = TelegramWorkflow::Stores::File.new
7
- config.api_token = <YOUR_TOKEN>
8
- end
9
-
10
- trap "SIGINT" do
11
- puts "Exiting..."
12
- TelegramWorkflow.stop_updates
13
- end
14
-
15
- TelegramWorkflow.updates(timeout: 5).each do |params|
16
- TelegramWorkflow.process(params)
17
- end