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 +4 -4
- data/lib/telegram_workflow.rb +1 -1
- data/lib/telegram_workflow/client.rb +17 -16
- data/lib/telegram_workflow/config.rb +3 -1
- data/lib/telegram_workflow/version.rb +1 -1
- data/telegram_workflow.gemspec +1 -1
- metadata +2 -13
- data/example/Gemfile +0 -2
- data/example/README.md +0 -79
- data/example/actions/create_appointment.rb +0 -56
- data/example/actions/list_actions.rb +0 -28
- data/example/actions/list_appointments.rb +0 -13
- data/example/actions/select_doctor.rb +0 -19
- data/example/actions/start.rb +0 -9
- data/example/client.rb +0 -5
- data/example/environment.rb +0 -13
- data/example/flow.jpg +0 -0
- data/example/main.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b9e4c2c5c0d7ee686ea3961a0af8c50ae6511c26cbf5ee704f1c3e27dad82e65
|
4
|
+
data.tar.gz: 80ce424f3627fb918810020c7811dbbe98713bd87e59280815ca6f7e37d6550f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ff7be3ead93112c1cb5debbe5f8a62399948057b445b896c4d3a585b660dfa9707569a5e214faa5fa75230b180db76b27167ae4c097ff687f7cec297dda5fa8
|
7
|
+
data.tar.gz: 04b307ae0e32fc0a5a76019372d8fed3fc5e70229818a90dbc134da3a5a9da1ce7d01e5ee50f3c41f905931f2fe5157b8bcff5d4c93a59009d9c6ce29dc4ea13
|
data/lib/telegram_workflow.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
98
|
+
cached_webhook_config(params)
|
100
99
|
end
|
101
100
|
|
102
101
|
def delete_webhook
|
103
|
-
make_request("deleteWebhook"
|
104
|
-
|
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
|
-
|
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(
|
113
|
+
set_webhook(webhook_params)
|
113
114
|
end
|
114
115
|
end
|
115
116
|
|
116
117
|
private
|
117
118
|
|
118
|
-
def
|
119
|
-
unless
|
120
|
-
|
121
|
-
|
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
|
125
|
-
|
125
|
+
if new_config.nil?
|
126
|
+
Marshal.load(WebhookConfigPath.read)
|
126
127
|
else
|
127
|
-
|
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
|
data/telegram_workflow.gemspec
CHANGED
@@ -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.
|
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-
|
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
|
data/example/Gemfile
DELETED
data/example/README.md
DELETED
@@ -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
|
data/example/actions/start.rb
DELETED
data/example/client.rb
DELETED
data/example/environment.rb
DELETED
data/example/flow.jpg
DELETED
Binary file
|
data/example/main.rb
DELETED
@@ -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
|