infopark_cloud_connector 6.8.0.beta.200.621.4c8e1b0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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