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.
- data/README +71 -0
- data/lib/infopark_cloud_connector.rb +19 -0
- data/lib/rails_connector/attribute.rb +35 -0
- data/lib/rails_connector/blob.rb +66 -0
- data/lib/rails_connector/cache.rb +35 -0
- data/lib/rails_connector/cache_middleware.rb +17 -0
- data/lib/rails_connector/chain.rb +177 -0
- data/lib/rails_connector/cms_base_model.rb +61 -0
- data/lib/rails_connector/content_cache.rb +24 -0
- data/lib/rails_connector/controller_runtime.rb +35 -0
- data/lib/rails_connector/couch_blob.rb +44 -0
- data/lib/rails_connector/couchdb_views_source_path.rb +7 -0
- data/lib/rails_connector/date_attribute.rb +28 -0
- data/lib/rails_connector/default_search_request.rb +6 -0
- data/lib/rails_connector/elasticsearch_request.rb +78 -0
- data/lib/rails_connector/errors.rb +9 -0
- data/lib/rails_connector/link.rb +135 -0
- data/lib/rails_connector/log_subscriber.rb +29 -0
- data/lib/rails_connector/named_link.rb +72 -0
- data/lib/rails_connector/obj.rb +622 -0
- data/lib/rails_connector/obj_body.rb +60 -0
- data/lib/rails_connector/obj_class.rb +35 -0
- data/lib/rails_connector/path_conversion.rb +17 -0
- data/lib/rails_connector/permission.rb +39 -0
- data/lib/rails_connector/rack_middlewares.rb +6 -0
- data/lib/rails_connector/s3_blob.rb +67 -0
- data/lib/rails_connector/version.rb +39 -0
- data/lib/rails_connector/workspace.rb +139 -0
- data/lib/rails_connector/workspace_label.rb +10 -0
- data/lib/rails_connector/workspace_selection_middleware.rb +45 -0
- metadata +169 -0
@@ -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
|