infopark_cloud_connector 6.8.3.174.51542603 → 6.9.0.3.197272233

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. data/app/controllers/rails_connector/objs_controller.rb +44 -9
  2. data/app/helpers/rails_connector/cms_tag_helper.rb +45 -8
  3. data/app/helpers/rails_connector/editing_helper.rb +1 -6
  4. data/app/helpers/rails_connector/widget_helper.rb +13 -0
  5. data/app/views/rails_connector/_editing_javascript.html.erb +9 -0
  6. data/app/views/rails_connector/objs/create_widget.html.erb +1 -0
  7. data/config/routes.rb +6 -1
  8. data/lib/assets/fonts/infopark_icons-webfont.eot +0 -0
  9. data/lib/assets/fonts/infopark_icons-webfont.ttf +0 -0
  10. data/lib/assets/fonts/infopark_icons-webfont.woff +0 -0
  11. data/lib/assets/images/180x120.gif +0 -0
  12. data/lib/assets/images/irongrip.png +0 -0
  13. data/lib/assets/javascripts/infopark_editing.js +11267 -3387
  14. data/lib/assets/stylesheets/infopark_editing.css +1362 -12
  15. data/lib/generators/cms/migration/migration_generator.rb +7 -1
  16. data/lib/rails_connector/backend_not_available.rb +4 -0
  17. data/lib/rails_connector/basic_obj.rb +27 -1
  18. data/lib/rails_connector/cloud_engine.rb +13 -1
  19. data/lib/rails_connector/cms_api_search_request.rb +0 -3
  20. data/lib/rails_connector/cms_backend.rb +25 -7
  21. data/lib/rails_connector/cms_cache_storage.rb +4 -4
  22. data/lib/rails_connector/content_service.rb +36 -12
  23. data/lib/rails_connector/content_state_caching.rb +0 -18
  24. data/lib/rails_connector/default_search_request.rb +0 -1
  25. data/lib/rails_connector/migrations/migrator.rb +4 -1
  26. data/lib/rails_connector/widget_renderer.rb +41 -0
  27. data/lib/rails_connector/workspace.rb +4 -0
  28. data/lib/rails_connector/workspace_data_from_service.rb +35 -0
  29. metadata +9 -3
@@ -4,12 +4,18 @@ module Cms
4
4
 
5
5
  source_root File.expand_path('../templates', __FILE__)
6
6
 
7
+ class_option :path,
8
+ type: :string,
9
+ default: 'cms/migrate',
10
+ desc: 'Relative path to Rails.root where to place the migration file. Defaults to "cms/migrate".',
11
+ banner: 'PATH'
12
+
7
13
  def self.next_migration_number(dirname)
8
14
  Time.now.utc.strftime('%Y%m%d%H%M%S')
9
15
  end
10
16
 
11
17
  def create_migration_file
12
- migration_template('migration.rb', "cms/migrate/#{file_name}")
18
+ migration_template('migration.rb', "#{options[:path]}/#{file_name}")
13
19
  end
14
20
  end
15
21
  end
@@ -3,6 +3,10 @@ module RailsConnector
3
3
  class BackendNotAvailable < StandardError
4
4
  attr_reader :http_code
5
5
 
6
+ def self.from_socket_error(socket_error)
7
+ new(socket_error.message, 503)
8
+ end
9
+
6
10
  def initialize(message, http_code)
7
11
  @http_code = http_code
8
12
  super(message)
@@ -666,6 +666,29 @@ module RailsConnector
666
666
  data_from_cms.has_custom_attribute?(name.to_s)
667
667
  end
668
668
 
669
+ def widgets(attribute_name)
670
+ unless (type_of_attribute(attribute_name) == 'widget')
671
+ raise "Not a widget field: #{attribute_name}."
672
+ end
673
+
674
+ widgets = read_attribute(attribute_name.to_s, false)
675
+
676
+ return [] unless widgets.present?
677
+
678
+ output_objs = []
679
+ (widgets['layout'] || []).each do |widget_hash|
680
+ begin
681
+ widget_obj = self.class.find(widget_hash['widget'])
682
+ rescue RailsConnector::ResourceNotFound => e
683
+ end
684
+ if widget_obj.present? && widget_obj.path.start_with?("/_widgets/#{id}/")
685
+ output_objs << widget_obj
686
+ end
687
+ end
688
+
689
+ output_objs
690
+ end
691
+
669
692
  private
