infopark_fiona_connector 7.0.1.5.2.3.rc8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +5 -0
  3. data/app/assets/images/admin/minus.gif +0 -0
  4. data/app/assets/images/bg80.png +0 -0
  5. data/app/assets/images/edit.png +0 -0
  6. data/app/assets/images/icons/mm_generic.png +0 -0
  7. data/app/assets/images/icons/mm_menu.png +0 -0
  8. data/app/assets/javascripts/editmarker.js +240 -0
  9. data/app/assets/javascripts/infopark_rails_connector.js.erb +0 -0
  10. data/app/assets/stylesheets/editmarker.css +70 -0
  11. data/app/assets/stylesheets/infopark_rails_connector.css.erb +0 -0
  12. data/app/controllers/cms_controller.rb +7 -0
  13. data/app/controllers/rails_connector/default_cms_controller.rb +41 -0
  14. data/app/helpers/cms_helper.rb +7 -0
  15. data/app/helpers/cms_routing_helper.rb +7 -0
  16. data/app/helpers/rails_connector/cms_asset_helper.rb +54 -0
  17. data/app/helpers/rails_connector/cms_tag_helper.rb +4 -0
  18. data/app/helpers/rails_connector/default_cms_helper.rb +21 -0
  19. data/app/helpers/rails_connector/default_cms_routing_helper.rb +119 -0
  20. data/app/helpers/rails_connector/display_helper.rb +124 -0
  21. data/app/helpers/rails_connector/editing_helper.rb +7 -0
  22. data/app/helpers/rails_connector/layout_helper.rb +26 -0
  23. data/app/helpers/rails_connector/marker_helper.rb +371 -0
  24. data/app/helpers/rails_connector/table_of_contents_helper.rb +20 -0
  25. data/app/models/named_link.rb +2 -0
  26. data/app/views/cms/_index.html.erb +7 -0
  27. data/app/views/cms/index.html.erb +1 -0
  28. data/app/views/errors/403_forbidden.html.erb +3 -0
  29. data/app/views/errors/410_gone.html.erb +7 -0
  30. data/config/cms_routes.rb +17 -0
  31. data/config/locales/de.rails_connector.errors.yml +11 -0
  32. data/config/locales/de.rails_connector.lib.yml +6 -0
  33. data/config/locales/de.rails_connector.views.yml +9 -0
  34. data/config/locales/en.rails_connector.errors.yml +10 -0
  35. data/config/locales/en.rails_connector.lib.yml +6 -0
  36. data/config/locales/en.rails_connector.views.yml +9 -0
  37. data/lib/gem_dependencies.rb +68 -0
  38. data/lib/generators/rails_connector/install/install_generator.rb +37 -0
  39. data/lib/generators/rails_connector/install/templates/app/models/obj.rb.erb +5 -0
  40. data/lib/generators/rails_connector/install/templates/initializers/rails_connector.rb +2 -0
  41. data/lib/generators/rails_connector/install/templates/local/configuration.rb +2 -0
  42. data/lib/infopark_fiona_connector.rb +44 -0
  43. data/lib/meta_eager_loader.rb +1 -0
  44. data/lib/obj.rb +3 -0
  45. data/lib/rails_connector/attr_dict.rb +169 -0
  46. data/lib/rails_connector/attr_value_provider.bundle +0 -0
  47. data/lib/rails_connector/attr_value_provider.so +0 -0
  48. data/lib/rails_connector/attr_value_provider64.so +0 -0
  49. data/lib/rails_connector/attribute.rb +93 -0
  50. data/lib/rails_connector/authenticable.rb +37 -0
  51. data/lib/rails_connector/basic_obj.rb +571 -0
  52. data/lib/rails_connector/blob.rb +75 -0
  53. data/lib/rails_connector/blob_mapping.rb +15 -0
  54. data/lib/rails_connector/blob_mysql.rb +30 -0
  55. data/lib/rails_connector/blob_oracle.rb +37 -0
  56. data/lib/rails_connector/cache_middleware.rb +13 -0
  57. data/lib/rails_connector/channel.rb +18 -0
  58. data/lib/rails_connector/cms_accessible.rb +111 -0
  59. data/lib/rails_connector/cms_base_model.rb +62 -0
  60. data/lib/rails_connector/cms_dispatch_controller.rb +43 -0
  61. data/lib/rails_connector/cms_env.rb +65 -0
  62. data/lib/rails_connector/cms_test_request.rb +8 -0
  63. data/lib/rails_connector/configuration.rb +174 -0
  64. data/lib/rails_connector/content.rb +7 -0
  65. data/lib/rails_connector/core_extensions.rb +1 -0
  66. data/lib/rails_connector/core_extensions/time.rb +17 -0
  67. data/lib/rails_connector/date_attribute.rb +26 -0
  68. data/lib/rails_connector/default_search_request.rb +6 -0
  69. data/lib/rails_connector/engine.rb +65 -0
  70. data/lib/rails_connector/errors.rb +6 -0
  71. data/lib/rails_connector/fiona_datetime.rb +14 -0
  72. data/lib/rails_connector/fiona_engine.rb +8 -0
  73. data/lib/rails_connector/html_string.rb +17 -0
  74. data/lib/rails_connector/job.rb +10 -0
  75. data/lib/rails_connector/link.rb +148 -0
  76. data/lib/rails_connector/link_list.rb +28 -0
  77. data/lib/rails_connector/link_resolvable.rb +5 -0
  78. data/lib/rails_connector/lucene_search_request.rb +102 -0
  79. data/lib/rails_connector/markdown_string.rb +17 -0
  80. data/lib/rails_connector/meta.rb +143 -0
  81. data/lib/rails_connector/meta/eager_loader.rb +84 -0
  82. data/lib/rails_connector/named_link.rb +90 -0
  83. data/lib/rails_connector/news.rb +20 -0
  84. data/lib/rails_connector/obj_class.rb +138 -0
  85. data/lib/rails_connector/obj_class_attr.rb +5 -0
  86. data/lib/rails_connector/object_with_meta_data.rb +13 -0
  87. data/lib/rails_connector/permission.rb +37 -0
  88. data/lib/rails_connector/rack_middlewares.rb +5 -0
  89. data/lib/rails_connector/ses.rb +78 -0
  90. data/lib/rails_connector/ses/verity_accessor.rb +127 -0
  91. data/lib/rails_connector/string_tagging.rb +26 -0
  92. data/lib/rails_connector/verity_search_request.rb +86 -0
  93. data/lib/search_request.rb +2 -0
  94. data/lib/version.rb +7 -0
  95. metadata +277 -0
