infopark_cloud_connector 6.8.0.beta.200.621.4c8e1b0

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.
@@ -0,0 +1,622 @@
1
+ require 'json'
2
+ require 'ostruct'
3
+ require 'kvom/model_identity'
4
+
5
+ module RailsConnector
6
+ # The CMS file class
7
+ class Obj
8
+ extend ActiveModel::Naming
9
+ include Kvom::ModelIdentity
10
+
11
+ include DateAttribute
12
+ include StringTagging
13
+ include SEO
14
+ include ObjBody
15
+
16
+ extend PathConversion
17
+ include PathConversion
18
+
19
+ # Create a new Obj instance with the given values and attributes.
20
+ # Normally this method should not be used.
21
+ # Instead Objs should be loaded from the cms database.
22
+ def initialize(values = {}, meta = {})
23
+ update_data(values, meta)
24
+ end
25
+
26
+ # instantiate an Obj instance from obj_data.
27
+ # May result in an instance of a subclass of Obj according to STI rules.
28
+ def self.instantiate(obj_data) # :nodoc:
29
+ obj_class = obj_data["values"]["obj_class"]
30
+ Obj.compute_type(obj_class).new(
31
+ obj_data["values"], obj_data
32
+ )
33
+ end
34
+
35
+ def id
36
+ @values["id"]
37
+ end
38
+
39
+ ### FINDERS ####################
40
+
41
+ # Find an Obj by it's id.
42
+ # If the paremeter is an Array containing ids, return a list of corresponding Objs.
43
+ def self.find(id_or_list)
44
+ case id_or_list
45
+ when Array
46
+ find_objs_by(:id, id_or_list).map(&:first)
47
+ else
48
+ obj = find_objs_by(:id, [id_or_list.to_s]).first.first
49
+ obj or raise ResourceNotFound, "Could not find #{self} with id #{id_or_list}"
50
+ end
51
+ end
52
+
53
+ # (notice: not yet implemented)
54
+ # Returns a list of all Objs.
55
+ # If invoked on a subclass of Obj, the result will be restricted to Obj of that subclass.
56
+ def self.all # :nodoc:
57
+ raise "not yet implemented!"
58
+ end
59
+
60
+ # (notice: not yet implemented)
61
+ # returns an Array of all Objs with the given obj_class.
62
+ def self.find_all_by_obj_class(obj_class) # :nodoc:
63
+ raise "not yet implemented!"
64
+ end
65
+
66
+ # Find the Obj with the given path.
67
+ # Returns nil if no matching Obj exists.
68
+ def self.find_by_path(path)
69
+ find_objs_by(:path, [path]).first.first
70
+ end
71
+
72
+ def self.find_by_path_list(path_list) # :nodoc:
73
+ find_by_path(path_from_list(path_list))
74
+ end
75
+
76
+ def self.find_many_by_paths(pathes) # :nodoc:
77
+ find_objs_by(:path, pathes).map(&:first)
78
+ end
79
+
80
+ # (notice: not yet implemented)
81
+ # Find an Obj with the given name.
82
+ # If several Objs exist with the given name, one of them is chosen and returned.
83
+ # If no Obj with the name exits, nil is returned.
84
+ def self.find_by_name(name) # :nodoc:
85
+ raise "not yet implemented!"
86
+ end
87
+
88
+ # (notice: not yet implemented)
89
+ # Find all Objs with the given name.
90
+ def self.find_all_by_name(name) # :nodoc:
91
+ raise "not yet implemented!"
92
+ end
93
+
94
+ # Return the Obj with the given permalink or nil if no matching Obj exists.
95
+ def self.find_by_permalink(permalink)
96
+ find_objs_by(:permalink, [permalink]).first.first
97
+ end
98
+
99
+ # Return the Obj with the given permalink or raise ResourceNotFound if no matching Obj exists.
100
+ def self.find_by_permalink!(permalink)
101
+ find_by_permalink(permalink) or
102
+ raise ResourceNotFound, "Could not find #{self} with permalink '#{permalink}'"
103
+ end
104
+
105
+ # accepts the name of an "obj_by" - view and a list of keys.
106
+ # returns a list of lists of Objs: a list of Objs for each given keys.
107
+ def self.find_objs_by(view, keys) # :nodoc:
108
+ Workspace.current.find_obj_data_by(view, keys).map do |list|
109
+ list.map { |obj_data| Obj.instantiate(obj_data) }
110
+ end
111
+ end
112
+
113
+ def to_param # :nodoc:
114
+ id
115
+ end
116
+
117
+ def self.configure_for_content(mode) # :nodoc:
118
+ # this method exists only for compatibility with the fiona connector.
119
+ end
120
+
121
+ # A CMS administrator can specify the <tt>obj_class</tt> for a given CMS object.
122
+ # In Rails, this could be either:
123
+ #
124
+ # * A valid and existing model name
125
+ # * A valid and non-existing model name
126
+ # * An invalid model name
127
+ #
128
+ # Rails' STI mechanism only considers the first case.
129
+ # In any other case, RailsConnector::Obj is used, except when explicitely asked
130
+ # for a model in the RailsConnector namespace (RailsConnector::Permission etc.)
131
+
132
+ def self.compute_type(type_name) # :nodoc:
133
+ @compute_type_cache ||= {}
134
+ @compute_type_cache [type_name] ||= try_type { type_name.constantize } || self
135
+ end
136
+
137
+ # return the Obj that is the parent of this Obj.
138
+ # returns nil for the root Obj.
139
+ def parent
140
+ root? ? nil : Obj.find_by_path_list(path_list[0..-2])
141
+ end
142
+
143
+ # Returns an Array of all the ancestor objects, starting at the root and ending at this object's parent.
144
+ def ancestors
145
+ return [] if root?
146
+ ancestor_paths = path_list[0..-2].inject([""]) do |list, component|
147
+ list << list.last + "/#{component}"
148
+ end
149
+ ancestor_paths[0] = "/"
150
+ Obj.find_many_by_paths(ancestor_paths)
151
+ end
152
+
153
+ # return a list of all child Objs.
154
+ def children
155
+ Obj.find_objs_by(:ppath, [path]).first
156
+ end
157
+
158
+ ### ATTRIBUTES #################
159
+
160
+ # returns the Obj's path as a String.
161
+ def path
162
+ path_from_list(path_list)
163
+ end
164
+
165
+ def path_list # :nodoc:
166
+ read_attribute(:path) || []
167
+ end
168
+
169
+ # returns the Obj's name, i.e. the last component of the path.
170
+ def name
171
+ path_list.last || ""
172
+ end
173
+
174
+ def permissions
175
+ # FIXME permissions
176
+ @permissions ||= OpenStruct.new({
177
+ :live => permitted_groups,
178
+ :read => [],
179
+ :write => [],
180
+ :root => [],
181
+ :create_children => [],
182
+ })
183
+ end
184
+
185
+ def permitted_for_user?(user)
186
+ if permitted_groups.blank?
187
+ true
188
+ else
189
+ if user
190
+ (permitted_groups & user.live_server_groups).any?
191
+ else
192
+ false
193
+ end
194
+ end
195
+ end
196
+
197
+ def object_id # :nodoc:
198
+ obj_id
199
+ end
200
+
201
+ # Returns the root Obj, i.e. the Obj with the path "/"
202
+ def self.root
203
+ Obj.find_by_path("/") or raise ResourceNotFound, "Obj.root not found: There is no Obj with path '/'."
204
+ end
205
+
206
+ # Returns the homepage object. This can be overwritten in your application's +ObjExtensions+.
207
+ # Use <tt>Obj#homepage?</tt> to check if an object is the homepage.
208
+ def self.homepage
209
+ root
210
+ end
211
+
212
+ # returns the obj's permalink.
213
+ def permalink
214
+ read_attribute(:permalink)
215
+ end
216
+
217
+ # This method determines the controller that should be invoked when the Obj is requested.
218
+ # By default a controller matching the Obj's obj_class will be used.
219
+ # If the controller does not exist, the CmsController will be used as a fallback.
220
+ # Overwrite this method to force a different controller to be used.
221
+ def controller_name
222
+ obj_class
223
+ end
224
+
225
+ # This method determines the action that should be invoked when the Obj is requested.
226
+ # The default action is 'index'.
227
+ # Overwrite this method to force a different action to be used.
228
+ def controller_action_name
229
+ "index"
230
+ end
231
+
232
+ # Returns true if the current object is the homepage object.
233
+ def homepage?
234
+ self == self.class.homepage
235
+ end
236
+
237
+ # Returns the title of the content or the name.
238
+ def display_title
239
+ self.title || name
240
+ end
241
+
242
+ def title
243
+ read_attribute(:title)
244
+ end
245
+
246
+ # Returns the type of the object: :document, :publication, :image or :generic
247
+ def object_type
248
+ read_attribute(:obj_type).to_sym
249
+ end
250
+
251
+ # Returns true if image? or generic?
252
+ def binary?
253
+ [:image, :generic].include? object_type
254
+ end
255
+
256
+ # Returns true if object_type == :image
257
+ def image?
258
+ object_type == :image
259
+ end
260
+
261
+ # Returns true if object_type == :generic
262
+ def generic?
263
+ object_type == :generic
264
+ end
265
+
266
+ # Returns true if object_type == :publication (for folders)
267
+ def publication?
268
+ object_type == :publication
269
+ end
270
+
271
+ # Returns true if object_type == :document
272
+ def document?
273
+ object_type == :document
274
+ end
275
+
276
+ # Returns true if this object is active (time_when is in object's time interval)
277
+ def active?(time_when = nil)
278
+ return false unless valid_from
279
+ time_then = time_when || Obj.preview_time
280
+ valid_from <= time_then && (!valid_until || time_then <= valid_until)
281
+ end
282
+
283
+ # compatibility with legacy apps.
284
+ def suppress_export # :nodoc:
285
+ suppressed? ? 1 : 0
286
+ end
287
+
288
+ # Returns true if the Obj is suppressed.
289
+ # A suppressed Obj does not represent an entire web page, but only a part of a page
290
+ # (for example a teaser) and will not be delivered by the rails application
291
+ # as a standalone web page.
292
+ def suppressed?
293
+ @values["suppress_export"] ? true : false
294
+ end
295
+
296
+ # Returns true if the export of the object is not suppressed and the content is active?
297
+ def exportable?(current_time = nil)
298
+ !suppressed? && active?(current_time)
299
+ end
300
+
301
+ # Returns the file name to which the Content.file_extension has been appended.
302
+ def filename
303
+ Rails.logger.warn(
304
+ "DEPRECATION WARNING: "\
305
+ "The Method Obj#filename is no longer supported. Please use Obj#name instead. "\
306
+ "From: #{caller[0]}"
307
+ )
308
+
309
+ name
310
+ end
311
+
312
+ # Returns an array with the names of groups that are permitted to access this Obj.
313
+ # This corresponds to the cms permission "permissionLiveServerRead".
314
+ def permitted_groups
315
+ # FIXME permissions not yet implemented in fiona 7
316
+ []
317
+ end
318
+
319
+ # Returns true if this object is the root object.
320
+ def root?
321
+ path_list.empty?
322
+ end
323
+
324
+ # Returns a list of exportable? children excluding the binary? ones unless :all is specfied.
325
+ # This is mainly used for navigations.
326
+ def toclist(*args)
327
+ return [] unless publication?
328
+ time = args.detect {|value| value.kind_of? Time}
329
+ toclist = children.select{ |toc| toc.exportable?(time) }
330
+ toclist = toclist.reject { |toc| toc.binary? } unless args.include?(:all)
331
+ toclist
332
+ end
333
+
334
+ # Returns the sorted +toclist+, respecting sort order and type of this Obj.
335
+ def sorted_toclist(*args)
336
+ list = self.toclist(*args)
337
+ return [] if list.blank?
338
+
339
+ cached_sort_key1 = self.sort_key1
340
+ cached_sort_type1 = self.sort_type1
341
+
342
+ sorted_list =
343
+ if cached_sort_key1.blank?
344
+ list.sort { |left_obj, right_obj| left_obj.name <=> right_obj.name }
345
+ else
346
+ cached_sort_key2 = self.sort_key2
347
+ cached_sort_type2 = self.sort_type2
348
+ cached_sort_key3 = self.sort_key3
349
+ cached_sort_type3 = self.sort_type3
350
+
351
+ list.sort do |left_obj, right_obj|
352
+ compare = compare_on_sort_key(left_obj, right_obj, cached_sort_key1, cached_sort_type1)
353
+ if compare == 0 && cached_sort_key2
354
+ compare = compare_on_sort_key(left_obj, right_obj, cached_sort_key2, cached_sort_type2)
355
+ if compare == 0 && cached_sort_key3
356
+ compare = compare_on_sort_key(left_obj, right_obj, cached_sort_key3, cached_sort_type3)
357
+ end
358
+ end
359
+ compare
360
+ end
361
+ end
362
+
363
+ return self.sort_order == "descending" ? sorted_list.reverse : sorted_list
364
+ end
365
+
366
+ def sort_order # :nodoc:
367
+ read_attribute(:sort_order) == 1 ? "descending" : "ascending"
368
+ end
369
+
370
+ def sort_type1 # :nodoc:
371
+ converted_sort_type(:sort_type1)
372
+ end
373
+
374
+ def sort_type2 # :nodoc:
375
+ converted_sort_type(:sort_type2)
376
+ end
377
+
378
+ def sort_type3 # :nodoc:
379
+ converted_sort_type(:sort_type3)
380
+ end
381
+
382
+ def sort_key1 # :nodoc:
383
+ converted_sort_key(:sort_key1)
384
+ end
385
+
386
+ def sort_key2 # :nodoc:
387
+ converted_sort_key(:sort_key2)
388
+ end
389
+
390
+ def sort_key3 # :nodoc:
391
+ converted_sort_key(:sort_key3)
392
+ end
393
+
394
+ # Returns the Object with the given name next in the hierarchy
395
+ # returns nil if no object with the given name was found.
396
+ def find_nearest(name)
397
+ obj = self.class.find_by_path_list(path_list + [name])
398
+ return obj if obj and obj.active?
399
+ parent.find_nearest(name) unless self.root?
400
+ end
401
+
402
+ # Returns the value of the attribute specified by its name.
403
+ #
404
+ # Passing an invalid key will not raise an error, but return nil.
405
+ def [](raw_key)
406
+ key = raw_key.to_s
407
+ case key
408
+ when "name"
409
+ name
410
+ when "body"
411
+ body
412
+ else
413
+ read_attribute(key)
414
+ end
415
+ end
416
+
417
+ # Reloads the attributes of this object from the database.
418
+ # Notice that the ruby class of this Obj instance will NOT change,
419
+ # even if the obj_class in the database has changed.
420
+ def reload
421
+ obj_data = Workspace.current.find_obj_data_by(:id, [id.to_s]).first.first
422
+ update_data(obj_data["values"], obj_data)
423
+ end
424
+
425
+ def last_changed
426
+ self[:last_changed]
427
+ end
428
+
429
+ def valid_from
430
+ self[:valid_from]
431
+ end
432
+
433
+ def valid_until
434
+ self[:valid_until]
435
+ end
436
+
437
+ # For a binary Obj, the content_type is equal to the content_type of it's body (i.e. it's data).
438
+ # For non-binary Objs, a the default content_type is "text/html".
439
+ # Override this method in subclasses to define a different content_type.
440
+ # Note that only Objs with content_type "text/html"
441
+ # will be rendered with layout and templates by the DefaultCmsController.
442
+ def content_type
443
+ if binary?
444
+ body_content_type
445
+ else
446
+ "text/html"
447
+ end
448
+ end
449
+ alias mime_type content_type
450
+
451
+ # returns the extension (the part after the last dot) from the Obj's name.
452
+ # returns an empty string if no extension is present in the Obj's name.
453
+ def file_extension
454
+ File.extname(name)[1..-1] || ""
455
+ end
456
+
457
+ def to_liquid # :nodoc:
458
+ LiquidSupport::ObjDrop.new(self)
459
+ end
460
+
461
+ def respond_to?(method_id, include_private=false) # :nodoc:
462
+ if has_attribute?(method_id)
463
+ true
464
+ else
465
+ super
466
+ end
467
+ end
468
+
469
+ # Returns a list of the names of all custom attributes defined for this Obj as Symbols.
470
+ # A custom attribute is a user-defined attribute, i.e. one that is not built-in in the CMS.
471
+ def custom_attribute_names
472
+ @attributes.keys.map(&:to_sym)
473
+ end
474
+
475
+ def has_attribute?(name)
476
+ name_as_string = name.to_s
477
+ @values.has_key?(name_as_string) || @attributes.has_key?(name_as_string)
478
+ end
479
+
480
+ def self.preview_time=(t) # :nodoc:
481
+ Thread.current[:preview_time] = t
482
+ end
483
+
484
+ def self.preview_time # :nodoc:
485
+ Thread.current[:preview_time] || Time.now
486
+ end
487
+
488
+ def inspect
489
+ "<#{self.class} id=\"#{id}\" path=\"#{path}\">"
490
+ end
491
+
492
+ private
493
+
494
+ def update_data(values = {}, meta = {})
495
+ @values = values
496
+ @attributes = meta["attributes"] || {}
497
+ @attr_cache = {}
498
+ end
499
+
500
+ def read_attribute(name)
501
+ name = name.to_s
502
+ if name == "suppress_export"
503
+ suppress_export
504
+ else
505
+ raw = @values[name]
506
+ @attr_cache[name] ||= case type_of(name)
507
+ when :markdown
508
+ StringTagging.tag_as_markdown(raw, self)
509
+ when :html
510
+ StringTagging.tag_as_html(raw, self)
511
+ when :date
512
+ DateAttribute.parse raw if raw
513
+ when :linklist
514
+ if name == "text_links"
515
+ LinkList.new(raw.values)
516
+ else
517
+ LinkList.new(raw)
518
+ end
519
+ else
520
+ raw
521
+ end
522
+ end
523
+ end
524
+
525
+ def type_of(key)
526
+ key = key.to_s
527
+ case key
528
+ when "permission_live_server_read"
529
+ nil
530
+ when "text_links"
531
+ :linklist
532
+ when "valid_from"
533
+ :date
534
+ when "valid_until"
535
+ :date
536
+ when "last_changed"
537
+ :date
538
+ when "title"
539
+ :html
540
+ else
541
+ if attr_def = @attributes[key]
542
+ type = attr_def["type"]
543
+ type.to_sym if type
544
+ end
545
+ end
546
+ end
547
+
548
+ def as_date(value)
549
+ DateAttribute.parse(value) unless value.nil?
550
+ end
551
+
552
+ def method_missing(method_id, *args) # :nodoc:
553
+ if has_attribute?(method_id)
554
+ read_attribute(method_id)
555
+ else
556
+ super
557
+ end
558
+ end
559
+
560
+ def compare_on_sort_key(left_obj, right_obj, my_sort_key, my_sort_type)
561
+ left_value = left_obj[my_sort_key]
562
+ right_value = right_obj[my_sort_key]
563
+
564
+ if left_value.nil?
565
+ 1
566
+ elsif right_value.nil?
567
+ -1
568
+ # hardcoded type check needed for speed
569
+ elsif left_value.is_a?(Time) && right_value.is_a?(Time)
570
+ left_value <=> right_value
571
+ else
572
+ if my_sort_type == "numeric"
573
+ (left_value.to_i rescue 0) <=> (right_value.to_i rescue 0)
574
+ else
575
+ left_value.to_s.downcase <=> right_value.to_s.downcase
576
+ end
577
+ end
578
+ end
579
+
580
+ def converted_sort_type(attribute)
581
+ read_attribute(attribute) == 1 ? "numeric" : "alphaNumeric"
582
+ end
583
+
584
+ def converted_sort_key(attribute)
585
+ key = read_attribute(attribute)
586
+ case key
587
+ when "validUntil"
588
+ "valid_until"
589
+ when "validFrom"
590
+ "valid_from"
591
+ when "lastChanged"
592
+ "last_changed"
593
+ when "contentType"
594
+ "content_type"
595
+ else
596
+ key
597
+ end
598
+ end
599
+
600
+ class << self
601
+ private
602
+
603
+ def try_type
604
+ result = yield
605
+ result if subclass_of_obj(result)
606
+ rescue NameError
607
+ nil
608
+ end
609
+
610
+ def subclass_of_obj(klass)
611
+ if klass == Obj
612
+ true
613
+ else
614
+ klass.superclass && subclass_of_obj(klass.superclass)
615
+ end
616
+ end
617
+
618
+ end
619
+ end
620
+
621
+ end
622
+
@@ -0,0 +1,60 @@
1
+ module RailsConnector
2
+
3
+ module ObjBody
4
+ # Returns the body (main content) of the Obj for non-binary Objs.
5
+ # Returns nil for binary Objs.
6
+ def body
7
+ if binary?
8
+ nil
9
+ else
10
+ StringTagging.tag_as_html(read_attribute(:blob), self)
11
+ end
12
+ end
13
+
14
+ # for binary Objs body_length equals the file size
15
+ # for non-binary Objs body_length equals the number of characters in the body (main content)
16
+ def body_length
17
+ if binary?
18
+ blob = find_blob
19
+ blob ? blob.length : 0
20
+ else
21
+ (body || "").length
22
+ end
23
+ end
24
+
25
+ # returns an URL to retrieve the Obj's body for binary Objs.
26
+ # returns nil for non-binary Objs.
27
+ def body_data_url
28
+ if binary?
29
+ blob = find_blob
30
+ blob.url if blob
31
+ end
32
+ end
33
+
34
+ def body_data_path # :nodoc:
35
+ # not needed/supported when using cloud connector.
36
+ nil
37
+ end
38
+
39
+ # returns the content type of the Obj's body for binary Objs.
40
+ # returns nil for non-binary Objs.
41
+ def body_content_type
42
+ if binary?
43
+ blob = find_blob
44
+ if blob
45
+ blob.content_type
46
+ else
47
+ "application/octet-stream"
48
+ end
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def find_blob
55
+ blob_spec = read_attribute(:blob)
56
+ Blob.find(blob_spec["id"], :context => path) if blob_spec
57
+ end
58
+ end
59
+
60
+ end # module RailsConnector
@@ -0,0 +1,35 @@
1
+ #:enddoc:
2
+ module RailsConnector
3
+
4
+ class ObjClass < CmsBaseModel
5
+ def self.by_name(name)
6
+ obj_class_cache[name]
7
+ end
8
+
9
+ def self.reset_cache
10
+ @obj_class_cache = nil
11
+ end
12
+
13
+ def name
14
+ obj_class_name
15
+ end
16
+
17
+ def has_attribute?(name)
18
+ @custom_attribute_names ||= custom_attributes.map(&:name)
19
+ @custom_attribute_names.include?(name.to_s)
20
+ end
21
+
22
+ module ClassMethods
23
+ private
24
+
25
+ def obj_class_cache
26
+ @obj_class_cache ||= find(:all).each_with_object({}) do |objclass, map|
27
+ map[objclass.name] = objclass
28
+ end
29
+ end
30
+ end
31
+
32
+ extend ClassMethods
33
+ end
34
+
35
+ end