670
693
 
671
694
  attr_accessor :data_from_cms
@@ -675,7 +698,10 @@ module RailsConnector
675
698
  @attribute_cache = {}
676
699
  end
677
700
 
678
- def read_attribute(attribute_name)
701
+ def read_attribute(attribute_name, skip_widgets = true)
702
+ if skip_widgets && (type_of_attribute(attribute_name) == 'widget')
703
+ raise "Field #{attribute_name} not (yet) available, since it's a widget"
704
+ end
679
705
  @attribute_cache.fetch(attribute_name) do
680
706
  (raw_value, attribute_type) = data_from_cms.value_and_type_of(attribute_name)
681
707
  @attribute_cache[attribute_name] =
@@ -4,6 +4,18 @@ module ::RailsConnector
4
4
  # Specify which file should be precompiled for packaging
5
5
  app.config.assets.precompile += %w( infopark_editing.js infopark_editing.css )
6
6
  end
7
+
8
+ initializer "rails issue 4911 workaround" do
9
+ if Rails.version < '4'
10
+ max_size = [ActiveSupport::Cache::FileStore::FILENAME_MAX_SIZE, 228].min
11
+ silence_warnings { ActiveSupport::Cache::FileStore::FILENAME_MAX_SIZE = max_size }
12
+ end
13
+ end
14
+
15
+ initializer "widgets.attach_router" do |app|
16
+ ::RailsConnector::WidgetRenderer.class_eval do
17
+ include app.routes.url_helpers
18
+ end
19
+ end
7
20
  end
8
21
  end
9
-
@@ -3,7 +3,6 @@ module RailsConnector
3
3
  # This class provides a basic implementation for accessing the search using the cms api.
4
4
  # It can be activated by making it the superclass of SearchRequest.
5
5
  # It should be customized by subclassing.
6
- # @api public
7
6
  class CmsApiSearchRequest
8
7
 
9
8
  # Takes +query_string+ and +options+ for accessing Cms Api Search.
@@ -12,14 +11,12 @@ module RailsConnector
12
11
  #
13
12
  # <tt>:limit</tt>:: The maximum number of hits
14
13
  # <tt>:offset</tt>:: The search offset
15
- # @api public
16
14
  def initialize(query_string, options = {})
17
15
  @query_string = query_string
18
16
  @options = options
19
17
  end
20
18
 
21
19
  # Accesses Cms Api Search using #query and fetches search hits.
22
- # @api public
23
20
  def fetch_hits
24
21
  search_enum = search_results
25
22
 
@@ -82,17 +82,26 @@ module RailsConnector
82
82
  end
83
83
 
84
84
  def find_workspace_data_by_id(id)
85
- from_content_state_id = ContentStateCaching.find_content_state_id(id)
85
+ workspace_data_from_cache = WorkspaceDataFromService.find_from_cache(id)
86
+ from_content_state_id = workspace_data_from_cache.try(:content_state_id)
87
+
86
88
  request_params = {:workspace_id => id}
87
89
  request_params[:content_state_id] = from_content_state_id if from_content_state_id
88
- raw_data = ContentService.query('workspaces/query', request_params)
90
+
91
+ raw_data = if id == 'published' && workspace_data_from_cache
92
+ begin
93
+ ContentService.query('workspaces/query', request_params, timeout: 1)
94
+ rescue BackendNotAvailable => e
95
+ warn_backend_not_available(id, from_content_state_id, e.message)
96
+ return workspace_data_from_cache
97
+ end
98
+ else
99
+ ContentService.query('workspaces/query', request_params)
100
+ end
101
+
89
102
  if raw_workspace_data = raw_data['workspace']
90
103
  workspace_data = WorkspaceDataFromService.new(raw_workspace_data)
91
- if from_content_state_id != workspace_data.content_state_id
92
- ContentStateCaching.store_content_state(workspace_data)
93
- ContentStateCaching.store_content_state_id(workspace_data.id,
94
- workspace_data.content_state_id)
95
- end
104
+ workspace_data.store_in_cache if from_content_state_id != workspace_data.content_state_id
96
105
  workspace_data
97
106
  end
98
107
  end
