glib-web 0.5.5

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.
Files changed (158) hide show
  1. checksums.yaml +7 -0
  2. data/app/controllers/concerns/glib/auth/policy.rb +148 -0
  3. data/app/controllers/concerns/glib/json/dynamic_text.rb +126 -0
  4. data/app/controllers/concerns/glib/json/libs.rb +144 -0
  5. data/app/controllers/concerns/glib/json/new_dynamic_text.rb +122 -0
  6. data/app/controllers/concerns/glib/json/transformation.rb +11 -0
  7. data/app/controllers/concerns/glib/json/traversal.rb +85 -0
  8. data/app/controllers/concerns/glib/json/ui.rb +70 -0
  9. data/app/controllers/concerns/glib/json/validation.rb +13 -0
  10. data/app/controllers/glib/home_controller.rb +16 -0
  11. data/app/helpers/glib/app_feature_support_helper.rb +16 -0
  12. data/app/helpers/glib/dynamic_images_helper.rb +52 -0
  13. data/app/helpers/glib/dynamic_texts_helper.rb +42 -0
  14. data/app/helpers/glib/forms_helper.rb +15 -0
  15. data/app/helpers/glib/json_ui/abstract_builder.rb +281 -0
  16. data/app/helpers/glib/json_ui/action_builder.rb +81 -0
  17. data/app/helpers/glib/json_ui/action_builder/dialogs.rb +58 -0
  18. data/app/helpers/glib/json_ui/action_builder/http.rb +19 -0
  19. data/app/helpers/glib/json_ui/action_builder/sheets.rb +15 -0
  20. data/app/helpers/glib/json_ui/action_builder/snackbars.rb +41 -0
  21. data/app/helpers/glib/json_ui/action_builder/windows.rb +25 -0
  22. data/app/helpers/glib/json_ui/dynamic_field_builders.rb +25 -0
  23. data/app/helpers/glib/json_ui/generic_builders.rb +28 -0
  24. data/app/helpers/glib/json_ui/list_builders.rb +87 -0
  25. data/app/helpers/glib/json_ui/menu_builder.rb +52 -0
  26. data/app/helpers/glib/json_ui/page_helper.rb +187 -0
  27. data/app/helpers/glib/json_ui/response_helper.rb +23 -0
  28. data/app/helpers/glib/json_ui/split_builders.rb +32 -0
  29. data/app/helpers/glib/json_ui/styling_helper.rb +25 -0
  30. data/app/helpers/glib/json_ui/table_builders.rb +74 -0
  31. data/app/helpers/glib/json_ui/view_builder.rb +185 -0
  32. data/app/helpers/glib/json_ui/view_builder/banners.rb +24 -0
  33. data/app/helpers/glib/json_ui/view_builder/charts.rb +33 -0
  34. data/app/helpers/glib/json_ui/view_builder/fields.rb +213 -0
  35. data/app/helpers/glib/json_ui/view_builder/panels.rb +219 -0
  36. data/app/models/glib/active_storage/attachment.rb +9 -0
  37. data/app/models/glib/active_storage/blob.rb +9 -0
  38. data/app/models/glib/dynamic_text_record.rb +9 -0
  39. data/app/models/glib/text.rb +96 -0
  40. data/app/policies/glib/application_policy.rb +164 -0
  41. data/app/validators/email_typo_validator.rb +38 -0
  42. data/app/validators/email_validator.rb +7 -0
  43. data/app/validators/url_validator.rb +20 -0
  44. data/app/views/app/views/json_ui/vue/renderer.html.erb +35 -0
  45. data/app/views/json_ui/garage/_nav_menu.json.jbuilder +71 -0
  46. data/app/views/json_ui/garage/actions/_dialogs.json.jbuilder +104 -0
  47. data/app/views/json_ui/garage/actions/_http.json.jbuilder +18 -0
  48. data/app/views/json_ui/garage/actions/_reload.json.jbuilder +17 -0
  49. data/app/views/json_ui/garage/actions/_sheets.json.jbuilder +19 -0
  50. data/app/views/json_ui/garage/actions/_snackbars.json.jbuilder +33 -0
  51. data/app/views/json_ui/garage/actions/_timeouts.json.jbuilder +18 -0
  52. data/app/views/json_ui/garage/actions/_windows.json.jbuilder +24 -0
  53. data/app/views/json_ui/garage/actions/dialogs_oauth_post.json.jbuilder +6 -0
  54. data/app/views/json_ui/garage/actions/index.json.jbuilder +23 -0
  55. data/app/views/json_ui/garage/forms/_alert_post_data.json.jbuilder +7 -0
  56. data/app/views/json_ui/garage/forms/basic.json.jbuilder +34 -0
  57. data/app/views/json_ui/garage/forms/basic_post.json.jbuilder +8 -0
  58. data/app/views/json_ui/garage/forms/checkboxes.json.jbuilder +44 -0
  59. data/app/views/json_ui/garage/forms/dynamic_group.json.jbuilder +41 -0
  60. data/app/views/json_ui/garage/forms/dynamic_select.json.jbuilder +25 -0
  61. data/app/views/json_ui/garage/forms/dynamic_select_data.json.jbuilder +38 -0
  62. data/app/views/json_ui/garage/forms/file_upload.json.jbuilder +58 -0
  63. data/app/views/json_ui/garage/forms/floating_submit.json.jbuilder +31 -0
  64. data/app/views/json_ui/garage/forms/generic_post.json.jbuilder +3 -0
  65. data/app/views/json_ui/garage/forms/get_request.json.jbuilder +28 -0
  66. data/app/views/json_ui/garage/forms/index.json.jbuilder +101 -0
  67. data/app/views/json_ui/garage/forms/pickers.json.jbuilder +46 -0
  68. data/app/views/json_ui/garage/forms/rich_text.json.jbuilder +40 -0
  69. data/app/views/json_ui/garage/forms/selects.json.jbuilder +70 -0
  70. data/app/views/json_ui/garage/forms/show_hide.json.jbuilder +88 -0
  71. data/app/views/json_ui/garage/forms/styled_boxes.json.jbuilder +32 -0
  72. data/app/views/json_ui/garage/forms/submission_flow.json.jbuilder +17 -0
  73. data/app/views/json_ui/garage/forms/submission_flow_post.json.jbuilder +24 -0
  74. data/app/views/json_ui/garage/forms/submission_indicator.json.jbuilder +63 -0
  75. data/app/views/json_ui/garage/forms/submission_indicator_post.json.jbuilder +25 -0
  76. data/app/views/json_ui/garage/forms/text_validation.json.jbuilder +22 -0
  77. data/app/views/json_ui/garage/home/blank.json.jbuilder +11 -0
  78. data/app/views/json_ui/garage/home/index.json.jbuilder +32 -0
  79. data/app/views/json_ui/garage/home/slow.json.jbuilder +11 -0
  80. data/app/views/json_ui/garage/lists/_infinite_scroll_section.json.jbuilder +20 -0
  81. data/app/views/json_ui/garage/lists/edit_actions.json.jbuilder +19 -0
  82. data/app/views/json_ui/garage/lists/fab.json.jbuilder +14 -0
  83. data/app/views/json_ui/garage/lists/index.json.jbuilder +23 -0
  84. data/app/views/json_ui/garage/lists/infinite_scroll.json.jbuilder +38 -0
  85. data/app/views/json_ui/garage/lists/templating.json.jbuilder +35 -0
  86. data/app/views/json_ui/garage/notifications/index.json.jbuilder +18 -0
  87. data/app/views/json_ui/garage/notifications/web_socket.json.jbuilder +60 -0
  88. data/app/views/json_ui/garage/pages/flat_centered.json.jbuilder +29 -0
  89. data/app/views/json_ui/garage/pages/full_width.json.jbuilder +29 -0
  90. data/app/views/json_ui/garage/pages/full_width_height.json.jbuilder +16 -0
  91. data/app/views/json_ui/garage/pages/index.json.jbuilder +47 -0
  92. data/app/views/json_ui/garage/pages/layout.json.jbuilder +19 -0
  93. data/app/views/json_ui/garage/pages/loading_indicator.json.jbuilder +10 -0
  94. data/app/views/json_ui/garage/pages/nav_buttons.json.jbuilder +21 -0
  95. data/app/views/json_ui/garage/pages/tab_bar.json.jbuilder +27 -0
  96. data/app/views/json_ui/garage/panels/_styled.json.jbuilder +78 -0
  97. data/app/views/json_ui/garage/panels/card.json.jbuilder +4 -0
  98. data/app/views/json_ui/garage/panels/carousel.json.jbuilder +16 -0
  99. data/app/views/json_ui/garage/panels/custom.json.jbuilder +17 -0
  100. data/app/views/json_ui/garage/panels/flow.json.jbuilder +49 -0
  101. data/app/views/json_ui/garage/panels/horizontal.json.jbuilder +91 -0
  102. data/app/views/json_ui/garage/panels/index.json.jbuilder +132 -0
  103. data/app/views/json_ui/garage/panels/outlined.json.jbuilder +4 -0
  104. data/app/views/json_ui/garage/panels/responsive.json.jbuilder +88 -0
  105. data/app/views/json_ui/garage/panels/split.json.jbuilder +183 -0
  106. data/app/views/json_ui/garage/panels/vertical.json.jbuilder +50 -0
  107. data/app/views/json_ui/garage/services/dynamic_text.json.jbuilder +13 -0
  108. data/app/views/json_ui/garage/services/image.json.jbuilder +47 -0
  109. data/app/views/json_ui/garage/services/index.json.jbuilder +17 -0
  110. data/app/views/json_ui/garage/tables/_autoload_section.json.jbuilder +13 -0
  111. data/app/views/json_ui/garage/tables/autoload_all.json.jbuilder +38 -0
  112. data/app/views/json_ui/garage/tables/autoload_as_needed.json.jbuilder +39 -0
  113. data/app/views/json_ui/garage/tables/export_import.json.jbuilder +29 -0
  114. data/app/views/json_ui/garage/tables/horizontal_scroll.json.jbuilder +26 -0
  115. data/app/views/json_ui/garage/tables/index.json.jbuilder +26 -0
  116. data/app/views/json_ui/garage/tables/layout.json.jbuilder +38 -0
  117. data/app/views/json_ui/garage/views/_chart_data.json.jbuilder +17 -0
  118. data/app/views/json_ui/garage/views/banners.json.jbuilder +51 -0
  119. data/app/views/json_ui/garage/views/calendar_data.json.jbuilder +30 -0
  120. data/app/views/json_ui/garage/views/carousels.json.jbuilder +37 -0
  121. data/app/views/json_ui/garage/views/charts.json.jbuilder +115 -0
  122. data/app/views/json_ui/garage/views/images.json.jbuilder +89 -0
  123. data/app/views/json_ui/garage/views/index.json.jbuilder +48 -0
  124. data/app/views/json_ui/garage/views/links.json.jbuilder +70 -0
  125. data/app/views/json_ui/garage/views/map_data.json.jbuilder +43 -0
  126. data/app/views/json_ui/garage/views/markdowns.json.jbuilder +41 -0
  127. data/app/views/json_ui/garage/views/misc.json.jbuilder +34 -0
  128. data/app/views/json_ui/garage/views/texts.json.jbuilder +41 -0
  129. data/app/views/layouts/json_ui/renderer.html.erb +32 -0
  130. data/config/routes.rb +8 -0
  131. data/lib/generators/glib/install_generator.rb +24 -0
  132. data/lib/generators/templates/20191017062519_create_texts.rb +12 -0
  133. data/lib/generators/templates/20191024063257_add_scope_to_texts.rb +7 -0
  134. data/lib/generators/templates/20191112095018_add_lang_to_texts.rb +7 -0
  135. data/lib/generators/templates/20191126071051_create_active_storage_tables.active_storage.rb +27 -0
  136. data/lib/generators/templates/database.yml +107 -0
  137. data/lib/generators/templates/dynamic_text.rb +2 -0
  138. data/lib/glib-web.rb +8 -0
  139. data/lib/glib/crypt.rb +1 -0
  140. data/lib/glib/crypt/utils.rb +26 -0
  141. data/lib/glib/dynamic_text.rb +1 -0
  142. data/lib/glib/dynamic_text/config.rb +21 -0
  143. data/lib/glib/engine.rb +7 -0
  144. data/lib/glib/json_crawler.rb +10 -0
  145. data/lib/glib/json_crawler/action_crawler.rb +20 -0
  146. data/lib/glib/json_crawler/action_crawlers/action_http.rb +14 -0
  147. data/lib/glib/json_crawler/action_crawlers/forms_submit.rb +48 -0
  148. data/lib/glib/json_crawler/action_crawlers/menu.rb +12 -0
  149. data/lib/glib/json_crawler/action_crawlers/nav_initiate.rb +15 -0
  150. data/lib/glib/json_crawler/action_crawlers/windows_open.rb +28 -0
  151. data/lib/glib/json_crawler/coverage.rb +20 -0
  152. data/lib/glib/json_crawler/http.rb +120 -0
  153. data/lib/glib/json_crawler/router.rb +86 -0
  154. data/lib/glib/test_helpers.rb +40 -0
  155. data/lib/glib/value.rb +7 -0
  156. data/lib/glib/version.rb +5 -0
  157. data/lib/tasks/db.rake +95 -0
  158. metadata +246 -0
