infopark_cloud_connector 7.0.2 → 7.1.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.
Files changed (61) hide show
  1. checksums.yaml +8 -8
  2. data/app/controllers/rails_connector/objs_controller.rb +29 -37
  3. data/app/helpers/rails_connector/cms_asset_helper.rb +1 -1
  4. data/app/helpers/rails_connector/cms_tag_helper.rb +1 -1
  5. data/app/helpers/rails_connector/default_cms_routing_helper.rb +1 -3
  6. data/app/helpers/rails_connector/display_helper.rb +5 -1
  7. data/app/views/rails_connector/_editing_javascript.html.erb +3 -2
  8. data/config/ca-bundle.crt +2 -2
  9. data/config/routes.rb +3 -0
  10. data/lib/assets/fonts/infopark_icons-webfont.eot +0 -0
  11. data/lib/assets/fonts/infopark_icons-webfont.ttf +0 -0
  12. data/lib/assets/fonts/infopark_icons-webfont.woff +0 -0
  13. data/lib/assets/images/apple-touch-icon.jpg +0 -0
  14. data/lib/assets/images/favicon.ico +0 -0
  15. data/lib/assets/images/ip_logo.svg +50 -0
  16. data/lib/assets/javascripts/infopark_editing.js +903 -164
  17. data/lib/assets/stylesheets/infopark_editing.css +222 -271
  18. data/lib/infopark_cloud_connector.rb +0 -1
  19. data/lib/rails_connector/attribute_content.rb +25 -74
  20. data/lib/rails_connector/backend_error.rb +4 -0
  21. data/lib/rails_connector/basic_obj.rb +173 -20
  22. data/lib/rails_connector/basic_widget.rb +42 -1
  23. data/lib/rails_connector/blob.rb +1 -1
  24. data/lib/rails_connector/cache_middleware.rb +2 -2
  25. data/lib/rails_connector/cms_backend.rb +51 -33
  26. data/lib/rails_connector/cms_rest_api.rb +13 -8
  27. data/lib/rails_connector/cms_rest_api/attribute_serializer.rb +62 -0
  28. data/lib/rails_connector/cms_rest_api/blob_uploader.rb +18 -0
  29. data/lib/rails_connector/communication_error.rb +17 -0
  30. data/lib/rails_connector/configuration.rb +28 -0
  31. data/lib/rails_connector/connection_manager.rb +2 -2
  32. data/lib/rails_connector/content_conversion.rb +16 -62
  33. data/lib/rails_connector/content_service.rb +2 -2
  34. data/lib/rails_connector/engine.rb +2 -1
  35. data/lib/rails_connector/html_string.rb +0 -1
  36. data/lib/rails_connector/link.rb +41 -33
  37. data/lib/rails_connector/link_parser.rb +72 -0
  38. data/lib/rails_connector/migrations/migration_dsl.rb +13 -0
  39. data/lib/rails_connector/{backend_not_available.rb → network_error.rb} +1 -6
  40. data/lib/rails_connector/obj_data.rb +4 -0
  41. data/lib/rails_connector/obj_data_from_hash.rb +6 -0
  42. data/lib/rails_connector/obj_data_from_service.rb +37 -3
  43. data/lib/rails_connector/obj_params_parser.rb +50 -0
  44. data/lib/rails_connector/obj_search_builder.rb +62 -0
  45. data/lib/rails_connector/obj_search_enumerator.rb +60 -5
  46. data/lib/rails_connector/rate_limit_exceeded.rb +5 -0
  47. data/lib/rails_connector/revision.rb +9 -0
  48. data/lib/rails_connector/string_tagging.rb +1 -12
  49. data/lib/rails_connector/text_link.rb +52 -0
  50. data/lib/rails_connector/text_link_conversion.rb +50 -0
  51. data/lib/rails_connector/workspace.rb +125 -3
  52. data/lib/rails_connector/workspace_data_from_service.rb +30 -31
  53. data/lib/rails_connector/workspace_selection_middleware.rb +62 -20
  54. data/lib/tasks/cache.rake +2 -0
  55. data/lib/tasks/rails_connector/cache_garbage_collector_task.rb +98 -0
  56. metadata +24 -17
  57. data/lib/assets/images/ip_logo_app.png +0 -0
  58. data/lib/assets/images/ip_logo_app2x.png +0 -0
  59. data/lib/assets/images/irongrip.png +0 -0
  60. data/lib/rails_connector/link_resolvable.rb +0 -9
  61. data/lib/rails_connector/rack_middlewares.rb +0 -6
@@ -108,6 +108,8 @@ module RailsConnector
108
108
  #
