infopark_fiona7 0.30.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +3 -0
- data/Rakefile +21 -0
- data/app/assets/images/fiona7-logo.png +0 -0
- data/app/assets/images/fiona7-marker.png +0 -0
- data/app/assets/javascripts/fiona7.js +284 -0
- data/app/assets/stylesheets/fiona7-login.css.scss +15 -0
- data/app/assets/stylesheets/fiona7.css.scss +83 -0
- data/app/controllers/fiona7/blobs_controller.rb +35 -0
- data/app/controllers/fiona7/default_scrivito_cms_controller.rb +16 -0
- data/app/controllers/fiona7/release_controller.rb +24 -0
- data/app/controllers/fiona7/sessions_controller.rb +49 -0
- data/app/controllers/fiona7_login_page_controller.rb +27 -0
- data/app/helpers/fiona7_login_helper.rb +18 -0
- data/app/helpers/fiona7_override_helper.rb +47 -0
- data/app/models/fiona7/edited_obj.rb +15 -0
- data/app/models/fiona7/internal_released_obj.rb +18 -0
- data/app/models/fiona7/released_obj.rb +18 -0
- data/app/models/fiona7/write_obj.rb +63 -0
- data/app/models/fiona7_login_page.rb +5 -0
- data/app/models/x_container.rb +5 -0
- data/app/models/x_generic.rb +5 -0
- data/app/models/x_image.rb +5 -0
- data/app/views/fiona7_login_page/index.html.erb +14 -0
- data/app/views/layouts/fiona7_login_page_layout.html.erb +23 -0
- data/config/locales/login.yml +19 -0
- data/config/locales/permissions.yml +7 -0
- data/config/routes.rb +9 -0
- data/lib/fiona7/assert.rb +17 -0
- data/lib/fiona7/builder/batch_widget_writer.rb +107 -0
- data/lib/fiona7/builder/obj_builder.rb +297 -0
- data/lib/fiona7/builder/obj_class_builder.rb +111 -0
- data/lib/fiona7/builder/obj_class_updater.rb +69 -0
- data/lib/fiona7/builder/obj_updater.rb +25 -0
- data/lib/fiona7/builder/widget_builder.rb +13 -0
- data/lib/fiona7/builder/widget_building.rb +35 -0
- data/lib/fiona7/builder/widget_updater.rb +13 -0
- data/lib/fiona7/controllers/content_service/obj_controller.rb +125 -0
- data/lib/fiona7/controllers/content_service/workspace_controller.rb +19 -0
- data/lib/fiona7/controllers/rest_api/blob_controller.rb +11 -0
- data/lib/fiona7/controllers/rest_api/obj_class_controller.rb +39 -0
- data/lib/fiona7/controllers/rest_api/obj_controller.rb +175 -0
- data/lib/fiona7/controllers/rest_api/workspace_controller.rb +58 -0
- data/lib/fiona7/engine.rb +138 -0
- data/lib/fiona7/fiona_connector_patches/basic_obj.rb +9 -0
- data/lib/fiona7/initializer.rb +78 -0
- data/lib/fiona7/json/obj_class_decorator.rb +45 -0
- data/lib/fiona7/json/obj_decorator.rb +153 -0
- data/lib/fiona7/json/typeless_obj_decorator.rb +30 -0
- data/lib/fiona7/json/widget_decorator.rb +18 -0
- data/lib/fiona7/link_converter/fiona_to_scrivito.rb +37 -0
- data/lib/fiona7/link_converter/scrivito_to_fiona.rb +42 -0
- data/lib/fiona7/mode_switch.rb +7 -0
- data/lib/fiona7/mode_switch/abstract_mode_switch.rb +19 -0
- data/lib/fiona7/mode_switch/cms_routes.rb +33 -0
- data/lib/fiona7/mode_switch/cms_routes/fiona_connector.rb +17 -0
- data/lib/fiona7/mode_switch/cms_routes/scrivito_sdk.rb +20 -0
- data/lib/fiona7/mode_switch/cms_routes/scrivito_sdk_slave.rb +20 -0
- data/lib/fiona7/mode_switch/composite.rb +33 -0
- data/lib/fiona7/mode_switch/constants.rb +86 -0
- data/lib/fiona7/mode_switch/views.rb +37 -0
- data/lib/fiona7/naive_search_engine.rb +111 -0
- data/lib/fiona7/recursive_link_resolver.rb +93 -0
- data/lib/fiona7/routers/content_service.rb +19 -0
- data/lib/fiona7/routers/rest_api.rb +135 -0
- data/lib/fiona7/routing_monkey_patch.rb +33 -0
- data/lib/fiona7/scrivito_patches/attribute_content.rb +19 -0
- data/lib/fiona7/scrivito_patches/basic_obj.rb +92 -0
- data/lib/fiona7/scrivito_patches/basic_widget.rb +14 -0
- data/lib/fiona7/scrivito_patches/binary.rb +55 -0
- data/lib/fiona7/scrivito_patches/client_config.rb +19 -0
- data/lib/fiona7/scrivito_patches/cms_dispatch_controller.rb +31 -0
- data/lib/fiona7/scrivito_patches/cms_rest_api.rb +11 -0
- data/lib/fiona7/scrivito_patches/cms_routing.rb +66 -0
- data/lib/fiona7/scrivito_patches/controller_actions.rb +14 -0
- data/lib/fiona7/scrivito_patches/link_parser.rb +22 -0
- data/lib/fiona7/scrivito_patches/migrator.rb +13 -0
- data/lib/fiona7/scrivito_patches/obj_class.rb +16 -0
- data/lib/fiona7/scrivito_patches/type_computer.rb +25 -0
- data/lib/fiona7/scrivito_patches/workspace.rb +12 -0
- data/lib/fiona7/scrivito_user.rb +44 -0
- data/lib/fiona7/search_engine.rb +20 -0
- data/lib/fiona7/type_register.rb +140 -0
- data/lib/fiona7/type_register_mixin.rb +9 -0
- data/lib/fiona7/version.rb +3 -0
- data/lib/fiona7/version_helper.rb +84 -0
- data/lib/fiona7/widget_resolver.rb +37 -0
- data/lib/fiona7/workspace.rb +76 -0
- data/lib/infopark_fiona7.rb +4 -0
- data/lib/tasks/fiona7_tasks.rake +13 -0
- metadata +216 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'scrivito/client_config'
|
2
|
+
|
3
|
+
module Scrivito
|
4
|
+
class ClientConfig
|
5
|
+
alias_method :original_obj_config, :obj_config
|
6
|
+
|
7
|
+
alias_method :original_user_permissions_config, :user_permissions_config
|
8
|
+
|
9
|
+
def user_permissions_config
|
10
|
+
original_user_permissions_config.tap do |config|
|
11
|
+
# TODO: optimize this find away
|
12
|
+
if obj && obj.id
|
13
|
+
config[:write_obj] = Fiona7::WriteObj.find(obj.id).permission.write?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'scrivito/cms_dispatch_controller'
|
2
|
+
module Scrivito
|
3
|
+
|
4
|
+
class CmsDispatchController
|
5
|
+
def target_controller(env)
|
6
|
+
return default_controller if obj_not_found?
|
7
|
+
controller = "#{loaded_obj.controller_name}Controller".constantize
|
8
|
+
|
9
|
+
if controller.respond_to?(:use_for_obj_dispatch?) && controller.use_for_obj_dispatch? && controller.include?(Scrivito::ControllerActions)
|
10
|
+
controller
|
11
|
+
else
|
12
|
+
default_controller
|
13
|
+
end
|
14
|
+
rescue NameError
|
15
|
+
default_controller
|
16
|
+
end
|
17
|
+
|
18
|
+
def default_controller
|
19
|
+
return Fiona7::DefaultScrivitoCmsController if Fiona7.mode == :legacy
|
20
|
+
CmsController
|
21
|
+
rescue NameError => e
|
22
|
+
if e.message.include?('CmsController')
|
23
|
+
raise 'Your application does not define the "CmsController" needed for Scrivito. '\
|
24
|
+
'Did you forget to run "rails generate scrivito:install"?'
|
25
|
+
else
|
26
|
+
raise
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'scrivito/cms_routing'
|
2
|
+
|
3
|
+
module Scrivito
|
4
|
+
class CmsRouting
|
5
|
+
# patch link converter to understand numerical IDs
|
6
|
+
def convert_links(html)
|
7
|
+
if html
|
8
|
+
html.gsub(%r{<?\bobjid:([1-9][0-9]{3,})\b>?}) do
|
9
|
+
if obj = Obj.find_by_id($1)
|
10
|
+
path_or_url(obj, "path")
|
11
|
+
else
|
12
|
+
"#__target_object_not_reachable"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# patch router to output proper binary urls fo uploaded files
|
19
|
+
def path_or_url_without_editing_context(target, path_or_url, options)
|
20
|
+
if target.is_a?(Link)
|
21
|
+
path_or_url_for_links(target, path_or_url, options)
|
22
|
+
elsif target.is_a?(BasicObj)
|
23
|
+
path_or_url_for_objs(target, path_or_url, options)
|
24
|
+
elsif target.respond_to?(:first)
|
25
|
+
if target.first.is_a?(Link)
|
26
|
+
path_or_url_for_links(target.first, path_or_url, options)
|
27
|
+
else
|
28
|
+
return LINK_TO_EMPTY_LINKLIST
|
29
|
+
end
|
30
|
+
elsif target.is_a?(Binary)
|
31
|
+
binary = target
|
32
|
+
main_app.public_send("fiona7_blob_#{path_or_url}", {id: binary.send(:id), name: binary.filename})
|
33
|
+
else
|
34
|
+
raise "scrivito_path or scrivito_url was called with an instance of #{target.class}. "+
|
35
|
+
"It must only be called with a descendant of Scrivito::BasicObj or a Link or a non-empty LinkList."
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# patch router to output proper binary urls fo uploaded files
|
40
|
+
def path_or_url_for_objs(obj, path_or_url, options = {})
|
41
|
+
permalink = obj.permalink
|
42
|
+
if permalink
|
43
|
+
main_app.public_send("scrivito_permalink_#{path_or_url}", options.merge(:permalink => permalink))
|
44
|
+
elsif obj.homepage?
|
45
|
+
main_app.public_send("scrivito_root_#{path_or_url}", options)
|
46
|
+
else
|
47
|
+
if obj.binary? && editing_context.display_mode != "editing"
|
48
|
+
if obj.binary
|
49
|
+
main_app.public_send("fiona7_blob_#{path_or_url}", {id: obj.binary.send(:id), name: obj.binary.filename})
|
50
|
+
else
|
51
|
+
LINK_TO_EMPTY_BLOB
|
52
|
+
end
|
53
|
+
else
|
54
|
+
main_app.public_send(
|
55
|
+
"scrivito_id_#{path_or_url}",
|
56
|
+
options.merge(
|
57
|
+
id: obj.id,
|
58
|
+
slug: obj.slug.presence
|
59
|
+
)
|
60
|
+
)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'scrivito/controller_actions'
|
2
|
+
|
3
|
+
module Scrivito
|
4
|
+
module ControllerActions
|
5
|
+
# different handling of binary objs
|
6
|
+
def deliver_file
|
7
|
+
if binary = @obj.binary
|
8
|
+
redirect_to fiona7_blob_path(id: binary.send(:id), name: binary.filename), :status => :moved_permanently
|
9
|
+
else
|
10
|
+
render text: 'Empty Blob', status: 404
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'scrivito/link_parser'
|
2
|
+
|
3
|
+
module Scrivito
|
4
|
+
class LinkParser
|
5
|
+
alias_method :original_parse, :parse
|
6
|
+
|
7
|
+
# Patch parse to handle numerical ids
|
8
|
+
def parse(url)
|
9
|
+
url = url.to_s if url
|
10
|
+
original_parse(url)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Patch to handle legacy mode
|
14
|
+
def application_route?(uri)
|
15
|
+
route_params = route(uri)
|
16
|
+
route_params && (
|
17
|
+
route_params[:controller] == 'scrivito/cms_dispatch' ||
|
18
|
+
route_params[:controller] == 'rails_connector/cms_dispatch'
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'scrivito/obj_class'
|
2
|
+
|
3
|
+
module Scrivito
|
4
|
+
class ObjClass
|
5
|
+
# there are no legacy types.
|
6
|
+
def is_binary
|
7
|
+
raise ScrivitoError,
|
8
|
+
%(`is_binary' and `binary?' can only be called on ObjClasses with a legacy_type.)
|
9
|
+
end
|
10
|
+
alias_method :binary?, :is_binary
|
11
|
+
|
12
|
+
def legacy_type?
|
13
|
+
false
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'scrivito/type_computer'
|
2
|
+
|
3
|
+
module Scrivito
|
4
|
+
class TypeComputer
|
5
|
+
private
|
6
|
+
# In legacy mode we allow for an objects inside global namespace and Scrivito:: namespace
|
7
|
+
def load_class(obj_class)
|
8
|
+
klass = nil
|
9
|
+
begin
|
10
|
+
klass = obj_class.constantize
|
11
|
+
rescue NameError
|
12
|
+
end
|
13
|
+
return klass if klass && inherits_from_base?(klass)
|
14
|
+
|
15
|
+
if Fiona7.mode == :legacy
|
16
|
+
obj_class = "Scrivito::#{obj_class}"
|
17
|
+
begin
|
18
|
+
klass = obj_class.safe_constantize
|
19
|
+
rescue NameError
|
20
|
+
end
|
21
|
+
return klass if klass && inherits_from_base?(klass)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'scrivito/workspace'
|
2
|
+
|
3
|
+
module Scrivito
|
4
|
+
class Workspace
|
5
|
+
# Backport a "solution" for broken diff view
|
6
|
+
def base_revision
|
7
|
+
if base_revision_id
|
8
|
+
@base_revision ||= Revision.new(id: base_revision_id, content_state: base_content_state, workspace: self)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Fiona7
|
2
|
+
class ScrivitoUser
|
3
|
+
def self.define(rsession_user)
|
4
|
+
Scrivito::User.define(rsession_user.user_name) do |user_definition|
|
5
|
+
#
|
6
|
+
# Define how this user should be presented in the UI.
|
7
|
+
#
|
8
|
+
user_definition.description { "#{rsession_user.user_name}" }
|
9
|
+
|
10
|
+
# :-)
|
11
|
+
user_definition.can_always(:read, :workspace)
|
12
|
+
|
13
|
+
# workspaces can only be selected
|
14
|
+
user_definition.can_never(:create, :workspace)
|
15
|
+
|
16
|
+
# any write operation
|
17
|
+
user_definition.can_always(:write, :workspace)
|
18
|
+
|
19
|
+
# only root can publish rtc
|
20
|
+
if rsession_user.superuser?
|
21
|
+
user_definition.can_always(:publish, :workspace)
|
22
|
+
else
|
23
|
+
user_definition.can_never(:publish, :workspace)
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Below, we define the publishing restrictions related to 'Obj's for this user.
|
28
|
+
# The restriction callbacks should either return nothing (the 'Obj' may be published),
|
29
|
+
# or a string describing why the 'Obj' cannot be published by this user.
|
30
|
+
#
|
31
|
+
# Here, the '_path' attribute of a changed 'Obj' is used to determine
|
32
|
+
# whether the user is trying to publish changes made to a particular website
|
33
|
+
# section, here "investor relations", which requires a special permission.
|
34
|
+
#
|
35
|
+
user_definition.restrict_obj_publish(using: :_path) do |path|
|
36
|
+
obj = Fiona7::WriteObj.find_by_path(path)
|
37
|
+
if !obj || !obj.permission.release?(rsession_user.user_name)
|
38
|
+
I18n.t(:"fiona7.publish_permission_resticted", path: path)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Fiona7
|
2
|
+
class SearchEngine
|
3
|
+
def initialize(klass, query, offset, limit, sort, order)
|
4
|
+
@klass = klass
|
5
|
+
@query = query
|
6
|
+
@offset, @limit = offset, limit
|
7
|
+
@sort, @order = sort, order
|
8
|
+
|
9
|
+
@count = 0
|
10
|
+
end
|
11
|
+
|
12
|
+
def total
|
13
|
+
@count
|
14
|
+
end
|
15
|
+
|
16
|
+
def results
|
17
|
+
raise "Not implemented"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Fiona7
|
4
|
+
class TypeRegister
|
5
|
+
TYPE_MAP = {
|
6
|
+
link: :linklist,
|
7
|
+
reference: :linklist,
|
8
|
+
referencelist: :linklist,
|
9
|
+
widget: :linklist,
|
10
|
+
binary: :linklist
|
11
|
+
}
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def instance
|
15
|
+
self.new
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class ObjClass < Struct.new('ObjClass', :name, :type, :attributes)
|
20
|
+
end
|
21
|
+
|
22
|
+
class Attribute < Struct.new(:real_name, :virtual_name, :real_type, :virtual_type, :values)
|
23
|
+
end
|
24
|
+
|
25
|
+
def cached_type(obj_class_name)
|
26
|
+
@@cached_type ||= {}
|
27
|
+
@@cached_type[obj_class_name.to_s] ||= ObjClass.new.tap do |obj_class|
|
28
|
+
cms_class = RailsConnector::ObjClass.find_by_obj_class_name(obj_class_name)
|
29
|
+
obj_class.name = cms_class.name
|
30
|
+
obj_class.type = cms_class.obj_type
|
31
|
+
|
32
|
+
attributes = Set.new
|
33
|
+
cms_class.custom_attributes.each do |real_name, cms_attribute|
|
34
|
+
real_name = real_name.to_sym
|
35
|
+
|
36
|
+
next if real_name == :X_widget_pool
|
37
|
+
|
38
|
+
if Fiona7.mode == :standalone
|
39
|
+
virtual_name = real_name.to_s.sub(/^s_#{Regexp.escape obj_class_name}__/, '').to_sym
|
40
|
+
elsif Fiona7.mode == :legacy
|
41
|
+
# X_blob simulates blob attribute
|
42
|
+
if real_name == :X_blob
|
43
|
+
virtual_name = :blob
|
44
|
+
else
|
45
|
+
virtual_name = real_name.to_sym
|
46
|
+
end
|
47
|
+
else
|
48
|
+
raise "Invalid Fiona7.mode = #{Fiona7.mode}"
|
49
|
+
end
|
50
|
+
|
51
|
+
real_type = cms_attribute.attribute_type.to_sym
|
52
|
+
virtual_type = ::JSON.parse(cms_attribute.help_text(:de))['type'].to_sym rescue nil
|
53
|
+
virtual_type ||= real_type
|
54
|
+
|
55
|
+
# real_type = virtual_type in this case
|
56
|
+
if [:enum, :multienum].include?(real_type)
|
57
|
+
values = cms_attribute.values
|
58
|
+
else
|
59
|
+
values = nil
|
60
|
+
end
|
61
|
+
|
62
|
+
attributes << Attribute.new(real_name, virtual_name, real_type, virtual_type, values)
|
63
|
+
end
|
64
|
+
|
65
|
+
if Fiona7.mode == :legacy
|
66
|
+
# include built-in title and body
|
67
|
+
attributes << Attribute.new(:title, :title, :string, :string, nil)
|
68
|
+
if cms_class.obj_type != "image" && cms_class.obj_type != "generic"
|
69
|
+
attributes << Attribute.new(:body, :body, :html, :html, nil)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
obj_class.attributes = attributes.to_a
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def invalidate_cached_type(obj_class_name)
|
78
|
+
@@cached_type.delete(obj_class_name.to_s)
|
79
|
+
# clear reactor cache as well
|
80
|
+
RailsConnector::Meta::EagerLoader.instance.forget_obj_class(obj_class_name)
|
81
|
+
end
|
82
|
+
|
83
|
+
def annotated_attributes(obj_class_name)
|
84
|
+
obj_class = cached_type(obj_class_name)
|
85
|
+
raise "Unknown obj_class: #{obj_class_name}" unless obj_class
|
86
|
+
obj_class.attributes
|
87
|
+
end
|
88
|
+
|
89
|
+
def attributes(obj_class_name)
|
90
|
+
raise "Deprecated"
|
91
|
+
end
|
92
|
+
|
93
|
+
def obj_type(obj_class_name)
|
94
|
+
self.cached_type(obj_class_name).type
|
95
|
+
end
|
96
|
+
|
97
|
+
def attribute_type(obj_class_name, attribute_name)
|
98
|
+
attribute = self.cached_type(obj_class_name).attributes.find {|a| a.virtual_name.to_s == attribute_name.to_s }
|
99
|
+
|
100
|
+
if attribute
|
101
|
+
attribute.virtual_type
|
102
|
+
else
|
103
|
+
raise "unknown attribute: #{attribute_name} in #{obj_class_name}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def real_attribute_name(obj_class_name, attribute_name)
|
108
|
+
if Fiona7.mode == :standalone
|
109
|
+
:"s_#{obj_class_name}__#{attribute_name}"
|
110
|
+
elsif Fiona7.mode == :legacy
|
111
|
+
# blob attribute is always mapped to X_blob attribute if present
|
112
|
+
if attribute_name.to_sym == :blob
|
113
|
+
:X_blob
|
114
|
+
else
|
115
|
+
attribute_name.to_sym
|
116
|
+
end
|
117
|
+
else
|
118
|
+
raise "Invalid Fiona7.mode = #{Fiona7.mode}"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def virtual_attribute_name(obj_class_name, attribute_name)
|
123
|
+
attribute_name.to_s.sub("s_#{obj_class_name}__", '').to_sym
|
124
|
+
end
|
125
|
+
|
126
|
+
def attribute_real_type(obj_class_name, attribute_name)
|
127
|
+
attribute = self.cached_type(obj_class_name).attributes.find {|a| a.virtual_name.to_s == attribute_name.to_s }
|
128
|
+
|
129
|
+
if attribute
|
130
|
+
attribute.real_type
|
131
|
+
else
|
132
|
+
raise "unknown attribute: #{attribute_name} in #{obj_class_name}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def map_virtual_to_real_type(virtual_type)
|
137
|
+
TYPE_MAP[virtual_type.to_sym] || virtual_type.to_sym
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|