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.
- checksums.yaml +7 -0
- data/app/controllers/concerns/glib/auth/policy.rb +148 -0
- data/app/controllers/concerns/glib/json/dynamic_text.rb +126 -0
- data/app/controllers/concerns/glib/json/libs.rb +144 -0
- data/app/controllers/concerns/glib/json/new_dynamic_text.rb +122 -0
- data/app/controllers/concerns/glib/json/transformation.rb +11 -0
- data/app/controllers/concerns/glib/json/traversal.rb +85 -0
- data/app/controllers/concerns/glib/json/ui.rb +70 -0
- data/app/controllers/concerns/glib/json/validation.rb +13 -0
- data/app/controllers/glib/home_controller.rb +16 -0
- data/app/helpers/glib/app_feature_support_helper.rb +16 -0
- data/app/helpers/glib/dynamic_images_helper.rb +52 -0
- data/app/helpers/glib/dynamic_texts_helper.rb +42 -0
- data/app/helpers/glib/forms_helper.rb +15 -0
- data/app/helpers/glib/json_ui/abstract_builder.rb +281 -0
- data/app/helpers/glib/json_ui/action_builder.rb +81 -0
- data/app/helpers/glib/json_ui/action_builder/dialogs.rb +58 -0
- data/app/helpers/glib/json_ui/action_builder/http.rb +19 -0
- data/app/helpers/glib/json_ui/action_builder/sheets.rb +15 -0
- data/app/helpers/glib/json_ui/action_builder/snackbars.rb +41 -0
- data/app/helpers/glib/json_ui/action_builder/windows.rb +25 -0
- data/app/helpers/glib/json_ui/dynamic_field_builders.rb +25 -0
- data/app/helpers/glib/json_ui/generic_builders.rb +28 -0
- data/app/helpers/glib/json_ui/list_builders.rb +87 -0
- data/app/helpers/glib/json_ui/menu_builder.rb +52 -0
- data/app/helpers/glib/json_ui/page_helper.rb +187 -0
- data/app/helpers/glib/json_ui/response_helper.rb +23 -0
- data/app/helpers/glib/json_ui/split_builders.rb +32 -0
- data/app/helpers/glib/json_ui/styling_helper.rb +25 -0
- data/app/helpers/glib/json_ui/table_builders.rb +74 -0
- data/app/helpers/glib/json_ui/view_builder.rb +185 -0
- data/app/helpers/glib/json_ui/view_builder/banners.rb +24 -0
- data/app/helpers/glib/json_ui/view_builder/charts.rb +33 -0
- data/app/helpers/glib/json_ui/view_builder/fields.rb +213 -0
- data/app/helpers/glib/json_ui/view_builder/panels.rb +219 -0
- data/app/models/glib/active_storage/attachment.rb +9 -0
- data/app/models/glib/active_storage/blob.rb +9 -0
- data/app/models/glib/dynamic_text_record.rb +9 -0
- data/app/models/glib/text.rb +96 -0
- data/app/policies/glib/application_policy.rb +164 -0
- data/app/validators/email_typo_validator.rb +38 -0
- data/app/validators/email_validator.rb +7 -0
- data/app/validators/url_validator.rb +20 -0
- data/app/views/app/views/json_ui/vue/renderer.html.erb +35 -0
- data/app/views/json_ui/garage/_nav_menu.json.jbuilder +71 -0
- data/app/views/json_ui/garage/actions/_dialogs.json.jbuilder +104 -0
- data/app/views/json_ui/garage/actions/_http.json.jbuilder +18 -0
- data/app/views/json_ui/garage/actions/_reload.json.jbuilder +17 -0
- data/app/views/json_ui/garage/actions/_sheets.json.jbuilder +19 -0
- data/app/views/json_ui/garage/actions/_snackbars.json.jbuilder +33 -0
- data/app/views/json_ui/garage/actions/_timeouts.json.jbuilder +18 -0
- data/app/views/json_ui/garage/actions/_windows.json.jbuilder +24 -0
- data/app/views/json_ui/garage/actions/dialogs_oauth_post.json.jbuilder +6 -0
- data/app/views/json_ui/garage/actions/index.json.jbuilder +23 -0
- data/app/views/json_ui/garage/forms/_alert_post_data.json.jbuilder +7 -0
- data/app/views/json_ui/garage/forms/basic.json.jbuilder +34 -0
- data/app/views/json_ui/garage/forms/basic_post.json.jbuilder +8 -0
- data/app/views/json_ui/garage/forms/checkboxes.json.jbuilder +44 -0
- data/app/views/json_ui/garage/forms/dynamic_group.json.jbuilder +41 -0
- data/app/views/json_ui/garage/forms/dynamic_select.json.jbuilder +25 -0
- data/app/views/json_ui/garage/forms/dynamic_select_data.json.jbuilder +38 -0
- data/app/views/json_ui/garage/forms/file_upload.json.jbuilder +58 -0
- data/app/views/json_ui/garage/forms/floating_submit.json.jbuilder +31 -0
- data/app/views/json_ui/garage/forms/generic_post.json.jbuilder +3 -0
- data/app/views/json_ui/garage/forms/get_request.json.jbuilder +28 -0
- data/app/views/json_ui/garage/forms/index.json.jbuilder +101 -0
- data/app/views/json_ui/garage/forms/pickers.json.jbuilder +46 -0
- data/app/views/json_ui/garage/forms/rich_text.json.jbuilder +40 -0
- data/app/views/json_ui/garage/forms/selects.json.jbuilder +70 -0
- data/app/views/json_ui/garage/forms/show_hide.json.jbuilder +88 -0
- data/app/views/json_ui/garage/forms/styled_boxes.json.jbuilder +32 -0
- data/app/views/json_ui/garage/forms/submission_flow.json.jbuilder +17 -0
- data/app/views/json_ui/garage/forms/submission_flow_post.json.jbuilder +24 -0
- data/app/views/json_ui/garage/forms/submission_indicator.json.jbuilder +63 -0
- data/app/views/json_ui/garage/forms/submission_indicator_post.json.jbuilder +25 -0
- data/app/views/json_ui/garage/forms/text_validation.json.jbuilder +22 -0
- data/app/views/json_ui/garage/home/blank.json.jbuilder +11 -0
- data/app/views/json_ui/garage/home/index.json.jbuilder +32 -0
- data/app/views/json_ui/garage/home/slow.json.jbuilder +11 -0
- data/app/views/json_ui/garage/lists/_infinite_scroll_section.json.jbuilder +20 -0
- data/app/views/json_ui/garage/lists/edit_actions.json.jbuilder +19 -0
- data/app/views/json_ui/garage/lists/fab.json.jbuilder +14 -0
- data/app/views/json_ui/garage/lists/index.json.jbuilder +23 -0
- data/app/views/json_ui/garage/lists/infinite_scroll.json.jbuilder +38 -0
- data/app/views/json_ui/garage/lists/templating.json.jbuilder +35 -0
- data/app/views/json_ui/garage/notifications/index.json.jbuilder +18 -0
- data/app/views/json_ui/garage/notifications/web_socket.json.jbuilder +60 -0
- data/app/views/json_ui/garage/pages/flat_centered.json.jbuilder +29 -0
- data/app/views/json_ui/garage/pages/full_width.json.jbuilder +29 -0
- data/app/views/json_ui/garage/pages/full_width_height.json.jbuilder +16 -0
- data/app/views/json_ui/garage/pages/index.json.jbuilder +47 -0
- data/app/views/json_ui/garage/pages/layout.json.jbuilder +19 -0
- data/app/views/json_ui/garage/pages/loading_indicator.json.jbuilder +10 -0
- data/app/views/json_ui/garage/pages/nav_buttons.json.jbuilder +21 -0
- data/app/views/json_ui/garage/pages/tab_bar.json.jbuilder +27 -0
- data/app/views/json_ui/garage/panels/_styled.json.jbuilder +78 -0
- data/app/views/json_ui/garage/panels/card.json.jbuilder +4 -0
- data/app/views/json_ui/garage/panels/carousel.json.jbuilder +16 -0
- data/app/views/json_ui/garage/panels/custom.json.jbuilder +17 -0
- data/app/views/json_ui/garage/panels/flow.json.jbuilder +49 -0
- data/app/views/json_ui/garage/panels/horizontal.json.jbuilder +91 -0
- data/app/views/json_ui/garage/panels/index.json.jbuilder +132 -0
- data/app/views/json_ui/garage/panels/outlined.json.jbuilder +4 -0
- data/app/views/json_ui/garage/panels/responsive.json.jbuilder +88 -0
- data/app/views/json_ui/garage/panels/split.json.jbuilder +183 -0
- data/app/views/json_ui/garage/panels/vertical.json.jbuilder +50 -0
- data/app/views/json_ui/garage/services/dynamic_text.json.jbuilder +13 -0
- data/app/views/json_ui/garage/services/image.json.jbuilder +47 -0
- data/app/views/json_ui/garage/services/index.json.jbuilder +17 -0
- data/app/views/json_ui/garage/tables/_autoload_section.json.jbuilder +13 -0
- data/app/views/json_ui/garage/tables/autoload_all.json.jbuilder +38 -0
- data/app/views/json_ui/garage/tables/autoload_as_needed.json.jbuilder +39 -0
- data/app/views/json_ui/garage/tables/export_import.json.jbuilder +29 -0
- data/app/views/json_ui/garage/tables/horizontal_scroll.json.jbuilder +26 -0
- data/app/views/json_ui/garage/tables/index.json.jbuilder +26 -0
- data/app/views/json_ui/garage/tables/layout.json.jbuilder +38 -0
- data/app/views/json_ui/garage/views/_chart_data.json.jbuilder +17 -0
- data/app/views/json_ui/garage/views/banners.json.jbuilder +51 -0
- data/app/views/json_ui/garage/views/calendar_data.json.jbuilder +30 -0
- data/app/views/json_ui/garage/views/carousels.json.jbuilder +37 -0
- data/app/views/json_ui/garage/views/charts.json.jbuilder +115 -0
- data/app/views/json_ui/garage/views/images.json.jbuilder +89 -0
- data/app/views/json_ui/garage/views/index.json.jbuilder +48 -0
- data/app/views/json_ui/garage/views/links.json.jbuilder +70 -0
- data/app/views/json_ui/garage/views/map_data.json.jbuilder +43 -0
- data/app/views/json_ui/garage/views/markdowns.json.jbuilder +41 -0
- data/app/views/json_ui/garage/views/misc.json.jbuilder +34 -0
- data/app/views/json_ui/garage/views/texts.json.jbuilder +41 -0
- data/app/views/layouts/json_ui/renderer.html.erb +32 -0
- data/config/routes.rb +8 -0
- data/lib/generators/glib/install_generator.rb +24 -0
- data/lib/generators/templates/20191017062519_create_texts.rb +12 -0
- data/lib/generators/templates/20191024063257_add_scope_to_texts.rb +7 -0
- data/lib/generators/templates/20191112095018_add_lang_to_texts.rb +7 -0
- data/lib/generators/templates/20191126071051_create_active_storage_tables.active_storage.rb +27 -0
- data/lib/generators/templates/database.yml +107 -0
- data/lib/generators/templates/dynamic_text.rb +2 -0
- data/lib/glib-web.rb +8 -0
- data/lib/glib/crypt.rb +1 -0
- data/lib/glib/crypt/utils.rb +26 -0
- data/lib/glib/dynamic_text.rb +1 -0
- data/lib/glib/dynamic_text/config.rb +21 -0
- data/lib/glib/engine.rb +7 -0
- data/lib/glib/json_crawler.rb +10 -0
- data/lib/glib/json_crawler/action_crawler.rb +20 -0
- data/lib/glib/json_crawler/action_crawlers/action_http.rb +14 -0
- data/lib/glib/json_crawler/action_crawlers/forms_submit.rb +48 -0
- data/lib/glib/json_crawler/action_crawlers/menu.rb +12 -0
- data/lib/glib/json_crawler/action_crawlers/nav_initiate.rb +15 -0
- data/lib/glib/json_crawler/action_crawlers/windows_open.rb +28 -0
- data/lib/glib/json_crawler/coverage.rb +20 -0
- data/lib/glib/json_crawler/http.rb +120 -0
- data/lib/glib/json_crawler/router.rb +86 -0
- data/lib/glib/test_helpers.rb +40 -0
- data/lib/glib/value.rb +7 -0
- data/lib/glib/version.rb +5 -0
- data/lib/tasks/db.rake +95 -0
- metadata +246 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 3a631905663a326cc5d4da2aa0be179812d12aae
|
|
4
|
+
data.tar.gz: a167fd02e4db101e5067832225762ba410bc401b
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 0a5094637dbe44532c384bd7e30a49bb3dd5377ef87cee6ea13da3528620aae8f2a43eba21f3077df4530a3356087851dcbd8be150d72a3ff1af70b4b3493afb
|
|
7
|
+
data.tar.gz: 03b85596d99b043700a6818feef54b6e45017e905800358502052a68bdf0d6cb472c64bc9bb352849a9628b587479bfbab41314da1543cb1f92317371639ac07
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
require 'pundit'
|
|
2
|
+
|
|
3
|
+
module Glib::Auth
|
|
4
|
+
module Policy
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
included do
|
|
8
|
+
include Pundit
|
|
9
|
+
include Overrides
|
|
10
|
+
extend ClassMethods
|
|
11
|
+
|
|
12
|
+
# TODO: Ultimately we want to uncomment this line, but:
|
|
13
|
+
# - Need to be able to set aside some time to run rspec tests to ensure nothing gets broken
|
|
14
|
+
# - Need to find a solution where we can reuse a single public policy
|
|
15
|
+
# after_action :verify_authorized
|
|
16
|
+
|
|
17
|
+
helper_method :policy, :can?, :cannot?
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
module Overrides
|
|
21
|
+
|
|
22
|
+
public # Override
|
|
23
|
+
def policy(record, policy_name = nil)
|
|
24
|
+
policy_name ||= record
|
|
25
|
+
|
|
26
|
+
@__pundit_policies ||= {}
|
|
27
|
+
return @__pundit_policies[policy_name] if @__pundit_policies[policy_name]
|
|
28
|
+
|
|
29
|
+
if policy_name.is_a?(Symbol) && policy_name.to_s.ends_with?('_admin')
|
|
30
|
+
policy_class = CommonAdminPolicy
|
|
31
|
+
else
|
|
32
|
+
policy_class = Pundit::PolicyFinder.new(policy_name).policy
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
raise "Policy not found for #{policy_name.is_a?(Symbol) || policy_name.is_a?(Class) ? policy_name : policy_name.class}" unless policy_class
|
|
36
|
+
|
|
37
|
+
@__pundit_policies[policy_name] = policy_class.new(current_user, record, policy_name, self, request, params, *policy_class.args_builder.call(self))
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Expose protected method
|
|
41
|
+
public # Override
|
|
42
|
+
def policy_scope(*args)
|
|
43
|
+
super
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
def raise_access_denied(record, policy)
|
|
49
|
+
raise UnauthorizedError.new(record: record, policy: policy, query: "#{action_name}?")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
public
|
|
53
|
+
def can?(action, record)
|
|
54
|
+
policy(record).send("#{action}?")
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
public
|
|
58
|
+
def cannot?(action, record)
|
|
59
|
+
!policy(record).send("#{action}?")
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Inspired from https://github.com/ryanb/cancan/wiki/Non-RESTful-Controllers
|
|
63
|
+
public
|
|
64
|
+
def glib_authorize_resource(*args)
|
|
65
|
+
options = args.extract_options!
|
|
66
|
+
resource_name = args.first
|
|
67
|
+
|
|
68
|
+
resource_name ||= controller_name.split('/').last.singularize
|
|
69
|
+
|
|
70
|
+
if (resource_key = options[:class]).nil?
|
|
71
|
+
policy_name = resource_name.camelize.constantize
|
|
72
|
+
else
|
|
73
|
+
policy_name = case resource_key
|
|
74
|
+
when false
|
|
75
|
+
resource_name.to_sym
|
|
76
|
+
when Symbol, Class
|
|
77
|
+
resource_key
|
|
78
|
+
else
|
|
79
|
+
raise "Invalid resource class: #{resource_key}"
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
resource_instance = instance_variable_get("@#{resource_name}") || policy_name
|
|
84
|
+
|
|
85
|
+
query = "#{action_name}?"
|
|
86
|
+
policy_instance = policy(resource_instance, policy_name)
|
|
87
|
+
raise_access_denied(resource_instance, policy_instance) unless policy_instance.public_send(query)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class UnauthorizedError < Pundit::NotAuthorizedError
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
module ClassMethods
|
|
98
|
+
def glib_auth_init
|
|
99
|
+
@@__glib_auth_init = true
|
|
100
|
+
|
|
101
|
+
before_action :glib_load_resource
|
|
102
|
+
before_action :glib_authorize_resource
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def glib_auth_inited?
|
|
106
|
+
@@__glib_auth_init ||= false
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# TODO: Consider deprecating
|
|
110
|
+
public
|
|
111
|
+
def authorize_resource(*args)
|
|
112
|
+
options = args.extract_options!
|
|
113
|
+
resource_name = args.first
|
|
114
|
+
|
|
115
|
+
self.before_action(options.slice(:only, :except, :if, :unless)) do |controller|
|
|
116
|
+
resource_name ||= resource_name_from_controller
|
|
117
|
+
|
|
118
|
+
begin
|
|
119
|
+
if !(resource_key = options[:class]).nil?
|
|
120
|
+
resource = case resource_key
|
|
121
|
+
when false
|
|
122
|
+
resource_name.to_sym
|
|
123
|
+
when Symbol, Class
|
|
124
|
+
resource_key
|
|
125
|
+
else
|
|
126
|
+
raise "Invalid resource class: #{resource_key}"
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
authorize resource
|
|
130
|
+
elsif (resource_instance = controller.instance_variable_get("@#{resource_name}"))
|
|
131
|
+
authorize resource_instance
|
|
132
|
+
else
|
|
133
|
+
authorize resource_name.camelize.constantize
|
|
134
|
+
end
|
|
135
|
+
rescue Pundit::NotAuthorizedError => e
|
|
136
|
+
raise_access_denied(e.record, e.policy)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
verify_authorized
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def resource_name_from_controller
|
|
145
|
+
params[:controller].split('/').last.singularize
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
module Glib::Json::DynamicText
|
|
2
|
+
def __json_traversal_register_dynamic_text
|
|
3
|
+
@__specs = {}
|
|
4
|
+
@__specs_db = {}
|
|
5
|
+
|
|
6
|
+
__json_traversal_on_traverse do |view|
|
|
7
|
+
extract_spec(view, 'text')
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
__json_traversal_on_complete do |view|
|
|
11
|
+
if @__specs.keys.size > 0
|
|
12
|
+
translated_texts = retrieve_texts(@__specs.keys)
|
|
13
|
+
# translated_texts = retrieve_local_texts(@__specs.keys).merge(retrieve_remote_texts(@__specs.keys))
|
|
14
|
+
translated_texts.each do |key, value|
|
|
15
|
+
@__specs[key].each do |spec|
|
|
16
|
+
spec.substitute_with(value)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
if @__specs_db[key] && @__specs_db[key].images.attached?
|
|
20
|
+
@__specs[key].each do |spec|
|
|
21
|
+
spec.substitute_image_with(@__specs_db[key].images)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def retrieve_texts
|
|
30
|
+
# TODO: Check local memory
|
|
31
|
+
# TODO: Then check DTR
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# def retrieve_remote_texts(keys)
|
|
35
|
+
# retries = 0
|
|
36
|
+
|
|
37
|
+
# begin
|
|
38
|
+
# response = RestClient.get(ENV['DTR_URL'], { params: { keys: keys } })
|
|
39
|
+
# rescue Errno::ECONNREFUSED, RestClient::InternalServerError, RestClient::Exceptions::OpenTimeout, RestClient::Exceptions::ReadTimeout
|
|
40
|
+
# if (retries += 1) <= 3
|
|
41
|
+
# puts "Timeout, retrying..."
|
|
42
|
+
# retry
|
|
43
|
+
# else
|
|
44
|
+
# raise
|
|
45
|
+
# end
|
|
46
|
+
# end
|
|
47
|
+
|
|
48
|
+
# JSON.parse(response)
|
|
49
|
+
# end
|
|
50
|
+
|
|
51
|
+
# def retrieve_local_texts(keys)
|
|
52
|
+
# translated_texts = {}
|
|
53
|
+
# db_keys = []
|
|
54
|
+
|
|
55
|
+
# redis = Glib::DynamicText::Config.redis
|
|
56
|
+
# contents = redis.pipelined do
|
|
57
|
+
# keys.each do |key|
|
|
58
|
+
# args = @__specs[key].first.args
|
|
59
|
+
# options = {
|
|
60
|
+
# scope: args.fetch(:scope, 'itinerarybuilder'),
|
|
61
|
+
# lang: args.fetch(:lang, 'en')
|
|
62
|
+
# }
|
|
63
|
+
|
|
64
|
+
# scope_key = "#{options[:scope]}.#{options[:lang]}.#{key}"
|
|
65
|
+
# redis.get(scope_key)
|
|
66
|
+
# end
|
|
67
|
+
# end
|
|
68
|
+
|
|
69
|
+
# keys.each_with_index do |key, index|
|
|
70
|
+
# if content = contents[index]
|
|
71
|
+
# translated_texts[key] = content
|
|
72
|
+
# db_keys << key if content.match(/\{\{image(\d)\}\}/)
|
|
73
|
+
# else
|
|
74
|
+
# db_keys << key
|
|
75
|
+
# end
|
|
76
|
+
# end
|
|
77
|
+
|
|
78
|
+
# if db_keys.size > 0
|
|
79
|
+
# texts = Glib::Text.where(key: db_keys)
|
|
80
|
+
# texts.each do |text|
|
|
81
|
+
# translated_texts[text.key] = text.content
|
|
82
|
+
# @__specs_db[text.key] = text
|
|
83
|
+
# end
|
|
84
|
+
# end
|
|
85
|
+
|
|
86
|
+
# translated_texts
|
|
87
|
+
# end
|
|
88
|
+
|
|
89
|
+
def extract_spec(view, prop)
|
|
90
|
+
if (spec = view[prop])
|
|
91
|
+
if spec.is_a?(Hash) && (key = spec['dt_key'])
|
|
92
|
+
@__specs[key] ||= []
|
|
93
|
+
@__specs[key] << TextSpec.new(view, prop, spec)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
TextSpec = Struct.new(:view, :prop, :args) do
|
|
99
|
+
def substitute_with(text)
|
|
100
|
+
view[prop] = text.gsub(/\{\{(\w+)\}\}/) { args.fetch($1, "{{#{$1}}}") }
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def substitute_image_with(images)
|
|
104
|
+
view[prop] = view[prop].gsub(/\{\{image(\d)\}\}/) {
|
|
105
|
+
if image = images[$1.to_i - 1]
|
|
106
|
+
image_server_url(image.blob.key)
|
|
107
|
+
else
|
|
108
|
+
"{{image#{$1}}}"
|
|
109
|
+
end
|
|
110
|
+
}
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# TODO: Reuse method from DynamicTextsHelper
|
|
114
|
+
def image_server_url(blob_key)
|
|
115
|
+
return unless blob_key.present?
|
|
116
|
+
|
|
117
|
+
uri = URI::HTTPS.build(
|
|
118
|
+
host: 'imageserver-demo.herokuapp.com',
|
|
119
|
+
path: "/image/#{ENV['AWS_S3_BUCKET']}/#{blob_key}",
|
|
120
|
+
query: { w: 100, h: 100 }.to_param
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
uri.to_s
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
module Glib::Json::Libs
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
included do
|
|
5
|
+
extend ClassMethods
|
|
6
|
+
|
|
7
|
+
helper_method :json_ui_app_bundle_id, :json_ui_app_build_version, :json_ui_app_device_os
|
|
8
|
+
helper_method :json_ui_app_is_android?, :json_ui_app_is_ios?, :json_ui_app_is_web?
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def json_ui_app_bundle_id
|
|
12
|
+
@json_ui_app_bundle_id ||= request.headers['JsonUiApp-Bundle-Id']
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def json_ui_app_build_version
|
|
16
|
+
@json_ui_app_build_version ||= request.headers['JsonUiApp-Build-Version']
|
|
17
|
+
@json_ui_app_build_version = params[:build_version] if @json_ui_app_build_version.nil? && Rails.env.development? # For easy testing
|
|
18
|
+
@json_ui_app_build_version
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def json_ui_app_device_os
|
|
22
|
+
@json_ui_app_device_os ||= request.headers['JsonUiApp-Device-Os']
|
|
23
|
+
@json_ui_app_device_os = params[:device_os] if @json_ui_app_device_os.nil? && Rails.env.development? # For easy testing
|
|
24
|
+
@json_ui_app_device_os || 'web'
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def json_ui_app_is_android?
|
|
28
|
+
json_ui_app_device_os == 'android'
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def json_ui_app_is_ios?
|
|
32
|
+
json_ui_app_device_os == 'ios'
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def json_ui_app_is_web?
|
|
36
|
+
json_ui_app_device_os == 'web'
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def json_ui_render(template, args = {})
|
|
40
|
+
JSON.parse(render_to_string(template, locals: args))
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def glib_force_json_ui
|
|
44
|
+
if params[:_render] != 'v1'
|
|
45
|
+
redirect_to url_for(params.to_unsafe_h.merge(_render: 'v1'))
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def glib_json_handle_403
|
|
50
|
+
render file: Rails.root.join('public', '404.html'), status: :forbidden
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def glib_json_handle_404
|
|
54
|
+
raise ActionController::RoutingError.new('Not Found')
|
|
55
|
+
|
|
56
|
+
# if json_ui_activated?
|
|
57
|
+
# render file: Rails.root.join('public', '404.html'), status: :not_found
|
|
58
|
+
# else
|
|
59
|
+
# raise exception
|
|
60
|
+
# end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def glib_json_handle_500(exception)
|
|
64
|
+
if json_ui_activated? && Rails.env.production?
|
|
65
|
+
Rollbar.error(exception) if defined?(Rollbar)
|
|
66
|
+
render file: Rails.root.join('public', '500.html'), status: :internal_server_error
|
|
67
|
+
else
|
|
68
|
+
raise exception
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
module ClassMethods
|
|
74
|
+
|
|
75
|
+
def json_libs_init(options)
|
|
76
|
+
include Glib::Json::Transformation
|
|
77
|
+
include Glib::Json::Validation
|
|
78
|
+
include Glib::Json::Ui
|
|
79
|
+
|
|
80
|
+
include Glib::Json::Traversal
|
|
81
|
+
include Glib::Json::NewDynamicText
|
|
82
|
+
|
|
83
|
+
before_action do
|
|
84
|
+
__json_ui_start(options)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Note that after_action gets executed in reverse
|
|
88
|
+
after_action do
|
|
89
|
+
__json_ui_commit(options)
|
|
90
|
+
end
|
|
91
|
+
after_action :__json_transformation_commit
|
|
92
|
+
after_action :__json_validate_perform
|
|
93
|
+
|
|
94
|
+
after_action :__json_traversal_perform
|
|
95
|
+
after_action :__json_traversal_register_dynamic_text
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def json_libs_set_locale
|
|
99
|
+
before_action do
|
|
100
|
+
# Need to explicitly fallback to EN
|
|
101
|
+
I18n.locale = params[:_locale] || :en
|
|
102
|
+
rescue
|
|
103
|
+
I18n.locale = :en
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def json_libs_force_json_ui
|
|
108
|
+
before_action :glib_force_json_ui
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def json_libs_rescue_csrf
|
|
112
|
+
rescue_from ActionController::InvalidAuthenticityToken do |exception|
|
|
113
|
+
sign_out(:user)
|
|
114
|
+
|
|
115
|
+
respond_to do |format|
|
|
116
|
+
format.json do
|
|
117
|
+
render json: {
|
|
118
|
+
onResponse: {
|
|
119
|
+
action: 'windows/open-v1',
|
|
120
|
+
url: root_url
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Call this before other rescues. Later rescue_from statements will take precedence, so more specific
|
|
129
|
+
# rescues have to be declared later.
|
|
130
|
+
def json_libs_rescue_500
|
|
131
|
+
rescue_from StandardError do |exception|
|
|
132
|
+
glib_json_handle_500(exception)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def json_libs_rescue_404
|
|
137
|
+
# Removed because it doesn't seem to offer anything extra
|
|
138
|
+
# rescue_from ActiveRecord::RecordNotFound do |exception|
|
|
139
|
+
# glib_json_handle_404
|
|
140
|
+
# end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
end
|
|
144
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
module Glib::Json::NewDynamicText
|
|
2
|
+
def __json_traversal_register_dynamic_text
|
|
3
|
+
@__specs = {}
|
|
4
|
+
@__specs_db = {}
|
|
5
|
+
|
|
6
|
+
__json_traversal_on_traverse do |view|
|
|
7
|
+
extract_spec(view, 'text')
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
__json_traversal_on_complete do |view|
|
|
11
|
+
if @__specs.keys.size > 0
|
|
12
|
+
# translated_texts = retrieve_remote_texts(@__specs.keys)
|
|
13
|
+
translated_texts = retrieve_local_texts(@__specs.keys).merge(retrieve_remote_texts(@__specs.keys))
|
|
14
|
+
translated_texts.each do |key, value|
|
|
15
|
+
@__specs[key].each do |spec|
|
|
16
|
+
spec.substitute_with(value)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
if @__specs_db[key] && @__specs_db[key].images.attached?
|
|
20
|
+
@__specs[key].each do |spec|
|
|
21
|
+
spec.substitute_image_with(@__specs_db[key].images)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def retrieve_example_texts(keys)
|
|
30
|
+
examples_translations = {
|
|
31
|
+
'home.json_ui_garage.hello' => 'Hello {{name}}',
|
|
32
|
+
'home.json_ui_garage.greeting' => 'Good day!',
|
|
33
|
+
'home.json_ui_garage.greeting_with_image' => 'Good day! (with image)',
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
translated_texts = {}
|
|
37
|
+
keys.each do |key|
|
|
38
|
+
translated_texts[key] = examples_translations[key]
|
|
39
|
+
end
|
|
40
|
+
translated_texts
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def retrieve_remote_texts(keys)
|
|
44
|
+
retries = 0
|
|
45
|
+
|
|
46
|
+
begin
|
|
47
|
+
response = RestClient.get(ENV['DTR_URL'], { params: { keys: keys } })
|
|
48
|
+
rescue Errno::ECONNREFUSED, RestClient::InternalServerError, RestClient::Exceptions::OpenTimeout, RestClient::Exceptions::ReadTimeout
|
|
49
|
+
if (retries += 1) <= 3
|
|
50
|
+
puts "Timeout, retrying..."
|
|
51
|
+
retry
|
|
52
|
+
else
|
|
53
|
+
raise
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
JSON.parse(response)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def retrieve_local_texts(keys)
|
|
61
|
+
translated_texts = {}
|
|
62
|
+
db_keys = []
|
|
63
|
+
|
|
64
|
+
redis = Glib::DynamicText::Config.redis
|
|
65
|
+
contents = redis.pipelined do
|
|
66
|
+
keys.each do |key|
|
|
67
|
+
args = @__specs[key].first.args
|
|
68
|
+
options = {
|
|
69
|
+
scope: args.fetch(:scope, 'itinerarybuilder'),
|
|
70
|
+
lang: args.fetch(:lang, 'en')
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
scope_key = "#{options[:scope]}.#{options[:lang]}.#{key}"
|
|
74
|
+
redis.get(scope_key)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
keys.each_with_index do |key, index|
|
|
79
|
+
if content = contents[index]
|
|
80
|
+
translated_texts[key] = content
|
|
81
|
+
db_keys << key if content.match(/\{\{image(\d)\}\}/)
|
|
82
|
+
else
|
|
83
|
+
db_keys << key
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
if db_keys.size > 0
|
|
88
|
+
texts = Glib::Text.where(key: db_keys)
|
|
89
|
+
texts.each do |text|
|
|
90
|
+
translated_texts[text.key] = text.content
|
|
91
|
+
@__specs_db[text.key] = text
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
translated_texts
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def extract_spec(view, prop)
|
|
99
|
+
if (spec = view[prop])
|
|
100
|
+
if spec.is_a?(Hash) && (key = spec['dt_key'])
|
|
101
|
+
@__specs[key] ||= []
|
|
102
|
+
@__specs[key] << TextSpec.new(view, prop, spec)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
TextSpec = Struct.new(:view, :prop, :args) do
|
|
108
|
+
def substitute_with(text)
|
|
109
|
+
view[prop] = text.gsub(/\{\{(\w+)\}\}/) { args.fetch($1, "{{#{$1}}}") }
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def substitute_image_with(images)
|
|
113
|
+
view[prop] = view[prop].gsub(/\{\{image(\d)\}\}/) {
|
|
114
|
+
if image = images[$1.to_i - 1]
|
|
115
|
+
ApplicationController.helpers.dynamic_image_url(image.blob.key)
|
|
116
|
+
else
|
|
117
|
+
"{{image#{$1}}}"
|
|
118
|
+
end
|
|
119
|
+
}
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|