109
109
  # @api public
110
110
  class ObjSearchEnumerator
111
+ class UnregisteredObjFormat < StandardError; end
112
+
111
113
  include Enumerable
112
114
 
113
115
  attr_reader :query
@@ -145,6 +147,7 @@ module RailsConnector
145
147
  "Valid operators are: #{valid_boost_operators.join(', ')}"
146
148
  end
147
149
  end
150
+ @size = nil
148
151
  @query = (query || []) + [subquery]
149
152
 
150
153
  self
@@ -172,6 +175,7 @@ module RailsConnector
172
175
  end
173
176
  subquery = {:field => field, :operator => real_operator, :value => convert_value(value),
174
177
  :negate => true}
178
+ @size = nil
175
179
  @query = (query || []) + [subquery]
176
180
 
177
181
  self
@@ -221,6 +225,12 @@ module RailsConnector
221
225
  self
222
226
  end
223
227
 
228
+ def include_deleted
229
+ @include_deleted = true
230
+
231
+ self
232
+ end
233
+
224
234
  # @!endgroup
225
235
 
226
236
  # Iterates over the search result, yielding {BasicObj Obj}.
@@ -241,7 +251,7 @@ module RailsConnector
241
251
 
242
252
  offset += 1
243
253
  hit = current_batch.shift
244
- yield Obj.find(hit['id'])
254
+ yield hit
245
255
  end
246
256
  end
247
257
 
@@ -249,7 +259,39 @@ module RailsConnector
249
259
  # @return [Integer]
250
260
  # @api public
251
261
  def size
252
- @size ||= CmsRestApi.get(resource_path, {:query => query, :size => 0})['total'].to_i
262
+ return @size if @size
263
+
264
+ size_query = {
265
+ query: query,
266
+ size: 0
267
+ }
268
+ if @include_deleted
269
+ size_query[:options] = {
270
+ include_deleted: true
271
+ }
272
+ end
273
+
274
+ @size ||= CmsRestApi.get(resource_path, size_query)['total'].to_i
275
+ end
276
+
277
+ # load a single batch of search results from the backend.
278
+ # returns an array of Objs.
279
+ # will usually return `batch_size` results if available,
280
+ # but may occasionally return fewer than `batch_size` results (due to rate limit, for example).
281
+ # @api public
282
+ def load_batch
283
+ next_batch = fetch_next_batch(options[:offset] || 0)
284
+
285
+ formatter = @formatter || -> obj { obj.id }
286
+ next_batch.first.map { |obj| formatter.call(obj) }
287
+ end
288
+
289
+ def format(name)
290
+ if @formatter = Configuration.obj_formats[name]
291
+ self
292
+ else
293
+ raise UnregisteredObjFormat, "The format with name '#{name}' is not registered."
294
+ end
253
295
  end
254
296
 
255
297
  # @api public
@@ -300,7 +342,12 @@ module RailsConnector
300
342
  def fetch_next_batch(offset)
301
343
  request_result = CmsRestApi.get(resource_path, search_dsl(offset))
302
344
 
303
- [request_result['results'], request_result['total'].to_i]
345
+ obj_ids = request_result['results'].map { |result| result['id'] }
346
+ objs = Obj.find_including_deleted(obj_ids)
347
+
348
+ @size = request_result['total'].to_i
349
+
350
+ [objs, @size]
304
351
  end
305
352
 
306
353
  def resource_path
@@ -309,13 +356,21 @@ module RailsConnector
309
356
 
310
357
  def search_dsl(offset)
311
358
  patches = {
312
- :offset => offset,
313
- :query => query,
359
+ offset: offset,
360
+ query: query,
314
361
  }
315
362
  if @reverse_order
316
363
  patches[:sort_order] = options[:sort_by].present? ? :desc : :asc
317
364
  end
365
+
366
+ if @include_deleted
367
+ patches[:options] = {
368
+ include_deleted: true
369
+ }
370
+ end
371
+
318
372
  options.merge(patches)
319
373
  end
374
+
320
375
  end
321
376
  end
@@ -0,0 +1,5 @@
1
+ module RailsConnector
2
+ class RateLimitExceeded < CommunicationError
3
+
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ module RailsConnector
2
+
3
+ class Revision < Struct.new(:id, :content_state, :workspace)
4
+ def initialize(options)
5
+ super(*options.values_at(:id, :content_state, :workspace))
6
+ end
7
+ end
8
+
9
+ end
@@ -4,26 +4,15 @@ module RailsConnector
4
4
  module StringTagging
5
5
 
6
6
  # html flavour
