stealth 1.1.2 → 2.0.0.beta1
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/.circleci/config.yml +18 -8
- data/CHANGELOG.md +100 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +49 -43
- data/LICENSE +4 -17
- data/README.md +9 -17
- data/VERSION +1 -1
- data/lib/stealth/base.rb +62 -13
- data/lib/stealth/cli.rb +1 -2
- data/lib/stealth/commands/console.rb +1 -1
- data/lib/stealth/configuration.rb +0 -3
- data/lib/stealth/controller/callbacks.rb +1 -1
- data/lib/stealth/controller/catch_all.rb +27 -4
- data/lib/stealth/controller/controller.rb +168 -49
- data/lib/stealth/controller/dev_jumps.rb +41 -0
- data/lib/stealth/controller/dynamic_delay.rb +4 -6
- data/lib/stealth/controller/interrupt_detect.rb +100 -0
- data/lib/stealth/controller/messages.rb +283 -0
- data/lib/stealth/controller/nlp.rb +50 -0
- data/lib/stealth/controller/replies.rb +179 -41
- data/lib/stealth/controller/unrecognized_message.rb +62 -0
- data/lib/stealth/core_ext.rb +5 -0
- data/lib/stealth/{flow/core_ext.rb → core_ext/numeric.rb} +0 -1
- data/lib/stealth/core_ext/string.rb +18 -0
- data/lib/stealth/dispatcher.rb +21 -0
- data/lib/stealth/errors.rb +12 -0
- data/lib/stealth/flow/base.rb +1 -2
- data/lib/stealth/flow/specification.rb +3 -2
- data/lib/stealth/flow/state.rb +3 -3
- data/lib/stealth/generators/builder/Gemfile +4 -3
- data/lib/stealth/generators/builder/bot/controllers/bot_controller.rb +42 -0
- data/lib/stealth/generators/builder/bot/controllers/catch_alls_controller.rb +2 -0
- data/lib/stealth/generators/builder/bot/controllers/goodbyes_controller.rb +2 -0
- data/lib/stealth/generators/builder/bot/controllers/hellos_controller.rb +2 -0
- data/lib/stealth/generators/builder/bot/controllers/interrupts_controller.rb +9 -0
- data/lib/stealth/generators/builder/bot/controllers/unrecognized_messages_controller.rb +9 -0
- data/lib/stealth/generators/builder/config/flow_map.rb +8 -0
- data/lib/stealth/generators/builder/config/initializers/autoload.rb +8 -0
- data/lib/stealth/generators/builder/config/initializers/inflections.rb +16 -0
- data/lib/stealth/generators/builder/config/puma.rb +15 -0
- data/lib/stealth/helpers/redis.rb +40 -0
- data/lib/stealth/lock.rb +83 -0
- data/lib/stealth/logger.rb +27 -18
- data/lib/stealth/nlp/client.rb +22 -0
- data/lib/stealth/nlp/result.rb +57 -0
- data/lib/stealth/reloader.rb +90 -0
- data/lib/stealth/reply.rb +17 -0
- data/lib/stealth/scheduled_reply.rb +3 -3
- data/lib/stealth/server.rb +4 -4
- data/lib/stealth/service_message.rb +3 -2
- data/lib/stealth/service_reply.rb +5 -1
- data/lib/stealth/services/base_reply_handler.rb +2 -2
- data/lib/stealth/session.rb +106 -53
- data/spec/configuration_spec.rb +9 -2
- data/spec/controller/callbacks_spec.rb +23 -28
- data/spec/controller/catch_all_spec.rb +81 -29
- data/spec/controller/controller_spec.rb +444 -43
- data/spec/controller/dynamic_delay_spec.rb +16 -18
- data/spec/controller/helpers_spec.rb +1 -2
- data/spec/controller/interrupt_detect_spec.rb +171 -0
- data/spec/controller/messages_spec.rb +744 -0
- data/spec/controller/nlp_spec.rb +93 -0
- data/spec/controller/replies_spec.rb +446 -11
- data/spec/controller/unrecognized_message_spec.rb +168 -0
- data/spec/dispatcher_spec.rb +79 -0
- data/spec/flow/flow_spec.rb +1 -2
- data/spec/flow/state_spec.rb +14 -3
- data/spec/helpers/redis_spec.rb +77 -0
- data/spec/lock_spec.rb +100 -0
- data/spec/nlp/client_spec.rb +23 -0
- data/spec/nlp/result_spec.rb +57 -0
- data/spec/replies/messages/say_msgs_without_breaks.yml +4 -0
- data/spec/replies/messages/say_randomize_speech.yml +10 -0
- data/spec/replies/messages/say_randomize_text.yml +10 -0
- data/spec/replies/messages/sub1/sub2/say_nested.yml +10 -0
- data/spec/reply_spec.rb +61 -0
- data/spec/scheduled_reply_spec.rb +23 -0
- data/spec/service_reply_spec.rb +1 -2
- data/spec/session_spec.rb +251 -12
- data/spec/spec_helper.rb +21 -0
- data/spec/support/controllers/vaders_controller.rb +24 -0
- data/spec/support/nlp_clients/dialogflow.rb +9 -0
- data/spec/support/nlp_clients/luis.rb +9 -0
- data/spec/support/nlp_results/luis_result.rb +163 -0
- data/spec/version_spec.rb +1 -2
- data/stealth.gemspec +6 -6
- metadata +83 -39
- data/docs/00-introduction.md +0 -37
- data/docs/01-getting-started.md +0 -21
- data/docs/02-local-development.md +0 -40
- data/docs/03-basics.md +0 -171
- data/docs/04-sessions.md +0 -29
- data/docs/05-controllers.md +0 -179
- data/docs/06-models.md +0 -39
- data/docs/07-replies.md +0 -114
- data/docs/08-catchalls.md +0 -49
- data/docs/09-messaging-integrations.md +0 -80
- data/docs/10-nlp-integrations.md +0 -13
- data/docs/11-analytics.md +0 -13
- data/docs/12-commands.md +0 -62
- data/docs/13-deployment.md +0 -50
- data/lib/stealth/generators/builder/config/initializers/.keep +0 -0
data/lib/stealth/logger.rb
CHANGED
@@ -13,7 +13,8 @@ module Stealth
|
|
13
13
|
magenta: 35,
|
14
14
|
cyan: 36,
|
15
15
|
gray: 37,
|
16
|
-
light_cyan: 96
|
16
|
+
light_cyan: 96,
|
17
|
+
white: 97
|
17
18
|
].freeze
|
18
19
|
|
19
20
|
def self.color_code(code)
|
@@ -26,29 +27,37 @@ module Stealth
|
|
26
27
|
|
27
28
|
def self.log(topic:, message:)
|
28
29
|
unless ENV['STEALTH_ENV'] == 'test'
|
29
|
-
puts "#{print_topic(topic)} #{message}"
|
30
|
+
puts "TID-#{Stealth.tid} #{print_topic(topic)} #{message}"
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
33
34
|
def self.print_topic(topic)
|
34
35
|
topic_string = "[#{topic}]"
|
35
36
|
|
36
|
-
case topic.to_sym
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
37
|
+
color = case topic.to_sym
|
38
|
+
when :primary_session
|
39
|
+
:green
|
40
|
+
when :previous_session, :back_to_session
|
41
|
+
:yellow
|
42
|
+
when :interrupt
|
43
|
+
:magenta
|
44
|
+
when :facebook, :twilio, :bandwidth
|
45
|
+
:blue
|
46
|
+
when :smooch
|
47
|
+
:magenta
|
48
|
+
when :alexa, :unrecognized_message
|
49
|
+
:light_cyan
|
50
|
+
when :nlp
|
51
|
+
:cyan
|
52
|
+
when :catch_all, :err
|
53
|
+
:red
|
54
|
+
when :user
|
55
|
+
:white
|
56
|
+
else
|
57
|
+
:gray
|
58
|
+
end
|
59
|
+
|
60
|
+
colorize(topic_string, color: color)
|
52
61
|
end
|
53
62
|
|
54
63
|
class << self
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Stealth
|
5
|
+
module Nlp
|
6
|
+
class Client
|
7
|
+
|
8
|
+
def client
|
9
|
+
nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def understand(query:)
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def understand_speech(audio_file:, audio_config: nil)
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Stealth
|
5
|
+
module Nlp
|
6
|
+
class Result
|
7
|
+
|
8
|
+
ENTITY_TYPES = %i(number currency email percentage phone age
|
9
|
+
url ordinal geo dimension temp datetime duration
|
10
|
+
key_phrase name)
|
11
|
+
|
12
|
+
attr_reader :result
|
13
|
+
|
14
|
+
def initialize(result:)
|
15
|
+
@result = result
|
16
|
+
end
|
17
|
+
|
18
|
+
def parsed_result
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def intent_id
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def intent
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def intent_score
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def raw_entities
|
35
|
+
{}
|
36
|
+
end
|
37
|
+
|
38
|
+
def entities
|
39
|
+
{}
|
40
|
+
end
|
41
|
+
|
42
|
+
# :postive, :negative, :neutral
|
43
|
+
def sentiment
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
|
47
|
+
def sentiment_score
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def present?
|
52
|
+
parsed_result.present?
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'zeitwerk'
|
5
|
+
|
6
|
+
module Stealth
|
7
|
+
class Reloader
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@reloader = Class.new(ActiveSupport::Reloader)
|
11
|
+
@loader = Zeitwerk::Loader.new
|
12
|
+
# @loader.logger = method(:puts)
|
13
|
+
@loader
|
14
|
+
end
|
15
|
+
|
16
|
+
def load_bot!
|
17
|
+
load_autoload_paths!
|
18
|
+
enable_reloading!
|
19
|
+
enable_eager_load!
|
20
|
+
@loader.setup
|
21
|
+
end
|
22
|
+
|
23
|
+
def load_autoload_paths!
|
24
|
+
if Stealth.config.autoload_paths.present?
|
25
|
+
Stealth.config.autoload_paths.each do |autoload_path|
|
26
|
+
@loader.push_dir(autoload_path)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Bot-specific ignores
|
30
|
+
Stealth.config.autoload_ignore_paths.each do |autoload_ignore_path|
|
31
|
+
@loader.ignore(autoload_ignore_path)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Ignore setup files
|
35
|
+
@loader.ignore(File.join(Stealth.root, 'config', 'initializers'))
|
36
|
+
@loader.ignore(File.join(Stealth.root, 'config', 'boot.rb'))
|
37
|
+
@loader.ignore(File.join(Stealth.root, 'config', 'environment.rb'))
|
38
|
+
@loader.ignore(File.join(Stealth.root, 'config', 'puma.rb'))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def enable_eager_load!
|
43
|
+
if Stealth.config.eager_load
|
44
|
+
@loader.eager_load
|
45
|
+
Stealth::Logger.l(topic: 'stealth', message: 'Eager loading enabled.')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def enable_reloading!
|
50
|
+
if Stealth.config.hot_reload
|
51
|
+
@checker = ActiveSupport::EventedFileUpdateChecker.new([], files_to_watch) do
|
52
|
+
reload!
|
53
|
+
end
|
54
|
+
|
55
|
+
@loader.enable_reloading
|
56
|
+
Stealth::Logger.l(topic: 'stealth', message: 'Hot reloading enabled.')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Only reloads if a change has been detected in one of the autoload files`
|
61
|
+
def reload
|
62
|
+
if Stealth.config.hot_reload
|
63
|
+
@checker.execute_if_updated
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Force reloads reglardless of filesystem changes
|
68
|
+
def reload!
|
69
|
+
if Stealth.config.hot_reload
|
70
|
+
@loader.reload
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def call
|
75
|
+
@reloader.wrap do
|
76
|
+
reload
|
77
|
+
yield
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def files_to_watch
|
84
|
+
Stealth.config.autoload_paths.map do |path|
|
85
|
+
[path, 'rb']
|
86
|
+
end.to_h
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
data/lib/stealth/reply.rb
CHANGED
@@ -15,5 +15,22 @@ module Stealth
|
|
15
15
|
@reply[key]
|
16
16
|
end
|
17
17
|
|
18
|
+
def []=(key, value)
|
19
|
+
@reply[key] = value
|
20
|
+
end
|
21
|
+
|
22
|
+
def delay?
|
23
|
+
reply_type == 'delay'
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.dynamic_delay
|
27
|
+
self.new(
|
28
|
+
unstructured_reply: {
|
29
|
+
'reply_type' => 'delay',
|
30
|
+
'duration' => 'dynamic'
|
31
|
+
}
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
18
35
|
end
|
19
36
|
end
|
@@ -6,12 +6,12 @@ module Stealth
|
|
6
6
|
class ScheduledReplyJob < Stealth::Jobs
|
7
7
|
sidekiq_options queue: :stealth_replies, retry: false
|
8
8
|
|
9
|
-
def perform(service, user_id, flow, state)
|
9
|
+
def perform(service, user_id, flow, state, target_id=nil)
|
10
10
|
service_message = ServiceMessage.new(service: service)
|
11
11
|
service_message.sender_id = user_id
|
12
|
+
service_message.target_id = target_id
|
12
13
|
controller = BotController.new(service_message: service_message)
|
13
|
-
controller.
|
14
|
-
controller.route
|
14
|
+
controller.step_to(flow: flow, state: state)
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
data/lib/stealth/server.rb
CHANGED
@@ -30,10 +30,10 @@ module Stealth
|
|
30
30
|
end
|
31
31
|
|
32
32
|
get_or_post '/incoming/:service' do
|
33
|
-
Stealth::Logger.l(topic:
|
33
|
+
Stealth::Logger.l(topic: params[:service], message: 'Received webhook.')
|
34
34
|
|
35
35
|
# JSON params need to be parsed and added to the params
|
36
|
-
if request.env['CONTENT_TYPE']
|
36
|
+
if request.env['CONTENT_TYPE']&.match(/application\/json/i)
|
37
37
|
json_params = MultiJson.load(request.body.read)
|
38
38
|
params.merge!(json_params)
|
39
39
|
end
|
@@ -50,8 +50,8 @@ module Stealth
|
|
50
50
|
private
|
51
51
|
|
52
52
|
def get_helpers_from_request(request)
|
53
|
-
request.env.
|
54
|
-
|
53
|
+
request.env.select do |header, value|
|
54
|
+
%w[HTTP_HOST].include?(header)
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
@@ -4,8 +4,9 @@
|
|
4
4
|
module Stealth
|
5
5
|
class ServiceMessage
|
6
6
|
|
7
|
-
attr_accessor :sender_id, :timestamp, :service, :message,
|
8
|
-
:attachments, :payload, :referral
|
7
|
+
attr_accessor :sender_id, :target_id, :timestamp, :service, :message,
|
8
|
+
:location, :attachments, :payload, :referral, :nlp_result,
|
9
|
+
:catch_all_reason
|
9
10
|
|
10
11
|
def initialize(service:)
|
11
12
|
@service = service
|
@@ -18,7 +18,11 @@ module Stealth
|
|
18
18
|
@yaml_reply
|
19
19
|
end
|
20
20
|
|
21
|
-
|
21
|
+
if yaml_reply.is_a?(Array)
|
22
|
+
@replies = load_replies(@yaml_reply)
|
23
|
+
else
|
24
|
+
@replies = load_replies(YAML.load(processed_reply))
|
25
|
+
end
|
22
26
|
end
|
23
27
|
|
24
28
|
private
|
data/lib/stealth/session.rb
CHANGED
@@ -4,21 +4,30 @@
|
|
4
4
|
module Stealth
|
5
5
|
class Session
|
6
6
|
|
7
|
+
include Stealth::Redis
|
8
|
+
|
7
9
|
SLUG_SEPARATOR = '->'
|
8
10
|
|
9
|
-
attr_reader :flow, :state, :
|
11
|
+
attr_reader :flow, :state, :id, :type
|
10
12
|
attr_accessor :session
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
# Session types:
|
15
|
+
# - :primary
|
16
|
+
# - :previous
|
17
|
+
# - :back_to
|
18
|
+
def initialize(id: nil, type: :primary)
|
19
|
+
@id = id
|
20
|
+
@type = type
|
15
21
|
|
16
|
-
if
|
22
|
+
if id.present?
|
17
23
|
unless defined?($redis) && $redis.present?
|
18
|
-
raise(
|
24
|
+
raise(
|
25
|
+
Stealth::Errors::RedisNotConfigured,
|
26
|
+
"Please make sure REDIS_URL is configured before using sessions"
|
27
|
+
)
|
19
28
|
end
|
20
29
|
|
21
|
-
|
30
|
+
get_session
|
22
31
|
end
|
23
32
|
|
24
33
|
self
|
@@ -31,6 +40,14 @@ module Stealth
|
|
31
40
|
}
|
32
41
|
end
|
33
42
|
|
43
|
+
def self.slugify(flow:, state:)
|
44
|
+
unless flow.present? && state.present?
|
45
|
+
raise(ArgumentError, 'A flow and state must be specified.')
|
46
|
+
end
|
47
|
+
|
48
|
+
[flow, state].join(SLUG_SEPARATOR)
|
49
|
+
end
|
50
|
+
|
34
51
|
def flow
|
35
52
|
return nil if flow_string.blank?
|
36
53
|
|
@@ -49,31 +66,32 @@ module Stealth
|
|
49
66
|
session&.split(SLUG_SEPARATOR)&.last
|
50
67
|
end
|
51
68
|
|
52
|
-
def
|
53
|
-
|
54
|
-
|
55
|
-
@session ||= begin
|
56
|
-
if sessions_expire?
|
57
|
-
previous? ? getex(prev_key) : getex(user_id)
|
58
|
-
else
|
59
|
-
previous? ? $redis.get(prev_key) : $redis.get(user_id)
|
60
|
-
end
|
61
|
-
end
|
69
|
+
def get_session
|
70
|
+
@session ||= get_key(session_key)
|
62
71
|
end
|
63
72
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
@
|
68
|
-
|
73
|
+
def set_session(new_flow:, new_state:)
|
74
|
+
@flow = nil # override @flow's memoization
|
75
|
+
existing_session = session # tmp backup for previous_session storage
|
76
|
+
@session = self.class.canonical_session_slug(
|
77
|
+
flow: new_flow,
|
78
|
+
state: new_state
|
79
|
+
)
|
80
|
+
|
81
|
+
Stealth::Logger.l(
|
82
|
+
topic: [type, 'session'].join('_'),
|
83
|
+
message: "User #{id}: setting session to #{new_flow}->#{new_state}"
|
84
|
+
)
|
85
|
+
|
86
|
+
if primary_session?
|
87
|
+
store_current_to_previous(existing_session: existing_session)
|
88
|
+
end
|
69
89
|
|
70
|
-
|
90
|
+
persist_key(key: session_key, value: session)
|
91
|
+
end
|
71
92
|
|
72
|
-
|
73
|
-
|
74
|
-
else
|
75
|
-
$redis.set(user_id, session)
|
76
|
-
end
|
93
|
+
def clear_session
|
94
|
+
$redis.del(session_key)
|
77
95
|
end
|
78
96
|
|
79
97
|
def present?
|
@@ -84,17 +102,16 @@ module Stealth
|
|
84
102
|
!present?
|
85
103
|
end
|
86
104
|
|
87
|
-
def previous?
|
88
|
-
@previous
|
89
|
-
end
|
90
|
-
|
91
105
|
def +(steps)
|
92
106
|
return nil if flow.blank?
|
93
107
|
return self if steps.zero?
|
94
108
|
|
95
109
|
new_state = self.state + steps
|
96
|
-
new_session = Stealth::Session.new(
|
97
|
-
new_session.session = self.class.canonical_session_slug(
|
110
|
+
new_session = Stealth::Session.new(id: self.id)
|
111
|
+
new_session.session = self.class.canonical_session_slug(
|
112
|
+
flow: self.flow_string,
|
113
|
+
state: new_state
|
114
|
+
)
|
98
115
|
|
99
116
|
new_session
|
100
117
|
end
|
@@ -109,6 +126,13 @@ module Stealth
|
|
109
126
|
end
|
110
127
|
end
|
111
128
|
|
129
|
+
def ==(other_session)
|
130
|
+
self.flow_string == other_session.flow_string &&
|
131
|
+
self.state_string == other_session.state_string &&
|
132
|
+
self.type == other_session.type &&
|
133
|
+
self.id == other_session.id
|
134
|
+
end
|
135
|
+
|
112
136
|
def self.is_a_session_string?(string)
|
113
137
|
session_regex = /(.+)(#{SLUG_SEPARATOR})(.+)/
|
114
138
|
!!string.match(session_regex)
|
@@ -118,32 +142,61 @@ module Stealth
|
|
118
142
|
[flow, state].join(SLUG_SEPARATOR)
|
119
143
|
end
|
120
144
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
145
|
+
def session_key
|
146
|
+
case type
|
147
|
+
when :primary
|
148
|
+
id
|
149
|
+
when :previous
|
150
|
+
previous_session_key
|
151
|
+
when :back_to
|
152
|
+
back_to_key
|
125
153
|
end
|
154
|
+
end
|
126
155
|
|
127
|
-
|
128
|
-
|
156
|
+
def primary_session?
|
157
|
+
type == :primary
|
158
|
+
end
|
129
159
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
160
|
+
def previous_session?
|
161
|
+
type == :previous
|
162
|
+
end
|
163
|
+
|
164
|
+
def back_to_session?
|
165
|
+
type == :back_to
|
166
|
+
end
|
167
|
+
|
168
|
+
def to_s
|
169
|
+
[flow_string, state_string].join(SLUG_SEPARATOR)
|
170
|
+
end
|
171
|
+
|
172
|
+
private
|
173
|
+
|
174
|
+
def previous_session_key
|
175
|
+
[id, 'previous'].join('-')
|
137
176
|
end
|
138
177
|
|
139
|
-
def
|
140
|
-
|
178
|
+
def back_to_key
|
179
|
+
[id, 'back_to'].join('-')
|
141
180
|
end
|
142
181
|
|
143
|
-
def
|
144
|
-
|
145
|
-
|
146
|
-
|
182
|
+
def store_current_to_previous(existing_session:)
|
183
|
+
# Prevent previous_session from becoming current_session
|
184
|
+
if session == existing_session
|
185
|
+
Stealth::Logger.l(
|
186
|
+
topic: "previous_session",
|
187
|
+
message: "User #{id}: skipping setting to #{session}"\
|
188
|
+
' because it is the same as current_session'
|
189
|
+
)
|
190
|
+
else
|
191
|
+
Stealth::Logger.l(
|
192
|
+
topic: "previous_session",
|
193
|
+
message: "User #{id}: setting to #{existing_session}"
|
194
|
+
)
|
195
|
+
|
196
|
+
persist_key(
|
197
|
+
key: previous_session_key,
|
198
|
+
value: existing_session
|
199
|
+
)
|
147
200
|
end
|
148
201
|
end
|
149
202
|
|