scrivito_sdk 0.60.0 → 0.65.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/app/controllers/scrivito/objs_controller.rb +10 -2
  4. data/app/controllers/scrivito/workspaces_controller.rb +2 -1
  5. data/app/helpers/scrivito_helper.rb +32 -1
  6. data/app/views/scrivito/page_details.html.erb +1 -0
  7. data/app/views/scrivito/{workspaces → webservice}/_workspace.json.jbuilder +0 -0
  8. data/app/views/scrivito/webservice/error.json.jbuilder +1 -1
  9. data/app/views/scrivito/{workspaces/index.json.jbuilder → webservice/workspaces.json.jbuilder} +0 -0
  10. data/config/ca-bundle.crt +1 -1
  11. data/config/precedence_routes.rb +1 -0
  12. data/config/routes.rb +4 -5
  13. data/lib/assets/javascripts/scrivito_ui.js +1875 -1065
  14. data/lib/assets/stylesheets/scrivito_sdk.css +1 -1
  15. data/lib/assets/stylesheets/scrivito_ui.css +1 -1
  16. data/lib/generators/scrivito/install/templates/app/views/page/details.html.erb +3 -1
  17. data/lib/generators/scrivito/page/templates/details.html.erb +3 -1
  18. data/lib/scrivito/attribute_content.rb +159 -17
  19. data/lib/scrivito/attribute_serializer.rb +7 -3
  20. data/lib/scrivito/backend/content_state_node.rb +68 -0
  21. data/lib/scrivito/backend/index.rb +45 -0
  22. data/lib/scrivito/backend/obj_data_cache.rb +68 -0
  23. data/lib/scrivito/backend/obj_data_from_rest.rb +64 -0
  24. data/lib/scrivito/backend/obj_load.rb +45 -0
  25. data/lib/scrivito/backend/obj_query.rb +63 -0
  26. data/lib/scrivito/backend/parent_path_index.rb +21 -0
  27. data/lib/scrivito/backend/path_index.rb +27 -0
  28. data/lib/scrivito/backend/permalink_index.rb +17 -0
  29. data/lib/scrivito/basic_obj.rb +67 -39
  30. data/lib/scrivito/basic_widget.rb +19 -3
  31. data/lib/scrivito/cache_middleware.rb +9 -3
  32. data/lib/scrivito/client_error.rb +3 -3
  33. data/lib/scrivito/cms_backend.rb +64 -18
  34. data/lib/scrivito/cms_data_cache.rb +33 -30
  35. data/lib/scrivito/cms_dispatch_controller.rb +18 -0
  36. data/lib/scrivito/cms_field_tag.rb +3 -2
  37. data/lib/scrivito/cms_rest_api.rb +18 -12
  38. data/lib/scrivito/cms_rest_api/rate_limit.rb +40 -0
  39. data/lib/scrivito/cms_routing.rb +9 -8
  40. data/lib/scrivito/configuration.rb +8 -1
  41. data/lib/scrivito/controller_actions.rb +6 -1
  42. data/lib/scrivito/errors.rb +5 -0
  43. data/lib/scrivito/migrations/cms_backend.rb +2 -0
  44. data/lib/scrivito/named_link.rb +9 -45
  45. data/lib/scrivito/obj_collection.rb +14 -15
  46. data/lib/scrivito/obj_create_params_parser.rb +3 -5
  47. data/lib/scrivito/obj_params_parser.rb +2 -2
  48. data/lib/scrivito/obj_update_params_parser.rb +5 -3
  49. data/lib/scrivito/revision.rb +62 -2
  50. data/lib/scrivito/type_computer.rb +6 -2
  51. data/lib/scrivito/widget_tag.rb +4 -4
  52. data/lib/scrivito/workspace.rb +19 -3
  53. data/lib/scrivito/workspace_data.rb +23 -0
  54. data/lib/scrivito/workspace_data_from_service.rb +11 -28
  55. metadata +31 -7
  56. data/lib/scrivito/workspace_data_from_rest_api.rb +0 -6
@@ -39,19 +39,24 @@ module ControllerActions
39
39
 
40
40
  def show_widget
41
41
  widget = load_widget
42
- render text: Scrivito::WidgetTag.new(view_context, widget).render, layout: false
42
+ widget_tag = Scrivito::WidgetTag.new(view_context, widget, nil, params[:template_name])
43
+ render text: widget_tag.render, layout: false
43
44
  end
44
45
 
45
46
  def widget_details
46
47
  assert_dialog_layout
47
48
  widget = load_widget