7
- def self.tag_as_html(string, source)
7
+ def self.tag_as_html(string)
8
8
  unless string.blank?
9
9
  class << string
10
10
  include RailsConnector::HtmlString
11
11
  end
12
- string.source = source
13
12
  end
14
13
  string
15
14
  end
16
15
 
17
- # markdown flavour
18
- def self.tag_as_markdown(string, source)
19
- unless string.blank?
20
- class << string
21
- include RailsConnector::MarkdownString
22
- end
23
- string.source = source
24
- end
25
- string
26
- end
27
16
  end
28
17
 
29
18
  end
@@ -0,0 +1,52 @@
1
+ module RailsConnector
2
+
3
+ class TextLink
4
+
5
+ def initialize(link_data)
6
+ @data = link_data
7
+ end
8
+
9
+ def query_and_fragment
10
+ query = @data["query"]
11
+ fragment = @data["fragment"]
12
+
13
+ str = ''
14
+ str << "?#{query}" if query.present?
15
+ str << "##{fragment}" if fragment.present?
16
+ str
17
+ end
18
+
19
+ def internal?
20
+ !url
21
+ end
22
+
23
+ def external_url
24
+ url =~ /(external:)?(.*)/
25
+ $2
26
+ end
27
+
28
+ def obj_id
29
+ @data["destination"]
30
+ end
31
+
32
+ def html_attribute_snippet
33
+ tag_name = @data["tag_name"]
34
+ title = @data["title"]
35
+ target = @data["target"]
36
+
37
+ parts = []
38
+ parts << %{alt="#{title}"} if tag_name == 'img' || tag_name == 'input'
39
+ parts << %{title="#{title}"} if (tag_name == 'a' || tag_name == 'link') && title.present?
40
+ parts << %{target="#{target}"} if target.present?
41
+ parts.join(' ')
42
+ end
43
+
44
+ private
45
+
46
+ def url
47
+ @data["url"]
48
+ end
49
+
50
+ end
51
+
52
+ end
@@ -0,0 +1,50 @@
1
+ module RailsConnector
2
+
3
+ class TextLinkConversion
4
+
5
+ def initialize(text_links)
6
+ @text_links = text_links
7
+ end
8
+
9
+ def convert(html)
10
+ return html unless @text_links
11
+
12
+ if html
13
+ html.gsub(%r{<?\binternallink:(\d+)\b>?(['"]?)}) do
14
+ link = @text_links[$1]
15
+ postfix = $2
16
+ if link
17
+ attach_snippet("#{convert_link(link)}#{postfix}", link)
18
+ else
19
+ "#__text_link_missing#{postfix}"
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def convert_link(link)
28
+ link.internal? ? convert_internal_link(link) : convert_external_link(link)
29
+ end
30
+
31
+ def attach_snippet(text, link)
32
+ snippet = link.html_attribute_snippet
33
+ if snippet.present?
34
+ "#{text} #{snippet}"
35
+ else
36
+ text
37
+ end
38
+ end
39
+
40
+ def convert_internal_link(link)
41
+ "objid:#{link.obj_id}#{link.query_and_fragment}"
42
+ end
43
+
44
+ def convert_external_link(link)
45
+ link.external_url
46
+ end
47
+
48
+ end
49
+
50
+ end
@@ -1,14 +1,26 @@
1
1
  module RailsConnector
2
2
 
3
+ # This class represents a CMS workspace
4
+ # @api public
3
5
  class Workspace
4
6
  extend ActiveModel::Naming
5
7
 
6
8
  include ModelIdentity
7
9
 
8
- def self.current=(workspace_or_proc)
9
- @current = workspace_or_proc
10
+ # Set the currently used workspace
11
+ # @api public
12
+ # @param [RailsConnector::Workspace] workspace
13
+ def self.current=(workspace)
14
+ @current = workspace
10
15
  end
11
16
 
17
+ def self.current_using_proc=(workspace_proc)
18
+ @current = workspace_proc
19
+ end
20
+
21
+ # Returns the currently used workspace
22
+ # @api public
23
+ # @return [RailsConnector::Workspace]
12
24
  def self.current
13
25
  if @current.respond_to? :call
14
26
  @current = @current.call
@@ -17,22 +29,103 @@ class Workspace
17
29
  end
18
30
  end
19
31
 
32
+ # Returns all the workspaces
33
+ # @api public
34
+ # @return [Array<RailsConnector::Workspace>]
35
+ def self.all
36
+ result_json = CmsRestApi.get('/workspaces')
37
+
38
+ result_json['results'].map do |workspace_json|
39
+ Workspace.find(workspace_json['id'])
40
+ end
41
+ end
42
+
20
43
  def self.default
21
44
  find("published")
22
45
  end
23
46
 
47
+ # Find a workspace by its id
48
+ # @api public
49
+ # @param [String] id
50
+ # @return [RailsConnector::Workspace]
51
+ # @raise [RailsConnector::ResourceNotFound]
24
52
  def self.find(id)
25
- if workspace_data = CmsBackend.find_workspace_data_by_id(id)
53
+ if workspace_data = CmsBackend.instance.find_workspace_data_by_id(id)
26
54
  Workspace.new workspace_data
27
55
  else
28
56
  raise ResourceNotFound, "Could not find #{self} with id #{id}"
29
57
  end
30
58
  end
31
59
 
60
+ delegate :content_state, :base_revision_id, :base_content_state, to: :data
61
+
62
+ # Create a new workspace
63
+ # @api public
64
+ # @param [Hash] attributes
65
+ # @return [RailsConnector::Workspace]
66
+ def self.create(attributes)
67
+ workspace_json = CmsRestApi.post("/workspaces", workspace: attributes)
68
+
69
+ self.find(workspace_json["id"])
70
+ end
71
+
72
+ # reloads the current workspace to reflect any changes to it that may have happened concurrently
73
+ # since it was loaded
74
+ # @api public
75
+ def self.reload
76
+ id = current.id
77
+ self.current_using_proc = proc { find(id) }
78
+ end
79
+
32
80
  def initialize(workspace_data)
33
81
  @workspace_data = workspace_data
34
82
  end
35
83
 
84
+ # Reloads this workspace to reflect any changes to it that may have happened concurrently since
85
+ # it was loaded
86
+ # @api public
87
+ def reload
88
+ @workspace_data = CmsBackend.instance.find_workspace_data_by_id(self.id)
89
+ @revision = @base_revision = nil
90
+ end
91
+
92
+ # Updates this workspace's attributes
93
+ # @api public
94
+ # @param [Hash] attributes
95
+ # @return [RailsConnector::Workspace]
96
+ def update(attributes)
97
+ CmsRestApi.put(backend_url, workspace: attributes)
98
+
99
+ self.reload
100
+ end
101
+
102
+ # Destroy this workspace
103
+ # @api public
104
+ def destroy
105
+ CmsRestApi.delete(backend_url)
106
+
107
+ reset_workspace_if_current
108
+ end
109
+
110
+ # Publish the changes of this workspace
111
+ # @api public
112
+ def publish
113
+ CmsRestApi.put("#{backend_url}/publish", {})
114
+
115
+ reset_workspace_if_current
116
+ end
117
+
118
+ # Rebases the current workspace on the published content
119
+ # @api public
120
+ def rebase
121
+ CmsRestApi.put("#{backend_url}/rebase", {})
122
+
123
+ self.reload
124
+ end
125
+
126
+ # Returns the id of the workspace
127
+ # @api public
128
+ # @return [String]
36
129
  def id
37
130
  @workspace_data.id
38
131
  end
@@ -41,6 +134,9 @@ class Workspace
41
134
  @workspace_data.revision_id
42
135
  end
43
136
 
137
+ # Returns the title of the workspace
138
+ # @api public
139
+ # @return [String]
44
140
  def title
45
141
  @workspace_data.title
46
142
  end
@@ -53,6 +149,14 @@ class Workspace
53
149
  self.id == 'published'
54
150
  end
55
151
 
152
+ def revision
153
+ @revision ||= Revision.new(id: revision_id, content_state: content_state, workspace: self)
154
+ end
155
+
156
+ def base_revision
157
+ @base_revision ||= Revision.new(id: base_revision_id, content_state: base_content_state)
158
+ end
159
+
56
160
  def as_current(&block)
57
161
  old_workspace = Workspace.current
58
162
 
@@ -65,6 +169,24 @@ class Workspace
65
169
  end
66
170
  end
67
171
 
172
+ def raise_if_reverting_objs_impossible
173
+ raise "cannot revert changes, since workspace is not modifiable" if published?
174
+ raise "cannot revert changes, since workspace may contain attribute "\
175
+ "and class changes (rtc)" if id == 'rtc'
176
+ end
177
+
178
+ private
179
+
180
+ def backend_url
181
+ "/workspaces/#{id}"
182
+ end
183
+
184
+ def reset_workspace_if_current
185
+ if Workspace.current == self
186
+ Workspace.current = Workspace.default
187
+ end
188
+ end
189
+
68
190
  end
69
191
 
70
192
  end