scrivito_sdk 0.60.0 → 0.65.0.rc1
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 +4 -4
- data/.yardopts +1 -0
- data/app/controllers/scrivito/objs_controller.rb +10 -2
- data/app/controllers/scrivito/workspaces_controller.rb +2 -1
- data/app/helpers/scrivito_helper.rb +32 -1
- data/app/views/scrivito/page_details.html.erb +1 -0
- data/app/views/scrivito/{workspaces → webservice}/_workspace.json.jbuilder +0 -0
- data/app/views/scrivito/webservice/error.json.jbuilder +1 -1
- data/app/views/scrivito/{workspaces/index.json.jbuilder → webservice/workspaces.json.jbuilder} +0 -0
- data/config/ca-bundle.crt +1 -1
- data/config/precedence_routes.rb +1 -0
- data/config/routes.rb +4 -5
- data/lib/assets/javascripts/scrivito_ui.js +1875 -1065
- data/lib/assets/stylesheets/scrivito_sdk.css +1 -1
- data/lib/assets/stylesheets/scrivito_ui.css +1 -1
- data/lib/generators/scrivito/install/templates/app/views/page/details.html.erb +3 -1
- data/lib/generators/scrivito/page/templates/details.html.erb +3 -1
- data/lib/scrivito/attribute_content.rb +159 -17
- data/lib/scrivito/attribute_serializer.rb +7 -3
- data/lib/scrivito/backend/content_state_node.rb +68 -0
- data/lib/scrivito/backend/index.rb +45 -0
- data/lib/scrivito/backend/obj_data_cache.rb +68 -0
- data/lib/scrivito/backend/obj_data_from_rest.rb +64 -0
- data/lib/scrivito/backend/obj_load.rb +45 -0
- data/lib/scrivito/backend/obj_query.rb +63 -0
- data/lib/scrivito/backend/parent_path_index.rb +21 -0
- data/lib/scrivito/backend/path_index.rb +27 -0
- data/lib/scrivito/backend/permalink_index.rb +17 -0
- data/lib/scrivito/basic_obj.rb +67 -39
- data/lib/scrivito/basic_widget.rb +19 -3
- data/lib/scrivito/cache_middleware.rb +9 -3
- data/lib/scrivito/client_error.rb +3 -3
- data/lib/scrivito/cms_backend.rb +64 -18
- data/lib/scrivito/cms_data_cache.rb +33 -30
- data/lib/scrivito/cms_dispatch_controller.rb +18 -0
- data/lib/scrivito/cms_field_tag.rb +3 -2
- data/lib/scrivito/cms_rest_api.rb +18 -12
- data/lib/scrivito/cms_rest_api/rate_limit.rb +40 -0
- data/lib/scrivito/cms_routing.rb +9 -8
- data/lib/scrivito/configuration.rb +8 -1
- data/lib/scrivito/controller_actions.rb +6 -1
- data/lib/scrivito/errors.rb +5 -0
- data/lib/scrivito/migrations/cms_backend.rb +2 -0
- data/lib/scrivito/named_link.rb +9 -45
- data/lib/scrivito/obj_collection.rb +14 -15
- data/lib/scrivito/obj_create_params_parser.rb +3 -5
- data/lib/scrivito/obj_params_parser.rb +2 -2
- data/lib/scrivito/obj_update_params_parser.rb +5 -3
- data/lib/scrivito/revision.rb +62 -2
- data/lib/scrivito/type_computer.rb +6 -2
- data/lib/scrivito/widget_tag.rb +4 -4
- data/lib/scrivito/workspace.rb +19 -3
- data/lib/scrivito/workspace_data.rb +23 -0
- data/lib/scrivito/workspace_data_from_service.rb +11 -28
- metadata +31 -7
- 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
|
-
|
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
|
data/lib/scrivito/errors.rb
CHANGED
@@ -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
|
data/lib/scrivito/named_link.rb
CHANGED
@@ -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
|
-
|
55
|
-
raise NotFound, "The NamedLink '#{title.to_s}' does not exist"
|
56
|
-
|
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
|
-
|
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
|
-
|
70
|
-
|
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
|
-
|
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
|
-
|
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
|
101
|
+
def find_using(id_or_list, method)
|
102
102
|
case id_or_list
|
103
103
|
when Array
|
104
|
-
|
104
|
+
send(method, :id, id_or_list).map(&:first).compact
|
105
105
|
else
|
106
|
-
obj =
|
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
|
-
|
112
|
-
|
113
|
-
|
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
|
-
|
122
|
-
|
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 <
|
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
|
-
|
10
|
-
convert_field_params(params,
|
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
|
-
|
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 <
|
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)
|
data/lib/scrivito/revision.rb
CHANGED
@@ -1,13 +1,73 @@
|
|
1
1
|
module Scrivito
|
2
2
|
|
3
|
-
class Revision < Struct.new(:id, :
|
3
|
+
class Revision < Struct.new(:id, :workspace, :base)
|
4
4
|
def initialize(options)
|
5
|
-
super(*options.values_at(:id, :
|
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
|
-
|
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)
|
data/lib/scrivito/widget_tag.rb
CHANGED
@@ -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:
|
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
|
50
|
-
widget.
|
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)
|
data/lib/scrivito/workspace.rb
CHANGED
@@ -79,7 +79,8 @@ class Workspace
|
|
79
79
|
all.detect { |workspace| workspace.title == title }
|
80
80
|
end
|
81
81
|
|
82
|
-
delegate :
|
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,
|
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
|
30
|
+
def store_in_cache_and_create_content_state
|
46
31
|
create_content_state if content_state_id
|
47
|
-
|
32
|
+
store_in_cache
|
48
33
|
end
|
49
34
|
|
50
|
-
|
35
|
+
def content_state
|
36
|
+
@content_state ||= ContentState.find_or_create(content_state_id) if content_state_id
|
37
|
+
end
|
51
38
|
|
52
|
-
def
|
53
|
-
|
54
|
-
|
55
|
-
|
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)
|