48
49
  template_path = "#{widget.obj_class_name.underscore}/details"
50
+ @scrivito_default_widget_template = :details
49
51
  render template_path, layout: 'scrivito_dialog', locals: {widget: widget}
50
52
  end
51
53
 
52
54
  def page_details
53
55
  assert_dialog_layout
56
+ @scrivito_default_widget_template = :details
54
57
  render @obj.details_view_path, layout: 'scrivito_dialog'
58
+ rescue ActionView::MissingTemplate
59
+ render 'scrivito/page_details', layout: 'scrivito_dialog'
55
60
  end
56
61
 
57
62
  def resource_details
@@ -12,4 +12,9 @@ end
12
12
  class ObjClassNotFound < ResourceNotFound
13
13
  end
14
14
 
15
+ # this error is raised if scrivito detects an internal problem.
16
+ # these errors should never occur when using the public api of the SDK.
17
+ class InternalError < ScrivitoError
18
+ end
19
+
15
20
  end # module Scrivito
@@ -16,6 +16,7 @@ module Scrivito
16
16
  CmsRestApi.put(endpoint("objs/#{migration_store_obj.id}"),
17
17
  obj: {versions: ['string', value]})
18
18
  end
19
+ Workspace.current.reload
19
20
  end
20
21
 
21
22
  private
@@ -28,6 +29,7 @@ module Scrivito
28
29
  CmsRestApi.post(endpoint('objs'),
29
30
  obj: {_path: path, _obj_class: 'MigrationStore', versions: ['string', '']})
30
31
  end
32
+ Workspace.current.reload
31
33
  end
32
34
 
33
35
  def migration_store_obj
@@ -9,28 +9,6 @@ module Scrivito
9
9
  class NotFound < StandardError
10
10
  end
11
11
 
12
- @@named_links_cache = nil
13
-
14
- # Generates a cache of named links based on the CMS objects related link list.
15
- # Raises exceptions if zero or more than one objects have this obj_class
16
- def self.generate_named_links_cache
17
- return if @@named_links_cache
18
-
19
- found_object = find_named_link_obj
20
- if found_object.nil?
21
- raise NotFound, "Couldn't find NamedLink CMS Object!"
22
- else
23
- @@named_links_cache = found_object.
24
- related_links.
25
- flatten(1).
26
- each_with_object({}) do |link_obj, temp|
27
- temp[link_obj.title] = link_obj.obj
28
- end
29
- end
30
-
31
- return nil
32
- end
33
-
34
12
  # This method will be called to retrieve the NamedLink {BasicObj Obj}.
35
13
  # By default it will look for the Obj at the path "_named_links".
36
14
  # Overwrite this method only if you know what you are doing.
@@ -39,37 +17,23 @@ module Scrivito
39
17
  BasicObj.find_by_path("/_named_links")
40
18
  end
41
19
 
42
- def self.cache_expiry_time=(value)
43
- raise "NamedLink.cache_expiry_time is deprecated. NamedLink no longer has a separate cache."
44
- end
45
-
46
- def self.cache_expired?
47
- true
48
- end
49
-
50
20
  # Returns the CMS object mapped to the given title or nil.
51
21
  # The title can be a string of symbol.
52
22
  # @api public
53
23
  def self.get_object(title, options = {})
54
- object = named_links[title.to_s]
55
- raise NotFound, "The NamedLink '#{title.to_s}' does not exist" if object.nil?
56
- object
57
- end
58
-
59
- def self.reset_cache
60
- @@named_links_cache = nil
24
+ link = named_links.find { |link| link.title == title.to_s }
25
+ raise NotFound, "The NamedLink '#{title.to_s}' does not exist" unless link
26
+ link.obj
61
27
  end
62
28
 
63
29
  def self.named_links
64
- reset_cache if cache_expired?
65
- generate_named_links_cache unless named_links_cache
66
- named_links_cache
67
- end
30
+ named_link_obj = find_named_link_obj
68
31
 
69
- def self.named_links_cache
70
- @@named_links_cache
32
+ if named_link_obj
33
+ named_link_obj.related_links
34
+ else
35
+ raise NotFound, "Couldn't find NamedLink CMS Object!"
36
+ end
71
37
  end
72
-
73
38
  end
74
-
75
39
  end
@@ -15,7 +15,7 @@ module Scrivito
15
15
  # @return [Obj, Array<Obj>]
16
16
  # @api public
17
17
  def find(id_or_list)
18
- find_filtering_deleted(id_or_list, false)
18
+ find_using(id_or_list, :find_by)
19
19
  end