@@ -198,6 +207,15 @@ module RailsConnector
198
207
  raise ArgumentError, "invalid index name '#{index}'" unless VALID_INDEX_NAMES.include?(index)
199
208
  end
200
209
 
210
+ def warn_backend_not_available(workspace_id, content_state_id, error_message)
211
+ message = <<-EOS
212
+ Couldn't connect to content service for workspace with id=#{workspace_id} and content_state_id=#{content_state_id}.
213
+ #{error_message}
214
+ Serving from cache.
215
+ EOS
216
+ Rails.logger.warn(message)
217
+ end
218
+
201
219
  end
202
220
 
203
221
  end
@@ -15,12 +15,12 @@ module CmsCacheStorage
15
15
  end
16
16
  end
17
17
 
18
- def read_workspace_content_state_id(workspace_id)
19
- cache.read("workspace/#{workspace_id}/content_state")
18
+ def read_workspace_data(workspace_id)
19
+ cache.read("workspace/#{workspace_id}")
20
20
  end
21
21
 
22
- def write_workspace_content_state_id(workspace_id, content_state_id)
23
- cache.write("workspace/#{workspace_id}/content_state", content_state_id)
22
+ def write_workspace_data(workspace_id, workspace_data)
23
+ cache.write("workspace/#{workspace_id}", workspace_data)
24
24
  end
25
25
 
26
26
  def read_content_state(content_state_id)
@@ -1,8 +1,20 @@
1
1
  module RailsConnector
2
2
  class ContentService
3
3
  DEFAULT_PROTOCOL = 'https'.freeze
4
- SOCKET_ERRORS = [EOFError, IOError, Errno::ECONNABORTED, Errno::ECONNRESET,
5
- Errno::EPIPE, Errno::EINVAL].freeze
4
+ DEFAULT_TIMEOUT = 10.freeze
5
+
6
+ SOCKET_ERRORS = [
7
+ EOFError,
8
+ Errno::ECONNABORTED,
9
+ Errno::ECONNREFUSED,
10
+ Errno::ECONNRESET,
11
+ Errno::EINVAL,
12
+ Errno::EPIPE,
13
+ Errno::ETIMEDOUT,
14
+ IOError,
15
+ SocketError,
16
+ Timeout::Error,
17
+ ].freeze
6
18
 
7
19
  class RateLimitExceeded < StandardError
8
20
  def initialize(retry_after)
@@ -33,15 +45,16 @@ class ContentService
33
45
  class << self
34
46
  @next_request_not_before = nil
35
47
 
36
- def query(path, payload)
48
+ def query(path, payload, options={})
49
+ timeout = options.fetch(:timeout, DEFAULT_TIMEOUT)
37
50
  retry_once_on_socket_error do
38
51
  retry_until_timeout_on_rate_limit_exceeded do
39
- ConnectionManager.ensure_started(uri)
52
+ ConnectionManager.ensure_started(uri, timeout)
40
53
  request = build_request(path, payload)
41
54
  if @next_request_not_before && @next_request_not_before > (now = Time.now)
42
55
  sleep @next_request_not_before - now
43
56
  end
44
- handle_response(ConnectionManager.connection.request(request))
57
+ handle_response(ConnectionManager.connection(timeout).request(request))
45
58
  end
46
59
  end
47
60
  end
@@ -57,8 +70,8 @@ class ContentService
57
70
  retried = false
58
71
  begin
59
72
  yield
60
- rescue *SOCKET_ERRORS
61
- raise if retried
73
+ rescue *SOCKET_ERRORS => e
74
+ raise BackendNotAvailable.from_socket_error(e) if retried
62
75
  ConnectionManager.ensure_finished
63
76
  retried = true
64
77
  retry
@@ -129,7 +142,8 @@ class ContentService
129
142
  end
130
143
 
131
144
  module ConnectionManager
132
- def self.connection
145
+ def self.connection(timeout=DEFAULT_TIMEOUT)
146
+ configure_timeout(@connection, timeout) if @connection
133
147
  @connection
134
148
  end
135
149
 
@@ -137,7 +151,7 @@ class ContentService
137
151
  @connection = conn
138
152
  end
139
153
 
140
- def self.ensure_started(uri)
154
+ def self.ensure_started(uri, timeout=DEFAULT_TIMEOUT)
141
155
  return if @connection && @connection.started?
142
156
  conn = Net::HTTP.new(uri.host, uri.port)