@@ -0,0 +1,93 @@
1
+ module RailsConnector
2
+ # The methods date?, enum?, html?, linklist?, markdown?, multienum?, string? and
3
+ # text? are created by meta programming have no documentation of their own.
4
+ # Warning: Dependent on the setup of your DB replication, most tables
5
+ # with meta information will not be available on your live system!
6
+ class Attribute < CmsBaseModel
7
+ # The possible types of an attribute.
8
+ TYPES = %w(date enum html linklist markdown multienum string text).freeze
9
+
10
+ self.primary_key = :attribute_id
11
+
12
+ has_and_belongs_to_many :obj_class_definitions, class_name: "::RailsConnector::ObjClass",
13
+ join_table: "#{table_name_prefix}obj_class_attrs"
14
+
15
+ alias_method :obj_class_defs, :obj_class_definitions
16
+ alias_attribute :name, :attribute_name
17
+ alias_attribute :type, :attribute_type
18
+
19
+ # The (human readable) title.
20
+ def title(language = :de)
21
+ blob_data["titles"].presence && blob_data["titles"][language.to_s]
22
+ end
23
+
24
+ # The description of the attribute.
25
+ def help_text(language = :de)
26
+ blob_data["helpTexts"].presence && blob_data["helpTexts"][language.to_s]
27
+ end
28
+
29
+ # Searchable in Content Manager.
30
+ def searchable_in_cm?
31
+ blob_data["isSearchableInCM"].to_i != 0
32
+ end
33
+
34
+ # Returns the possible values if attribute is of type `enum' or `multienum'.
35
+ def values
36
+ blob_data["values"]
37
+ end
38
+
39
+ def max_size
40
+ blob_data["maxSize"]
41
+ end
42
+
43
+ def min_size
44
+ blob_data["minSize"]
45
+ end
46
+
47
+ def edit_field
48
+ blob_data["editField"]
49
+ end
50
+
51
+ def callback
52
+ blob_data["callback"]
53
+ end
54
+
55
+ TYPES.each do |type|
56
+ class_eval <<EOM, __FILE__, __LINE__ + 1
57
+ def #{type}?
58
+ self.attribute_type == "#{type}"
59
+ end
60
+ EOM
61
+ end
62
+
63
+ # Convenience method for find_by_attribute_name
64
+ def self.find_by_name(*args)
65
+ find_by_attribute_name(*args)
66
+ end
67
+
68
+ # Returns the blob as a JSON object.
69
+ def self.read_blob_data(name) #:nodoc:
70
+ blob = RailsConnector::Meta.hello_im_rails_and_im_retarted_so_please_be_patient do # these queries really pollute our logs!
71
+ blob_name =
72
+ if RailsConnector::BlobMapping.exists?
73
+ RailsConnector::BlobMapping.get_fingerprint("#{name}.jsonAttributeDict")
74
+ else
75
+ "#{name}.jsonAttributeDict"
76
+ end
77
+
78
+ RailsConnector::Blob.find_without_excluded_blob_data(blob_name)
79
+ end
80
+
81
+ return {} unless blob&.blob_data?
82
+
83
+ JSON.parse(blob.blob_data)
84
+ end
85
+
86
+ private
87
+
88
+ # load attribute details from blob
89
+ def blob_data #:nodoc:
90
+ @blob_data ||= self.class.read_blob_data(attribute_name)
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,37 @@
1
+ module RailsConnector
2
+ module Authenticable
3
+ def self.included(mod)
4
+ %w(logged_in? admin? current_user).each do |method_name|
5
+ unless instance_method_defined?(mod, method_name)
6
+ mod.class_eval do
7
+ private
8
+
9
+ define_method(method_name, InstanceMethods.method(method_name).to_proc)
10
+ end
11
+ end
12
+
13
+ mod.send(:helper_method, method_name)
14
+ end
15
+ end
16
+
17
+ module InstanceMethods
18
+ def self.logged_in?
19
+ false
20
+ end
21
+
22
+ def self.admin?
23
+ false
24
+ end
25
+
26
+ def self.current_user
27
+ nil
28
+ end
29
+ end
30
+
31
+ def self.instance_method_defined?(mod, method_name)
32
+ (
33
+ mod.instance_methods + mod.protected_instance_methods + mod.private_instance_methods
34
+ ).map(&:to_s).include?(method_name)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,571 @@
1
+ require "json"
2
+ require "openssl"
3
+ require "rails_connector/fiona_datetime"
4
+
5
+ module RailsConnector
6
+ # The CMS file class
7
+ #
8
+ # [children] an Array of objects, Obj, of which this one is the parent
9
+ # [parent] the Obj of which this one is a child - nil for the root object
10
+ # @api public
11
+ class BasicObj < CmsBaseModel
12
+ include RailsConnector::Meta
13
+
14
+ CRYPT_KEY = "\xd7\x28\x9c\x63\xd6\x29\xdf\x20\xcd\x32\xcf\x30\xcf\x30\xcf\x30\xdf\x20\xb6\x49"\
15
+ "\x91\x6e\x99\x66\x90\x6f\x8f\x70\x9e\x61\x8d\x72\x94\x6b\xdf\x20\xbe\x41\xb8\x47\xc4\x3b"\
16
+ "\xdf\x20\xbd\x42\x9a\x65\x8d\x72\x93\x6c\x96\x69\x91\x6e".freeze
17
+
18
+ PREDEFINED_ATTRIBUTES = %w(blob body title channels sort_key1 sort_type1 sort_key2 sort_type2
19
+ sort_key3 sort_type3 sort_order).freeze
20
+
21
+ self.store_full_sti_class = false
22
+
23
+ def self.inherited(subclass)
24
+ super
25
+ subclass.delegate_attributes
26
+ end
27
+
28
+ def self.configure_for_content(which)
29
+ case which
30
+ when :released then configure_column_information("objs", true)
31
+ when :edited
32
+ configure_column_information("preview_objs", false)
33
+ has_many(:arel_permissions, class_name: "::RailsConnector::Permission", foreign_key: "object_id")
34
+ else
35
+ raise "configure_for_content called with unknown parameter #{which}"
36
+ end
37
+ end
38
+
39
+ def self.configure_column_information(table_name_postfix, use_cached_permissions)
40
+ reset_column_information
41
+
42
+ self.table_name = "#{table_name_prefix}#{table_name_postfix}"
43
+ self.primary_key = "obj_id"
44
+ self.inheritance_column = "obj_class"
45
+
46
+ @@use_cached_permissions = use_cached_permissions
47
+ descendants.each do |klass|
48
+ klass.reset_table_name
49
+ klass.initialize_attributes
50
+ end
51
+
52
+ RailsConnector::Meta::EagerLoader.instance.obj_classes.each do |class_name, obj_class|
53
+ next unless obj_class
54
+
55
+ next unless /^[A-Z]/.match?(class_name)
56
+
57
+ klass = class_name.safe_constantize
58
+ next unless klass
59
+
60
+ klass.initialize_attributes if klass < RailsConnector::BasicObj
61
+ end
62
+ end
63
+
64
+ def self.initialize_attributes
65
+ PREDEFINED_ATTRIBUTES.each do |attribute|
66
+ send(:define_attribute, attribute, ActiveRecord::Type::String.new)
67
+ end
68
+
69
+ return if obj_class_definition.blank?
70
+
71
+ obj_class_definition.custom_attributes.each_key do |attribute|
72
+ send(:define_attribute, attribute, ActiveRecord::Type::String.new)
73
+ end
74
+ end
75
+
76
+ def self.delegate_attributes
77
+ PREDEFINED_ATTRIBUTES.each do |attribute|
78
+ delegate attribute, to: :attr_dict
79
+ end
80
+
81
+ return if obj_class_definition.blank?
82
+
83
+ obj_class_definition.custom_attributes.each_key do |attribute|
84
+ delegate attribute, to: :attr_dict
85
+ end
86
+ end
87
+
88
+ attribute :last_changed, :fiona_datetime
89
+ attribute :valid_from, :fiona_datetime
90
+ attribute :valid_until, :fiona_datetime
91
+ attribute :suppress_export, :boolean
92
+ attribute :is_edited, :boolean
93
+ attribute :is_released, :boolean
94
+
95
+ delegate :sort_keys, to: :attr_dict
96
+ delegate :body_data_path, to: :attr_dict
97
+ delegate :empty?, to: :attr_dict
98
+ delegate :text_links, to: :attr_dict
99
+
100
+ # Patch to avoid a type_condition being added by ActiveRecord::Base.add_conditions! for Obj.find(params):
101
+ def self.descends_from_active_record?
102
+ self == BasicObj || superclass == BasicObj
103
+ end
104
+
105
+ # A CMS administrator can specify the <tt>obj_class</tt> for a given CMS object.
106
+ # In Rails, this could be either:
107
+ #
108
+ # * A valid and existing model name
109
+ # * A valid and non-existing model name
110
+ # * An invalid model name
111
+ #
112
+ # Rails' STI mechanism only considers the first case.
113
+ # In any other case, RailsConnector::Obj is used, except when explicitely asked
114
+ # for a model in the RailsConnector namespace (RailsConnector::Permission etc.)
115
+
116
+ def self.compute_type(type_name)
117
+ try_type { type_name.constantize } || ::Obj
118
+ end
119
+
120
+ def self.reset_type_cache
121
+ # We don't cache types at all here.
122
+ end
123
+
124
+ def self.reset_reflections
125
+ has_many :children, class_name: "Obj", foreign_key: "parent_obj_id", validate: false
126
+ belongs_to :parent, class_name: "Obj", foreign_key: "parent_obj_id"
127
+ end
128
+
129
+ # @api public
130
+ def permissions
131
+ @@use_cached_permissions ? attr_dict.permissions : arel_permissions
132
+ end
133
+
134
+ # @api public
135
+ def permitted_for_user?(user)
136
+ if permitted_groups.blank?
137
+ true
138
+ else
139
+ if user
140
+ (permitted_groups & user.live_server_groups).any?
141
+ else
142
+ false
143
+ end
144
+ end
145
+ end
146
+
147
+ # Returns the root Obj. Its id is 2001 and cannot be changed.
148
+ # @api public
149
+ def self.root
150
+ Obj.find(2001)
151
+ end
152
+
153
+ # Returns the homepage object. This can be overwritten in your application's +Obj+.
154
+ # Use <tt>Obj#homepage?</tt> to check if an object is the homepage.
155
+ # @api public
156
+ def self.homepage
157
+ root
158
+ end
159
+
160
+ # for testing purposes only
161
+ def self.reset_homepage
162
+ @@homepage_id = nil
163
+ end
164
+
165
+ # This method determines the controller that should be invoked when the Obj is requested.
166
+ # By default a controller matching the Obj's obj_class will be used.
167
+ # If the controller does not exist, the CmsController will be used as a fallback.
168
+ # Overwrite this method to force a different controller to be used.
169
+ # @api public
170
+ def controller_name
171
+ obj_class
172
+ end
173
+
174
+ # This method determines the action that should be invoked when the Obj is requested.
175
+ # The default action is 'index'.
176
+ # Overwrite this method to force a different action to be used.
177
+ # @api public
178
+ def controller_action_name
179
+ "index"
180
+ end
181
+
182
+ @@homepage_id = nil
183
+
184
+ # Returns true if the current object has the same id as the homepage object. Always use this method instead of
185
+ # manually comparing an object to <tt>Obj.homepage</tt>, as Obj#homepage? caches the object id
186
+ # and thus requires no extra database access.
187
+ # @api public
188
+ def homepage?
189
+ id == (@@homepage_id ||= self.class.homepage.id)
190
+ end
191
+
192
+ # This method is used to calculate a part of a URL of an obj.
193
+ #
194
+ # The routing schema: <code><em><obj.id></em>/<em><obj.slug></em></code>
195
+ #
196
+ # The default is +obj.name+.
197
+ #
198
+ # You can customize this part by overwriting +obj.slug+ in {Obj}.
199
+ # @return [String]
200
+ # @api public
201
+ def slug
202
+ name
203
+ end
204
+
205
+ # Returns the title of the content or the name.
206
+ # @api public
207
+ def display_title
208
+ title || name
209
+ end
210
+
211
+ unless defined?(OBJECT_TYPES)
212
+ OBJECT_TYPES = {
213
+ "2" => :document,
214
+ "5" => :publication,
215
+ "B" => :image,
216
+ "C" => :generic
217
+ }.freeze
218
+ end
219
+
220
+ # Returns the type of the object: :document, :publication, :image or :generic
221
+ # @api public
222
+ def object_type
223
+ OBJECT_TYPES[obj_type_code]
224
+ end
225
+
226
+ # Returns true if image? or generic?
227
+ # @api public
228
+ def binary?
229
+ %i(image generic).include? object_type
230
+ end
231
+
232
+ # Returns true if object_type == :image
233
+ # @api public
234
+ def image?
235
+ object_type == :image
236
+ end
237
+
238
+ # Returns true if object_type == :generic
239
+ # @api public
240
+ def generic?
241
+ object_type == :generic
242
+ end
243
+
244
+ # Returns true if object_type == :publication (for folders)
245
+ # @api public
246
+ def publication?
247
+ object_type == :publication
248
+ end
249
+
250
+ # Returns true if object_type == :document
251
+ # @api public
252
+ def document?
253
+ object_type == :document
254
+ end
255
+
256
+ # Returns true if this object is active.
257
+ # @api public
258
+ def active?
259
+ return false unless valid_from
260
+
261
+ valid_from <= Time.now && (!valid_until || Time.now <= valid_until)
262
+ end
263
+
264
+ # Returns true if this object has edited content.
265
+ # Note that edited content is not available when Configuration.mode == :live
266
+ # and edited? will always return false in this case.
267
+ # @api public
268
+ def edited?
269
+ is_edited
270
+ end
271
+
272
+ # Returns true if this object has released content
273
+ # @api public
274
+ def released?
275
+ is_released
276
+ end
277
+
278
+ # Returns true if the Obj is suppressed.
279
+ # A suppressed Obj does not represent an entire web page, but only a part of a page
280
+ # (for example a teaser) and will not be delivered by the rails application
281
+ # as a standalone web page.
282
+ # @api public
283
+ def suppressed?
284
+ suppress_export
285
+ end
286
+
287
+ # Returns true if the export of the object is not suppressed and the content is active?
288
+ # @api public
289
+ def exportable?
290
+ !suppressed? && active?
291
+ end
292
+
293
+ # Returns the file name to which the Content.file_extension has been appended.
294
+ # @api public
295
+ def filename
296
+ extension = ".#{file_extension}" unless file_extension.blank?
297
+ "#{name}#{extension}"
298
+ rescue NoMethodError
299
+ name
300
+ end
301
+
302
+ # Returns an array with the names of groups that are permitted to access this Obj.
303
+ # This corresponds to the cms permission "permissionLiveServerRead".
304
+ # @api public
305
+ def permitted_groups
306
+ attr_dict.permitted_groups
307
+ end
308
+
309
+ # Returns true if this object is the root object.
310
+ # @api public
311
+ def root?
312
+ parent_obj_id.nil?
313
+ end
314
+
315
+ # Returns a list of exportable? children excluding the binary? ones unless :all is specfied.
316
+ # This is mainly used for navigations.
317
+ # @api public
318
+ def toclist(*args)
319
+ return [] unless publication?
320
+
321
+ toclist = children.to_a.select { |toc| toc.exportable? }
322
+ toclist = toclist.reject { |toc| toc.binary? } unless args.include?(:all)
323
+ toclist
324
+ end
325
+
326
+ # Returns the sorted +toclist+, respecting sort order and type of this Obj.
327
+ # @api public
328
+ def sorted_toclist(*args)
329
+ list = toclist(*args)
330
+ return [] if list.blank?
331
+
332
+ cached_sort_key1 = sort_key1
333
+ cached_sort_type1 = sort_type1
334
+
335
+ sorted_list =
336
+ if cached_sort_key1.blank?
337
+ list.sort_by(&:name)
338
+ else
339
+ cached_sort_key2 = sort_key2
340
+ cached_sort_type2 = sort_type2
341
+ cached_sort_key3 = sort_key3
342
+ cached_sort_type3 = sort_type3
343
+
344
+ list.sort do |left_obj, right_obj|
345
+ compare = compare_on_sort_key(left_obj, right_obj, cached_sort_key1, cached_sort_type1)
346
+ if compare == 0 && cached_sort_key2
347
+ compare = compare_on_sort_key(left_obj, right_obj, cached_sort_key2, cached_sort_type2)
348
+ if compare == 0 && cached_sort_key3
349
+ compare = compare_on_sort_key(left_obj, right_obj, cached_sort_key3, cached_sort_type3)
350
+ end
351
+ end
352
+ compare
353
+ end
354
+ end
355
+
356
+ sort_order == "descending" ? sorted_list.reverse : sorted_list
357
+ end
358
+
359
+ # Returns an Array of all the ancestor objects, starting at the root and ending at this object's parent.
360
+ # @api public
361
+ def ancestors
362
+ if parent
363
+ parent.ancestors + [parent]
364
+ else
365
+ []
366
+ end
367
+ end
368
+
369
+ # Returns the Object with the given name next in the hierarchy
370
+ # returns nil if no object with the given name was found.
371
+ # @api public
372
+ def find_nearest(name)
373
+ obj = children.find_by_name(name)
374
+ return obj if obj&.active?
375
+
376
+ parent.find_nearest(name) unless root?
377
+ end
378
+
379
+ # Returns the value of the attribute specified by its name.
380
+ #
381
+ # Passing an invalid key will not raise an error, but return nil.
382
+ # @api public
383
+ def [](key)
384
+ if has_attribute?(key)
385
+ begin
386
+ return attr_dict.send(key) if attr_dict.respond_to?(key)
387
+
388
+ read_attribute(key)
389
+ rescue NoMethodError
390
+ nil
391
+ end
392
+ end
393
+ end
394
+
395
+ # Reloads the attributes of this object from the database, invalidates custom attributes
396
+ # @api public
397
+ def reload
398
+ super
399
+ @attr_dict = nil
400
+ @attr_values = nil
401
+ @attr_defs = nil
402
+ self
403
+ end
404
+
405
+ # object_name is a legacy alias to name. Please use name instead, because only name
406
+ # works with ActiveRecord's dynamic finder methods like find_by_name(...)
407
+ def object_name
408
+ name
409
+ end
410
+
411
+ # object_class is a legacy alias to name. Please use obj_class instead, because only obj_class
412
+ # works with ActiveRecord's dynamic finder methods like find_by_obj_class(...)
413
+ # @api public
414
+ def object_class
415
+ obj_class
416
+ end
417
+
418
+ # for binary Objs body_length equals the file size
419
+ # for non-binary Objs body_length equals the number of characters in the body (main content)
420
+ # @api public
421
+ delegate :body_length, to: :attr_dict
422
+
423
+ # Override this method to provide an external url
424
+ # where the content (the body) of this Obj can be downloaded.
425
+ # The Rails Connector will then use this url when creating links to this Obj.
426
+ # This is useful when delivering images via a content delivery network (CDN), for example.
427
+ # Returns nil by default.
428
+ #
429
+ # Note: When this method returns an url, the Rails Connector's DefaultCmsController
430
+ # will redirect to this url instead of delivering this Obj's body.
431
+ # And the Rails Connector's cms_path and cms_url helpers will link to this url
432
+ # instead of linking to the Obj.
433
+ #
434
+ # Note also that the url will be used regardless of the Obj's permissions, so be careful not
435
+ # to provide urls that contain unprotected secrets.
436
+ # @api public
437
+ def body_data_url
438
+ nil
439
+ end
440
+
441
+ def set_attr_values(dictionary)
442
+ @attr_values = dictionary
443
+ @attr_dict = nil
444
+ end
445
+
446
+ # Returns an instance of AttrDict which provides access to formatted attribute values (i.e. content).
447
+ # The method uses attr_defs to determine the right formatting depending on the particular field type.
448
+ def attr_dict
449
+ @attr_dict ||= AttrDict.new(self, attr_values, attr_defs)
450
+ end
451
+
452
+ # Returns a nested hash of attribute values.
453
+ def attr_values
454
+ @attr_values ||= begin
455
+ encoded_and_encrypted_attr_values = read_attribute(:attr_values)
456
+ return {} unless encoded_and_encrypted_attr_values
457
+
458
+ encrypted_attr_values = Base64.decode64(encoded_and_encrypted_attr_values)
459
+ if !encrypted_attr_values.starts_with?("Salted__") || encrypted_attr_values.length < 16
460
+ raise "attr_values has wrong format"
461
+ end
462
+
463
+ cipher = OpenSSL::Cipher.new("rc4")
464
+ cipher.decrypt
465
+ salt = encrypted_attr_values[8..15]
466
+ cipher.pkcs5_keyivgen(CRYPT_KEY, salt, 1)
467
+ encrypted_attr_values = encrypted_attr_values[16..-1]
468
+ if encrypted_attr_values.present?
469
+ decrypted_attr_values = cipher.update(encrypted_attr_values)
470
+ decrypted_attr_values << cipher.final
471
+ JSON.parse(decrypted_attr_values)
472
+ else
473
+ {}
474
+ end
475
+ end
476
+ end
477
+
478
+ # Returns a nested hash of attribute definitions.
479
+ def attr_defs
480
+ @attr_defs ||= JSON.parse(read_attribute(:attr_defs) || "{}")
481
+ end
482
+
483
+ # Provides access to field metadata:
484
+ #
485
+ # <%= @obj.metadata_for_field(:body_de, :titles, :en) %>
486
+ #
487
+ # In addition to the field name, the method takes an arbitrary number of arguments
488
+ # constituting a path through the nested (hash) structures of the attribute definition (attr_defs).
489
+ #
490
+ # If the path doesn't fit the metadata structure, the method returns nil and doesn't raise an exception.
491
+ def metadata_for_field(field, *args)
492
+ rslt = fiona_fields[field.to_s] || attr_defs[field.to_s]
493
+ args.each do |key|
494
+ rslt = rslt[key.to_s] unless rslt.nil?
495
+ end
496
+ rslt
497
+ end
498
+
499
+ # Returns the MIME-type as determined from the file_extension - see MIME::Types
500
+ # @api public
501
+ def mime_type
502
+ @mime_type ||= compute_mime_type
503
+ end
504
+
505
+ def respond_to?(method_id, include_private = false)
506
+ if super
507
+ true
508
+ elsif %w(_attr_dict _attr_defs _attr_values).include?(method_id.to_s)
509
+ # prevent infinite recursion when calling "attr_*" below,
510
+ # since rails checks the absence of an "_attr_*" method internally
511
+ false
512
+ else
513
+ attr_dict.respond_to?(method_id)
514
+ end
515
+ end
516
+
517
+ private
518
+
519
+ def fiona_fields
520
+ @fiona_fields ||=
521
+ %w(name obj_class workflow suppressexport permalink).inject({}) do |all, field|
522
+ all.merge! field => {
523
+ "titles" => { "de" => field.humanize, "en" => field.humanize },
524
+ "type" => "string",
525
+ "help_texts" => { "de" => field, "en" => field }
526
+ }
527
+ end
528
+ end
529
+
530
+ def compute_mime_type
531
+ MIME::Types.type_for(file_extension).first.content_type
532
+ rescue StandardError
533
+ binary? ? "application/octet-stream" : "text/plain"
534
+ end
535
+
536
+ def compare_on_sort_key(left_obj, right_obj, my_sort_key, my_sort_type)
537
+ left_value = left_obj[my_sort_key]
538
+ right_value = right_obj[my_sort_key]
539
+
540
+ if left_value.nil?
541
+ 1
542
+ elsif right_value.nil?
543
+ -1
544
+ # hardcoded type check needed for speed
545
+ elsif left_value.is_a?(Time) && right_value.is_a?(Time)
546
+ left_value <=> right_value
547
+ else
548
+ if my_sort_type == "numeric"
549
+ (begin
550
+ left_value.to_i
551
+ rescue StandardError
552
+ 0
553
+ end) <=> (begin
554
+ right_value.to_i
555
+ rescue StandardError
556
+ 0
557
+ end)
558
+ else
559
+ left_value.to_s.downcase <=> right_value.to_s.downcase
560
+ end
561
+ end
562
+ end
563
+
564
+ def self.try_type
565
+ result = yield
566
+ result if result < CmsBaseModel
567
+ rescue NameError, ActiveRecord::ActiveRecordError
568
+ nil
569
+ end
570
+ end
571
+ end