20
20
 
21
21
  # Find a {BasicObj Obj} by its id.
@@ -25,7 +25,7 @@ module Scrivito
25
25
  # @return [Obj, Array<Obj>]
26
26
  # @api public
27
27
  def find_including_deleted(id_or_list)
28
- find_filtering_deleted(id_or_list, true)
28
+ find_using(id_or_list, :find_by_including_deleted)
29
29
  end
30
30
 
31
31
  # Find the {BasicObj Obj} with the given path.
@@ -98,28 +98,27 @@ module Scrivito
98
98
 
99
99
  private
100
100
 
101
- def find_filtering_deleted(id_or_list, include_deleted)
101
+ def find_using(id_or_list, method)
102
102
  case id_or_list
103
103
  when Array
104
- find_by(:id, id_or_list, include_deleted).map(&:first).compact
104
+ send(method, :id, id_or_list).map(&:first).compact
105
105
  else
106
- obj = find_by(:id, [id_or_list.to_s], include_deleted).first.first
106
+ obj = send(method, :id, [id_or_list.to_s]).first.first
107
+
107
108
  obj or raise ResourceNotFound, "Could not find Obj with id #{id_or_list}"
108
109
  end
109
110
  end
110
111
 
111
- # accepts the name of an "obj_by" - view, a list of keys
112
- # and an "include_deleted" flag
113
- # returns a list of lists of Objs: a list of Objs for each given keys.
114
- def find_by(view, keys, include_deleted = false)
115
- if include_deleted
116
- finder_method_name = :find_obj_data_including_deleted_by
117
- else
118
- finder_method_name = :find_obj_data_by
112
+ def find_by(view, keys)
113
+ find_by_including_deleted(view, keys).map do |list|
114
+ list.reject(&:deleted?)
119
115
  end
116
+ end
120
117
 
121
- result = CmsBackend.instance.public_send(
122
- finder_method_name,
118
+ # accepts the name of an "obj_by" - view, a list of keys
119
+ # returns a list of lists of Objs: a list of Objs for each given keys.
120
+ def find_by_including_deleted(view, keys)
121
+ result = CmsBackend.instance.find_obj_data_by(
123
122
  workspace.revision,
124
123
  view,
125
124
  keys)
@@ -1,13 +1,11 @@
1
1
  module Scrivito
2
- class ObjCreateParamsParser < Struct.new(:host, :port)
3
- include ObjParamsParser
4
-
2
+ class ObjCreateParamsParser < ObjParamsParser
5
3
  private
6
4
 
7
5
  def convert_params(params)
8
6
  if obj_class_name = params['_obj_class']
9
- model_class = Obj.type_computer.compute_type(obj_class_name)
10
- convert_field_params(params, model_class.attribute_definitions)
7
+ obj_class = Obj.type_computer.compute_type_without_fallback(obj_class_name)
8
+ convert_field_params(params, obj_class.attribute_definitions)
11
9
  else
12
10
  raise ArgumentError, 'Missing "_obj_class" param'
13
11
  end
@@ -1,5 +1,5 @@
1
1
  module Scrivito
2
- module ObjParamsParser
2
+ class ObjParamsParser < Struct.new(:host, :port, :context)
3
3
  class UnknownWidgetAction < ScrivitoError
4
4
  end
5
5
 
@@ -30,7 +30,7 @@ module Scrivito
30
30
  if widget_id_or_params.is_a?(Hash)
31
31
  action, widget_params = widget_id_or_params.flatten
32
32
  case action
33
- when 'create' then Widget.new(widget_params)
33
+ when 'create' then Widget.new(widget_params, context.slice(:scrivito_user))
34
34
  when 'copy'
35
35
  widget_id = widget_params['widget_id']
36
36
  widget = Workspace.find(widget_params['workspace_id'])
@@ -1,9 +1,11 @@
1
1
  module Scrivito
2
- class ObjUpdateParamsParser < Struct.new(:obj, :host, :port)
3
- include ObjParamsParser
4
-
2
+ class ObjUpdateParamsParser < ObjParamsParser
5
3
  private
6
4
 
5
+ def obj
6
+ context[:current_obj]
7
+ end
8
+
7
9
  def convert_params(params)
8
10
  convert_field_params(params, obj.attribute_definitions)
9
11
  convert_widget_pool_params(params)
@@ -1,13 +1,73 @@
1
1
  module Scrivito
2
2
 
3
- class Revision < Struct.new(:id, :content_state, :workspace, :base)
3
+ class Revision < Struct.new(:id, :workspace, :base)
4
4
  def initialize(options)
5
- super(*options.values_at(:id, :content_state, :workspace, :base))
5
+ super(*options.values_at(:id, :workspace, :base))
6
+ end
7
+
8
+ def content_state
9
+ base ? workspace.base_content_state : workspace.content_state
10
+ end
11
+
12
+ def content_state_id
13
+ base ? workspace.base_content_state_id : workspace.content_state_id
14
+ end
15
+
16
+ def content_state_node
17
+ @node ||= Backend::ContentStateNode.new(content_state_id)
18
+ end
19
+
20
+ # returns a list of raw rest-api hashes, one for each given id
21
+ def obj_mget_request(ids)
22
+ internal_obj_mget(ids, [])
23
+ end
24
+
25
+ # performs given search-query, returns the search-hits as a list of obj-ids
26
+ def obj_search_request(query)
27
+ if base
28
+ raise Scrivito::InternalError, "search not possible for base revision"
29
+ end
30
+
31
+ internal_obj_search(query, [])
32
+ end
33
+
34
+ def api_request(verb, path, payload = nil)
35
+ CmsRestApi.public_send(verb, "revisions/#{id}#{path}", payload)
6
36
  end
7
37
 
8
38
  def base?
9
39
  !!base
10
40
  end
41
+
42
+ private
43
+
44
+ def internal_obj_search(query, result)
45
+ response = workspace.api_request(:get, "/objs/search", {
46
+ query: query, include_deleted: true, size: 100, offset: result.size
47
+ })
48
+
49
+ cur_result = response['results'].map { |obj_data| obj_data['id'] }
50
+ result += cur_result
51
+
52
+ if result.size >= response['total'].to_i
53
+ result
54
+ else
55
+ internal_obj_search(query, result)
56
+ end
57
+ end
58
+
59
+ def internal_obj_mget(ids, result)
60
+ response = api_request(
61
+ :get, "/objs/mget", ids: ids, include_deleted: true)
62
+
63
+ current_result = result + response["results"]
64
+
65
+ if response["results"].size < ids.size
66
+ internal_obj_mget(ids.drop(response["results"].size), current_result)
67
+ else
68
+ current_result
69
+ end
70
+ end
11
71
  end
12
72
 
13
73
  end
@@ -6,11 +6,15 @@ class TypeComputer
6
6
  end
7
7
 
8
8
  def compute_type(obj_class_name)
9
- compute_type_without_fallback(obj_class_name) || @fallback_class
9
+ load_class(obj_class_name) || @fallback_class
10
10
  end
11
11
 
12
12
  def compute_type_without_fallback(obj_class_name)
13
- load_class(obj_class_name)
13
+ if obj_class = load_class(obj_class_name)
14
+ obj_class
15
+ else
16
+ raise ObjClassNotFound
17
+ end
14
18
  end
15
19
 
16
20
  def special_class?(klass)
@@ -1,6 +1,6 @@
1
1
  module Scrivito
2
2
 
3
- class WidgetTag < Struct.new(:view, :widget, :placement_modification)
3
+ class WidgetTag < Struct.new(:view, :widget, :placement_modification, :template_name)
4
4
  include TagRenderer
5
5
 
6
6
  def tag_name
@@ -8,7 +8,7 @@ class WidgetTag < Struct.new(:view, :widget, :placement_modification)
8
8
  end
9
9
 
10
10
  def content
11
- view.render(template: template, locals: {widget: widget})
11
+ view.render(template: template_path, locals: {widget: widget})
12
12
  rescue ActionView::MissingTemplate
13
13
  %{Missing Ruby model class for "#{widget.obj_class_name}"} if view.scrivito_user
14
14
  end
@@ -46,8 +46,8 @@ class WidgetTag < Struct.new(:view, :widget, :placement_modification)
46
46
 
47
47
  private
48
48
 
49
- def template
50
- widget.to_show_view_path
49
+ def template_path
50
+ widget.public_send("to_#{template_name}_view_path")
51
51
  end
52
52
 
53
53
  def has_widget_details_view?(widget)
@@ -79,7 +79,8 @@ class Workspace
79
79
  all.detect { |workspace| workspace.title == title }
80
80
  end
81
81
 
82
- delegate :content_state, :base_revision_id, :base_content_state, :uses_obj_classes, to: :data
82
+ delegate :content_state_id, :base_content_state_id, :content_state,
83
+ :base_revision_id, :base_content_state, :uses_obj_classes, to: :data
83
84
 
84
85
  # Create a new workspace
85
86
  # @api public
@@ -203,14 +204,13 @@ class Workspace
203
204
  end
204
205
 
205
206
  def revision
206
- @revision ||= Revision.new(id: revision_id, content_state: content_state, workspace: self)
207
+ @revision ||= Revision.new(id: revision_id, workspace: self)
207
208
  end
208
209
 
209
210
  def base_revision
210
211
  if base_revision_id
211
212
  @base_revision ||= Revision.new(
212
213
  id: base_revision_id,
213
- content_state: base_content_state,
214
214
  workspace: self,
215
215
  base: true
216
216
  )
@@ -258,6 +258,22 @@ class Workspace
258
258
  "<#{self.class} id=\"#{id}\" title=\"#{title}\">"
259
259
  end
260
260
 
261
+ def has_modification_for?(obj_id)
262
+ !!objs.find_including_deleted(obj_id).modification
263
+ rescue Scrivito::ResourceNotFound
264
+ false
265
+ end
266
+
267
+ def self.all_with_modification_for(obj_id)
268
+ all.select do |ws|
269
+ ws.has_modification_for?(obj_id)
270
+ end
271
+ end
272
+
273
+ def conflict_warning_for(obj_id)
274
+ self.class.all_with_modification_for(obj_id) - [self]
275
+ end
276
+
261
277
  private
262
278
 
263
279
  def backend_url
@@ -11,9 +11,32 @@ module Scrivito
11
11
  data_attr_reader :id
12
12
  data_attr_reader :title
13
13
  data_attr_reader :memberships
14
+ data_attr_reader :revision_id
15
+ data_attr_reader :content_state_id
16
+ data_attr_reader :uses_obj_classes
17
+ data_attr_reader :base_revision_id
18
+ data_attr_reader :base_content_state_id
14
19
 
15
20
  def initialize(data)
16
21
  @data = data
17
22
  end
23
+
24
+ def store_in_cache
25
+ CmsDataCache.write_workspace_data(id, to_hash)
26
+ end
27
+
28
+ private
29
+
30
+ def to_hash
31
+ {
32
+ 'id' => id,
33
+ 'revision_id' => revision_id,
34
+ 'title' => title,
35
+ 'content_state_id' => content_state_id,
36
+ 'base_revision_id' => base_revision_id,
37
+ 'base_content_state_id' => base_content_state_id,
38
+ 'memberships' => memberships,
39
+ }
40
+ end
18
41
  end
19
42
  end
@@ -11,22 +11,7 @@ class WorkspaceDataFromService < WorkspaceData
11
11
  end
12
12
  end
13
13
 
14
- data_attr_reader :revision_id
15
- data_attr_reader :content_state_id
16
- data_attr_reader :base_revision_id
17
- data_attr_reader :base_content_state_id
18
14
  data_attr_reader :diff
19
- data_attr_reader :uses_obj_classes
20
-
21
- def content_state
22
- @content_state ||= ContentState.find_or_create(content_state_id) if content_state_id
23
- end
24
-
25
- def base_content_state
26
- if base_content_state_id
27
- @base_content_state ||= ContentState.find_or_create(base_content_state_id)
28
- end
29
- end
30
15
 
31
16
  def changes
32
17
  diff && diff['changes']
@@ -42,25 +27,23 @@ class WorkspaceDataFromService < WorkspaceData
42
27
 
43
28
  # Serializes and stores a workspace data in cache storage.
44
29
  # Also creates an appropriate content state if needed.
45
- def store_in_cache
30
+ def store_in_cache_and_create_content_state
46
31
  create_content_state if content_state_id
47
- CmsDataCache.write_workspace_data(id, to_hash)
32
+ store_in_cache
48
33
  end
49
34
 
50
- private
35
+ def content_state
36
+ @content_state ||= ContentState.find_or_create(content_state_id) if content_state_id
37
+ end
51
38
 
52
- def to_hash
53
- {
54
- 'id' => id,
55
- 'revision_id' => revision_id,
56
- 'title' => title,
57
- 'content_state_id' => content_state_id,
58
- 'base_revision_id' => base_revision_id,
59
- 'base_content_state_id' => base_content_state_id,
60
- 'memberships' => memberships,
61
- }
39
+ def base_content_state
40
+ if base_content_state_id
41
+ @base_content_state ||= ContentState.find_or_create(base_content_state_id)
42
+ end
62
43
  end
63
44
 
45
+ private
46
+
64
47
  def create_content_state
65
48
  ContentState.create(content_state_id: to_content_state_id, changes: changes,
66
49
  from_content_state_id: from_content_state_id)