143
157
  if uri.scheme == 'https'
@@ -145,7 +159,10 @@ class ContentService
145
159
  conn.verify_mode = OpenSSL::SSL::VERIFY_PEER
146
160
  conn.ca_file = RailsConnector::Configuration.ca_file
147
161
  end
148
- retry_twice_on_socket_error { conn.start }
162
+ configure_timeout(conn, timeout)
163
+ retry_twice_on_socket_error do
164
+ conn.start
165
+ end
149
166
  @connection = conn
150
167
  end
151
168
 
@@ -161,12 +178,19 @@ class ContentService
161
178
  attempt = 0
162
179
  begin
163
180
  yield
164
- rescue *ContentService::SOCKET_ERRORS
165
- raise if attempt == 2
181
+ rescue *ContentService::SOCKET_ERRORS => e
182
+ raise BackendNotAvailable.from_socket_error(e) if attempt == 2
166
183
  attempt += 1
167
184
  retry
168
185
  end
169
186
  end
187
+
188
+ def configure_timeout(connection, timeout)
189
+ connection.open_timeout = timeout
190
+ connection.read_timeout = timeout
191
+ connection.ssl_timeout = timeout
192
+ end
193
+
170
194
  end
171
195
  end
172
196
  end
@@ -14,24 +14,6 @@ module ContentStateCaching
14
14
  # to the current content state's cache. Default depth is 5.
15
15
  attr_accessor :cache_replication_depth
16
16
 
17
- # Creates a new content state for given workspace with given ancetor and returns it.
18
- def store_content_state(workspace_data)
19
- ContentState.create(content_state_id: workspace_data.to_content_state_id,
20
- changes: workspace_data.changes,
21
- from_content_state_id: workspace_data.from_content_state_id)
22
- end
23
-
24
- # Fetches last known content state id for a given workspace id.
25
- # Returns nil if there is no content state for that workspace.
26
- def find_content_state_id(workspace_id)
27
- CmsCacheStorage.read_workspace_content_state_id(workspace_id)
28
- end
29
-
30
- # Stores current content state id for workspace with given id.
31
- def store_content_state_id(workspace_id, content_state_id)
32
- CmsCacheStorage.write_workspace_content_state_id(workspace_id, content_state_id)
33
- end
34
-
35
17
  # Updates caches with data from given workspace.
36
18
  # Should be called every time a new OBJ data has been fetched.
37
19
  def store_obj_data(workspace_data, index, key, data)
@@ -1,7 +1,6 @@
1
1
  module RailsConnector
2
2
  # This class provides a default implementation for accessing the search server.
3
3
  # It is used by {DefaultSearchController}.
4
- # @api public
5
4
  class DefaultSearchRequest < CmsApiSearchRequest
6
5
  end
7
6
  end
@@ -92,7 +92,10 @@ module RailsConnector
92
92
  end
93
93
 
94
94
  def migrations_paths
95
- ["#{Rails.root}/cms/migrate"]
95
+ Dir.glob([
96
+ Rails.root + 'cms/migrate',
97
+ Rails.root + 'app/widgets/**/migrate/',
98
+ ])
96
99
  end
97
100
 
98
101
  def runnable
@@ -0,0 +1,41 @@
1
+ module RailsConnector
2
+
3
+ class WidgetRenderer < AbstractController::Base
4
+ include AbstractController::Rendering
5
+ include AbstractController::Helpers
6
+
7
+ helper :cms, "rails_connector/widget"
8
+
9
+ self.view_paths = [File.join('app', 'widgets')]
10
+
11
+ def initialize(request)
12
+ @_request = request
13
+ end
14
+
15
+ def show(widget, obj, widget_field_name, container)
16
+ @widget = widget
17
+ @obj = obj
18
+ @widget_field_name = widget_field_name
19
+ @container = container
20
+
21
+ render_to_string "#{widget.obj_class.underscore}/show"
22
+ end
23
+
24
+ def thumbnail(widget_dir)
25
+ begin
26
+ render_to_string "#{widget_dir}/thumbnail"
27
+ rescue ActionView::MissingTemplate => e
28
+ view_context.widget_thumbnail(
29
+ widget_dir.titleize,
30
+ 'thumbnail.html.erb does not existing. Please provide one.',
31
+ view_context.image_tag('180x120.gif')
32
+ )
33
+ end
34
+ end
35
+
36
+ def request
37
+ @_request
38
+ end
39
+ end
40
+
41
+ end # module RailsConnector
@@ -41,6 +41,10 @@ class Workspace
41
41
  @workspace_data.revision_id