@@ -0,0 +1,2 @@
1
+ dt_redis_url = ENV.fetch('<%= options[:redis_env_key] %>', 'redis://localhost:6379')
2
+ $dt_redis = Redis.new(url: dt_redis_url)
@@ -0,0 +1,8 @@
1
+ require "glib/version"
2
+ require "glib/engine" if defined?(::Rails)
3
+ require "glib/value"
4
+ require "glib/json_crawler"
5
+
6
+ require 'glib/dynamic_text'
7
+ require 'glib/crypt'
8
+ require 'glib/test_helpers'
@@ -0,0 +1 @@
1
+ require_relative './crypt/utils'
@@ -0,0 +1,26 @@
1
+ module Glib
2
+ module Crypt
3
+ class Utils
4
+ def self.encrypt(original_message, encryption_secret, encryption_salt)
5
+ encryptor = message_encryptor(encryption_secret, encryption_salt)
6
+ CGI.escape(encryptor.encrypt_and_sign(original_message))
7
+ end
8
+
9
+ def self.decrypt(encrypted_message, encryption_secret, encryption_salt)
10
+ encryptor = message_encryptor(encryption_secret, encryption_salt)
11
+ begin
12
+ encryptor.decrypt_and_verify(CGI.unescape(encrypted_message))
13
+ rescue ActiveSupport::MessageEncryptor::InvalidMessage
14
+ nil
15
+ end
16
+ end
17
+
18
+ private
19
+ def self.message_encryptor(encryption_secret, encryption_salt)
20
+ key_generator = ActiveSupport::KeyGenerator.new(encryption_secret, iterations: 1000)
21
+ key_secret = key_generator.generate_key(encryption_salt, 32)
22
+ ActiveSupport::MessageEncryptor.new(key_secret, digest: 'SHA1', serializer: JSON)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1 @@
1
+ require_relative './dynamic_text/config'
@@ -0,0 +1,21 @@
1
+ module Glib
2
+ module DynamicText
3
+ class Config
4
+ @@redis = nil
5
+ @@database_url = nil
6
+
7
+ def self.redis
8
+ if @@redis.nil?
9
+ redis_url = ENV.fetch('DT_REDIS_URL', 'redis://localhost:6379')
10
+ # Allow application to specify their own $dt_redis
11
+ @@redis = $dt_redis || Redis.new(url: redis_url)
12
+ end
13
+ @@redis
14
+ end
15
+
16
+ def self.database_url
17
+ @@database_url ||= ENV['DT_DATABASE_URL']
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,7 @@
1
+ module Glib
2
+ module Web
3
+ class Engine < ::Rails::Engine
4
+ # isolate_namespace Glib::Web
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ require_relative './json_crawler/http'
2
+ require_relative './json_crawler/router'
3
+ require_relative './json_crawler/action_crawler'
4
+ require_relative './json_crawler/coverage'
5
+
6
+ require_relative './json_crawler/action_crawlers/nav_initiate'
7
+ require_relative './json_crawler/action_crawlers/windows_open'
8
+ require_relative './json_crawler/action_crawlers/action_http'
9
+ require_relative './json_crawler/action_crawlers/forms_submit'
10
+ require_relative './json_crawler/action_crawlers/menu'
@@ -0,0 +1,20 @@
1
+ module Glib
2
+ module JsonCrawler
3
+ class ActionCrawler
4
+ def initialize(http)
5
+ @http = http
6
+ end
7
+
8
+ def click(object)
9
+ @http.router.step(@http, object)
10
+ end
11
+
12
+ def crawl(views)
13
+ @http.router.crawl_multiple views, ->(view) do
14
+ click view
15
+ end
16
+ end
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ module Glib
2
+ module JsonCrawler
3
+ class ActionHttp < ActionCrawler
4
+ def initialize(method, http, args, controller)
5
+ @http = http
6
+ json = @http.send(method, args['url'], controller, args.fetch('formData', {}))
7
+
8
+ unless json.nil?
9
+ click(json)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,48 @@
1
+ module Glib
2
+ module JsonCrawler
3
+ class FormsSubmit < ActionCrawler
4
+ def initialize(http, form)
5
+ super(http)
6
+
7
+ raise 'Submit action needs to be inside a form' unless form
8
+
9
+ @http = http
10
+
11
+ method = form['method']
12
+ action = "forms/#{method}"
13
+
14
+ case method
15
+ when 'patch', 'put'
16
+ submit_update(form, action)
17
+ else
18
+ url = form['url']
19
+ http.router.log action, url
20
+ end
21
+ end
22
+
23
+ def submit_update(view, action)
24
+ url = view['url']
25
+ fields = []
26
+ params = {}
27
+ @http.router.crawl_multiple view['childViews'], ->(child) do
28
+ name = child['view']
29
+ if name.start_with?('fields/')
30
+ fields << child
31
+
32
+ include_params = case name
33
+ when 'fields/check', 'fields/check-v1'
34
+ child['checked']
35
+ else
36
+ true
37
+ end
38
+
39
+ params[child['name']] = child['value'] if include_params
40
+ end
41
+ end
42
+
43
+ json = @http.patch url, action, params
44
+ click(json)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,12 @@
1
+ module Glib
2
+ module JsonCrawler
3
+ class Menu < ActionCrawler
4
+ def initialize(http, args, action)
5
+ super(http)
6
+
7
+ @http.router.log action, nil
8
+ crawl args['buttons']
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ module Glib
2
+ module JsonCrawler
3
+ class NavInitiate < ActionCrawler
4
+ def initialize(http, args, action)
5
+ super(http)
6
+
7
+ @http = http
8
+ if (json = (@http.get args['url'], action, args.except('url'))) && (left_drawer = json['leftDrawer'])
9
+ crawl left_drawer['header']&.[]('childViews')
10
+ crawl left_drawer['rows']
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,28 @@
1
+ module Glib
2
+ module JsonCrawler
3
+ class WindowsOpen < ActionCrawler
4
+ def initialize(http, args, action)
5
+ @http = http
6
+ if (url = args['url'])
7
+ json = @http.get(url, action, args.except('url'))
8
+
9
+ unless json.nil?
10
+ crawl json['header']&.[]('childViews')
11
+ crawl json['body']&.[]('childViews')
12
+ crawl json['footer']&.[]('childViews')
13
+
14
+ json['rightNavButtons']&.each do |button|
15
+ if button['buttons'].present?
16
+ button['buttons'].each do |inner_button|
17
+ click inner_button
18
+ end
19
+ else
20
+ click button
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,20 @@
1
+ module Glib
2
+ module JsonCrawler
3
+ class Coverage
4
+ @@files = []
5
+ @@coverage_files = Set.new
6
+
7
+ def self.files
8
+ @@files
9
+ end
10
+
11
+ def self.files=(files)
12
+ @@files = files
13
+ end
14
+
15
+ def self.coverage_files
16
+ @@coverage_files
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,120 @@
1
+ module Glib
2
+ module JsonCrawler
3
+ class Http
4
+ attr_accessor :history, :response_times, :user, :router
5
+
6
+ URI_REGEXP = /\A#{URI::regexp}\z/
7
+
8
+ VALID_RESPONSE_CODES = [
9
+ (200..299).to_a,
10
+ ## Note, the JSON API does not allow redirects
11
+ # 401, ## UNAUTHORIZED Should be used for not-logged-in
12
+ # 403, ## FORBIDDEN Should be used for logged-in but not allowed to access
13
+ ].flatten
14
+
15
+ def initialize(context, user, router)
16
+ @context = context
17
+ @history = []
18
+ @response_times = []
19
+ @user = user
20
+ @router = router
21
+ end
22
+
23
+ def get(url, action, params = {}, inspect_result = true)
24
+ fetch(:get, url, action, params, inspect_result)
25
+ end
26
+
27
+ def post(url, action, params)
28
+ fetch(:post, url, action, params)
29
+ end
30
+
31
+ def patch(url, action, params)
32
+ fetch(:patch, url, action, params)
33
+ end
34
+
35
+ def put(url, action, params)
36
+ fetch(:put, url, action, params)
37
+ end
38
+
39
+ def delete(url, action, params = {})
40
+ fetch(:delete, url, action, {})
41
+ end
42
+
43
+ private
44
+ Response = Struct.new :code, :headers, :media_type, :body do
45
+ def initialize(*)
46
+ super
47
+ self.headers ||= {}
48
+ self.media_type ||= 'text/plain'
49
+ end
50
+ end
51
+
52
+ def fetch(method, url, action, params = {}, inspect_result = true)
53
+ return nil if url.blank?
54
+
55
+ if method == :get
56
+ return nil if history.include?(url)
57
+
58
+ history << url
59
+ end
60
+
61
+ if !URI_REGEXP.match(url)
62
+ raise "Invalid URL: `#{url}`. Make sure to use the absolute URL."
63
+ end
64
+
65
+ http_header = {
66
+ 'Client-DeviceOS' => user[:device],
67
+ 'Client-Version' => user[:version],
68
+ 'X-CSRF-Token' => user[:token]
69
+ }
70
+ http_header.merge!(params[:headers]) if params[:headers].present?
71
+
72
+ params.each do |name, value|
73
+ params[name] = '' if value.is_a?(Array) && value.size == 0
74
+ end
75
+
76
+ response = nil
77
+ begin
78
+ @context.send(method, url, params: params, headers: http_header)
79
+ raw_response = @context.response
80
+ response = Response.new(raw_response.code.to_i, raw_response.headers, raw_response.media_type, raw_response.body)
81
+
82
+ if (controller = @context.controller)
83
+ Glib::JsonCrawler::Coverage.coverage_files.add(controller.class.instance_method(controller.action_name).source_location.first)
84
+ end
85
+ rescue => ex
86
+ if !inspect_result
87
+ case ex
88
+ when ActionController::RoutingError, ActiveRecord::RecordNotFound
89
+ response = Response.new(404)
90
+ end
91
+ end
92
+
93
+ if !response
94
+ puts "Crashed on #{url}"
95
+ raise
96
+ end
97
+ end
98
+
99
+ @router.log(action, url, response)
100
+
101
+ if inspect_result
102
+ if (code = response.code) == 302
103
+ redirect_uri = URI(response.headers['Location'])
104
+ redirect_uri.query = [redirect_uri.query, 'format=json'].compact.join('&')
105
+ get redirect_uri.to_s, action, params
106
+ else
107
+ response_times << response.headers['X-Runtime'].to_f
108
+
109
+ @context.assert_includes VALID_RESPONSE_CODES, code, "Expected a valid response but was [#{response.code}] #{Rack::Utils::HTTP_STATUS_CODES[response.code.to_i]}:\n#{url}"
110
+ if response.media_type == 'application/json'
111
+ JSON.parse(response.body)
112
+ else
113
+ nil
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,86 @@
1
+ module Glib
2
+ module JsonCrawler
3
+ class Router
4
+ attr_reader :read_only_actions
5
+
6
+ def log(action, url, response = nil)
7
+ @logger.puts ' ' * @depth + [
8
+ action,
9
+ response.present? ? response.code : nil,
10
+ url
11
+ ].compact.join(' :: ')
12
+ end
13
+
14
+ def initialize(logger)
15
+ @depth = -1
16
+ @logger = logger
17
+ @visitor = Glib::Json::Traversal::Visitor.new
18
+ @read_only_actions = Set.new
19
+ end
20
+
21
+ def step(http, args)
22
+ case args['view']
23
+ when 'fields/submit-v1', 'fields/submit'
24
+ @depth += 1
25
+ forms = @visitor.forms
26
+ JsonCrawler::FormsSubmit.new(http, forms.last)
27
+ @depth -= 1
28
+ return
29
+ end
30
+
31
+ if args.is_a?(Hash) && args['rel'] != 'nofollow'
32
+ if (onClick = (args.fetch('onClick', nil) || args.fetch('onResponse', nil)))
33
+ action = onClick['action']
34
+ params = onClick
35
+ end
36
+
37
+ if action.present?
38
+ @depth += 1
39
+ case action
40
+ when 'initiate_navigation'
41
+ @read_only_actions.add([action, params['url']])
42
+ JsonCrawler::NavInitiate.new(http, params, action)
43
+ when 'windows/open-v1', 'dialogs/open-v1', 'windows/reload-v1', 'windows/open', 'dialogs/open', 'windows/reload'
44
+ @read_only_actions.add([action, params['url']])
45
+ JsonCrawler::WindowsOpen.new(http, params, action)
46
+ when 'sheets/select-v1', 'sheets/select'
47
+ JsonCrawler::Menu.new(http, params, action)
48
+ when 'http/post-v1', 'http/post'
49
+ JsonCrawler::ActionHttp.new(:post, http, params, action)
50
+ when 'forms/submit-v1', 'forms/submit'
51
+ forms = @visitor.forms
52
+ # raise 'Submit action needs to be inside a form' if forms.size < 1
53
+ JsonCrawler::FormsSubmit.new(http, forms.last)
54
+ else
55
+ unless [
56
+ 'http/delete-v1', 'dialogs/oauth-v1', 'windows/openWeb-v1',
57
+ 'http/delete', 'dialogs/oauth', 'windows/openWeb'
58
+ ].include?(action)
59
+ @read_only_actions.add([action, params['url']])
60
+ end
61
+ self.log action, params['url']
62
+ end
63
+ @depth -= 1
64
+ # child
65
+ end
66
+ end
67
+ end
68
+
69
+ def follow(http, target_router)
70
+ @depth += 1
71
+ target_router.read_only_actions.each do |crawler_action|
72
+ action, url = crawler_action
73
+ http.get(url, action, {}, false)
74
+ end
75
+ end
76
+
77
+ def tear_down
78
+ @logger.close
79
+ end
80
+
81
+ def crawl_multiple(views, block)
82
+ @visitor.traverse_multiple views, block
83
+ end
84
+ end
85
+ end
86
+ end