42
42
  end
43
43
 
44
+ def title
45
+ @workspace_data.title
46
+ end
47
+
44
48
  def data
45
49
  @workspace_data
46
50
  end
@@ -1,6 +1,14 @@
1
1
  module RailsConnector
2
2
 
3
3
  class WorkspaceDataFromService
4
+ # Fetches a workspace data previously store in cache storage.
5
+ # Returns nil if not found.
6
+ def self.find_from_cache(id)
7
+ if data = CmsCacheStorage.read_workspace_data(id)
8
+ new(data)
9
+ end
10
+ end
11
+
4
12
  def initialize(data)
5
13
  @data = data
6
14
  end
@@ -13,6 +21,10 @@ class WorkspaceDataFromService
13
21
  @data["id"]
14
22
  end
15
23
 
24
+ def title
25
+ @data["title"]
26
+ end
27
+
16
28
  # remove this method after DynamoCmsBackend has been removed from the Cloud Connector
17
29
  def content_cache_id=(id)
18
30
  # ignore, since not using content caches
@@ -41,6 +53,29 @@ class WorkspaceDataFromService
41
53
  def to_content_state_id
42
54
  diff && diff['to_content_state_id']
43
55
  end
56
+
57
+ # Serializes and stores a workspace data in cache storage.
58
+ # Also creates an appropriate content state if needed.
59
+ def store_in_cache
60
+ create_content_state if content_state_id
61
+ CmsCacheStorage.write_workspace_data(id, to_hash)
62
+ end
63
+
64
+ private
65
+
66
+ def to_hash
67
+ {
68
+ 'id' => id,
69
+ 'revision_id' => revision_id,
70
+ 'title' => title,
71
+ 'content_state_id' => content_state_id,
72
+ }
73
+ end
74
+
75
+ def create_content_state
76
+ ContentState.create(content_state_id: to_content_state_id, changes: changes,
77
+ from_content_state_id: from_content_state_id)
78
+ end
44
79
  end
45
80
 
46
81
  end # module RailsConnector
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: infopark_cloud_connector
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.8.3.174.51542603
4
+ version: 6.9.0.3.197272233
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-05 00:00:00.000000000 Z
12
+ date: 2013-04-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rest-client
@@ -73,10 +73,15 @@ files:
73
73
  - app/helpers/rails_connector/cms_tag_helper.rb
74
74
  - app/helpers/rails_connector/editing_helper.rb
75
75
  - app/helpers/rails_connector/marker_helper.rb
76
+ - app/helpers/rails_connector/widget_helper.rb
77
+ - app/views/rails_connector/_editing_javascript.html.erb
78
+ - app/views/rails_connector/objs/create_widget.html.erb
76
79
  - config/routes.rb
77
80
  - lib/assets/fonts/infopark_icons-webfont.eot
78
81
  - lib/assets/fonts/infopark_icons-webfont.ttf
79
82
  - lib/assets/fonts/infopark_icons-webfont.woff
83
+ - lib/assets/images/180x120.gif
84
+ - lib/assets/images/irongrip.png
80
85
  - lib/assets/javascripts/infopark_editing.js
81
86
  - lib/assets/stylesheets/infopark_editing.css
82
87
  - lib/generators/cms/migration/USAGE
@@ -122,6 +127,7 @@ files:
122
127
  - lib/rails_connector/obj_data_from_service.rb
123
128
  - lib/rails_connector/obj_search_enumerator.rb
124
129
  - lib/rails_connector/rack_middlewares.rb
130
+ - lib/rails_connector/widget_renderer.rb
125
131
  - lib/rails_connector/workspace.rb
126
132
  - lib/rails_connector/workspace_data_from_service.rb
127
133
  - lib/rails_connector/workspace_selection_middleware.rb
@@ -140,7 +146,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
140
146
  version: '0'
141
147
  segments:
142
148
  - 0
143
- hash: 676465587
149
+ hash: 779053553
144
150
  required_rubygems_version: !ruby/object:Gem::Requirement
145
151
  none: false
146
152
  requirements: