infopark_fiona7 1.1.0.0.10 → 1.2.0.0.0

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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/fiona7_ui.js +96 -50
  3. data/app/assets/javascripts/scrivito_patches/models/blob.js +21 -0
  4. data/app/assets/javascripts/scrivito_patches/models/obj.js +1 -1
  5. data/app/controllers/fiona7/release_controller.rb +6 -2
  6. data/app/controllers/fiona7/sessions_controller.rb +3 -0
  7. data/app/controllers/fiona7/workflow_controller.rb +46 -0
  8. data/app/helpers/fiona7_login_helper.rb +16 -0
  9. data/app/helpers/fiona7_override_helper.rb +1 -1
  10. data/config/delayed_routes.rb +1 -0
  11. data/config/precedence_routes.rb +92 -0
  12. data/infopark_fiona7.gemspec +2 -2
  13. data/lib/fiona7/blob_id_generator.rb +13 -0
  14. data/lib/fiona7/builder/indirect_blob_builder.rb +71 -0
  15. data/lib/fiona7/builder/lazy_blob_copier.rb +207 -0
  16. data/lib/fiona7/builder/obj_builder.rb +29 -50
  17. data/lib/fiona7/builder/obj_class_builder.rb +20 -0
  18. data/lib/fiona7/controllers/rest_api/blob_controller.rb +19 -0
  19. data/lib/fiona7/controllers/rest_api/obj_controller.rb +8 -4
  20. data/lib/fiona7/controllers/rest_api/workspace_controller.rb +2 -1
  21. data/lib/fiona7/engine.rb +56 -2
  22. data/lib/fiona7/json/obj_decorator.rb +4 -1
  23. data/lib/fiona7/link_converter/fiona_to_scrivito.rb +3 -1
  24. data/lib/fiona7/link_converter/scrivito_to_fiona.rb +12 -1
  25. data/lib/fiona7/mode_switch/cms_routes/scrivito_sdk.rb +1 -71
  26. data/lib/fiona7/mode_switch/cms_routes/scrivito_sdk_slave.rb +1 -71
  27. data/lib/fiona7/recursive_object_finder.rb +32 -8
  28. data/lib/fiona7/routers/rest_api.rb +6 -7
  29. data/lib/fiona7/scrivito_patches/attribute_content.rb +1 -1
  30. data/lib/fiona7/scrivito_patches/attribute_serializer.rb +22 -1
  31. data/lib/fiona7/scrivito_patches/basic_obj.rb +27 -5
  32. data/lib/fiona7/scrivito_patches/cms_backend.rb +3 -22
  33. data/lib/fiona7/scrivito_patches/cms_rest_api.rb +2 -1
  34. data/lib/fiona7/scrivito_patches/cms_routing.rb +2 -2
  35. data/lib/fiona7/scrivito_patches/model_library.rb +3 -3
  36. data/lib/fiona7/scrivito_patches/page_config.rb +21 -1
  37. data/lib/fiona7/scrivito_patches/preset_routes.rb +15 -2
  38. data/lib/fiona7/scrivito_patches/routing_extensions.rb +33 -20
  39. data/lib/fiona7/scrivito_patches/workspace.rb +3 -1
  40. data/lib/fiona7/super_object_finder.rb +63 -0
  41. data/lib/fiona7/type_register.rb +35 -9
  42. data/lib/fiona7/verity_search_engine.rb +1 -1
  43. data/lib/fiona7/version.rb +1 -1
  44. metadata +13 -7
  45. data/config/routes.rb +0 -13
@@ -17,7 +17,7 @@ module Scrivito
17
17
 
18
18
  # support shadow classes
19
19
  def description_for_editor
20
- to_s
20
+ to_s.titleize
21
21
  end
22
22
 
23
23
  def register_attribute_definitions(obj_class)
@@ -5,12 +5,33 @@ module Scrivito
5
5
  def serialize_binary_value(attribute_value, attribute_definition)
6
6
  case attribute_value
7
7
  when File then attribute_value
8
- when FutureBinary then attribute_value.file_to_upload
8
+ when FutureBinary then special_handling_of_future_binary(attribute_value, attribute_definition)
9
9
  when UploadedBinary then attribute_value.params
10
10
  else
11
11
  raise_validation_error(attribute_definition.name,
12
12
  'an instance of File, Scrivito::UploadedBinary or nil', attribute_value)
13
13
  end
14
14
  end
15
+
16
+ protected
17
+ def special_handling_of_future_binary(future_binary, attribute_definition)
18
+ if future_binary.file_to_upload
19
+ # The easy case: just upload the file directly, it works
20
+ future_binary.file_to_upload
21
+ elsif future_binary.id_to_copy
22
+ # The hard case: magic blob copy/rename needs to happen
23
+ {
24
+ obj_id: obj_id,
25
+ attr_name: attribute_definition.name.to_s,
26
+ id_to_copy: future_binary.id_to_copy,
27
+ filename: future_binary.filename,
28
+ content_type: future_binary.content_type
29
+ }
30
+ else
31
+ # The unknown case: ???
32
+ Rails.logger.error("Unsure how to proceed with an upload of #{future_binary.inspect}")
33
+ nil
34
+ end
35
+ end
15
36
  end
16
37
  end
@@ -21,11 +21,6 @@ module Scrivito
21
21
  "Already modified in workspace #{target_workspace.id}"
22
22
  end
23
23
 
24
- def copy_binaries(attributes)
25
- # TODO: what to do?
26
- attributes
27
- end
28
-
29
24
  # Originally this method checks for conflicts
30
25
  # which are impossible here, hence the method is stubbed out
31
26
  def publishable?
@@ -45,6 +40,33 @@ module Scrivito
45
40
  end
46
41
  end
47
42
 
43
+ # Original implementation mishandles attribute => [type, value]
44
+ def copy_binaries(attributes)
45
+ attribute_defintions = self.class.find_attribute_definitions(obj_class)
46
+ destination_obj_id = attributes.fetch(:_id)
47
+
48
+ Hash[attributes.map do |name, value|
49
+ # Here is the change
50
+ if value && attribute_defintions[name].try(:type) == 'binary' && (binary = self[name])
51
+ [name, ['binary', copy_binary(destination_obj_id, binary)]]
52
+ else
53
+ [name, value]
54
+ end
55
+ end]
56
+ end
57
+
58
+ # Original implmentation uses the blob copy API
59
+ # This is completely unneccessary, as the required
60
+ # logic is already possible implemented similar to FutureBinary
61
+ def copy_binary(destination_obj_id, binary)
62
+ {
63
+ obj_id: destination_obj_id,
64
+ id_to_copy: binary.id,
65
+ filename: binary.filename,
66
+ content_type: binary.content_type
67
+ }.stringify_keys
68
+ end
69
+
48
70
  def fiona_obj
49
71
  @fiona_obj ||= ::RailsConnector::BasicObj.find(self.id)
50
72
  end
@@ -1,11 +1,11 @@
1
1
  require 'scrivito/cms_backend'
2
2
 
3
3
  module Scrivito
4
- class CmsBackend
4
+ module CmsBackend
5
5
  # prevent the use of local URLs (localhost:7104) from cache
6
6
  # when running under a server
7
- def find_blob_data_from_cache(id, access, verb, transformation_definition)
8
- cache_key = blob_data_cache_key(normalize_blob_id(id), access, verb, transformation_definition)
7
+ def self.find_blob_data_from_cache(id, access, verb, options)
8
+ cache_key = blob_data_cache_key(normalize_blob_id(id), access, verb, options)
9
9
  data = CmsDataCache.cache.read(cache_key)
10
10
 
11
11
  if !data.nil? && Fiona7::Middleware::ServerDetectionMiddleware.server_detected?
@@ -20,24 +20,5 @@ module Scrivito
20
20
  data
21
21
  end
22
22
  end
23
-
24
- # prevent real get requests since we run everything locally
25
- # def request_blob_metadata_from_s3(url)
26
- # @query_counter += 1
27
-
28
- # blob_id = /\/_b\/([0-9]+)/.match(url)[1]
29
-
30
- # raise ScrivitoError, "Unexpected 's3' url: #{url}" unless blob_id.present?
31
-
32
- # rest_api_meta_data = Fiona7::Controllers::RestAPI::BlobController.new.metadata(blob_id)
33
-
34
- # meta_data = {}
35
- # meta_data[:content_type] = rest_api_meta_data['meta_data']['content_type'].last
36
- # meta_data[:content_length] = rest_api_meta_data['meta_data']['content_length'].last
37
- # meta_data[:cache_control] = 'no-transform,public,max-age=300,s-maxage=900'
38
-
39
- # meta_data
40
- # end
41
-
42
23
  end
43
24
  end
@@ -1,4 +1,5 @@
1
1
  require 'scrivito/cms_rest_api.rb'
2
+ require 'fiona7/blob_id_generator'
2
3
 
3
4
  module Scrivito
4
5
  class CmsRestApi
@@ -18,7 +19,7 @@ module Scrivito
18
19
  raise Scrivito::ScrivitoError.new("File extension of uploaded file cannot be identified", 422) if ext.nil?
19
20
 
20
21
  upload = Fiona7::WriteObj.upload(file, ext, {name: name, parent: parent, obj_class: obj_class}).tap(&:release!)
21
- encoded_id = '%032d' % upload.id
22
+ encoded_id = Fiona7::BlobIdGenerator.new(upload.id, upload.last_changed).call
22
23
  {'id' => encoded_id}
23
24
  end
24
25
 
@@ -53,7 +53,7 @@ module Scrivito
53
53
  # Use fiona connector permalinks in legacy mode
54
54
  def path_or_url_for_objs(obj, path_or_url, options)
55
55
  permalink = obj.permalink
56
- if permalink && route_defined?(:permalink)
56
+ if permalink && route_defined?(:permalink) && permalink.split('/').first != 'scrivito'
57
57
 
58
58
  if Fiona7.mode == :legacy
59
59
  context.public_send("cms_permalink_#{path_or_url}", options.merge(:permalink => permalink))
@@ -64,7 +64,7 @@ module Scrivito
64
64
  use_route(:homepage, path_or_url, options)
65
65
  elsif obj.binary?
66
66
  # use fiona connector routes when possible
67
- if Fiona7.mode == :legacy
67
+ if Fiona7.mode == :legacy && self.image_options.blank?
68
68
  if binary = obj.binary
69
69
  params = {
70
70
  id: obj.id,
@@ -10,10 +10,10 @@ module Scrivito
10
10
  return model_class if model_class.ancestors.include?(base_class)
11
11
 
12
12
  if Fiona7.mode == :legacy && model_class.respond_to?(:shadow_class)
13
- model_class = model_class.shadow_class
14
- model_class if model_class.ancestors.include?(base_class)
13
+ model_class = model_class.shadow_class rescue nil
14
+ model_class if model_class && model_class.ancestors.include?(base_class)
15
15
  end
16
- rescue NameError
16
+ rescue LoadError
17
17
  end
18
18
  end
19
19
  end
@@ -5,7 +5,7 @@ module Scrivito
5
5
  def current_page_config
6
6
  # TODO: add permission info
7
7
  return {} unless obj
8
- {
8
+ config = {
9
9
  id: obj.id,
10
10
  path: obj.path,
11
11
  obj_class: obj.obj_class,
@@ -16,6 +16,26 @@ module Scrivito
16
16
  parent_path: obj.parent_path,
17
17
  restriction_messages: editor.restriction_messages_for(obj),
18
18
  }
19
+ if ::Fiona7.workflows_enabled?
20
+ fiona_obj = obj.fiona_obj
21
+ if fiona_obj.workflow.present?
22
+ # without a workflow or with workflows disabled this will be falsy
23
+ config[:workflow] = true
24
+ # this just the returns the currently set editor
25
+ config[:editor] = fiona_obj.editor
26
+ # this is the most important bit: when to disable the editing
27
+ # altough simple this implementation handles the following cases:
28
+ # 1. someone outside the workflow visits the page
29
+ # 2. a current editor within the workflow visits the page
30
+ # 3. someone within the workflow visits the page
31
+ config[:editing_disabled] = fiona_obj.editor != editor.id
32
+ # this contains validActionKeys from cms
33
+ # TODO: this should be implemented in reactor
34
+ config[:buttons] = fiona_obj.send(:crul_obj).valid_actions
35
+ end
36
+ end
37
+
38
+ config
19
39
  end
20
40
  end
21
41
  end
@@ -1,6 +1,18 @@
1
+ require "scrivito/preset_routes"
2
+
1
3
  module Scrivito
2
4
  module PresetRoutes
3
- def self.install_into(route_set)
5
+ mattr_accessor :delayed
6
+ self.delayed ||= {}
7
+
8
+ def self.install_delayed(route_set=nil)
9
+ delayed.each do |route, delayed_lambda|
10
+ delayed_lambda.call(route_set)
11
+ end
12
+ end
13
+
14
+ def self.install_into(route_set, do_the_install=false)
15
+ return unless do_the_install
4
16
  return if Scrivito::Configuration.scrivito_route_enabled?
5
17
 
6
18
  Scrivito::Configuration.with_scrivito_route_enabled do
@@ -22,7 +34,8 @@ module Scrivito
22
34
  end
23
35
  end
24
36
 
25
- def self.install_slave_into(route_set)
37
+ def self.install_slave_into(route_set, do_the_install=false)
38
+ return unless do_the_install
26
39
  return if Scrivito::Configuration.scrivito_route_enabled?
27
40
 
28
41
  Scrivito::Configuration.with_scrivito_route_enabled do
@@ -1,3 +1,5 @@
1
+ require "scrivito/routing_extensions"
2
+
1
3
  module Scrivito
2
4
 
3
5
  module RoutingExtensions
@@ -6,32 +8,43 @@ module RoutingExtensions
6
8
  assert_scrivito_route_enabled
7
9
  # @set is a ActionDispatch::Routing::RouteSet
8
10
  # see: http://git.io/v4UYF and http://git.io/v4UOI
9
- route_set = @set
11
+ original_route_set = @set
10
12
 
11
13
  route_name = using.to_sym
12
14
 
13
- route = Route.register(route_set, route_name)
14
-
15
- options = {
16
- to: 'scrivito/cms_dispatch#index',
17
- via: via,
18
- format: format,
19
- as: route.helper_name,
20
- }
21
-
22
- # removed fixed length constraint on ids
23
- options[:constraints] = {id: /[0-9]{4,}/} if route_name == :slug_id
24
-
25
- begin
26
- match(path, options)
27
- rescue ArgumentError => error
28
- if error.message.include?(route.helper_name)
29
- raise ScrivitoError,
15
+ # route_set is actually an optional parameter
16
+ # and should only be used in test scenarios
17
+ delayed = proc do |route_set|
18
+ route_set ||= original_route_set
19
+ route = Route.register(route_set, route_name)
20
+
21
+ options = {
22
+ to: 'scrivito/cms_dispatch#index',
23
+ via: via,
24
+ format: format,
25
+ as: route.helper_name,
26
+ }
27
+
28
+ # removed fixed length constraint on ids
29
+ options[:constraints] = {id: /[0-9]{4,}/} if route_name == :slug_id
30
+
31
+ begin
32
+ match(path, options)
33
+ rescue ArgumentError => error
34
+ if error.message.include?(route.helper_name)
35
+ raise ScrivitoError,
30
36
  %(You have already defined a Scrivito route with the name "#{route_name}".)
31
- else
32
- raise error
37
+ else
38
+ raise error
39
+ end
33
40
  end
34
41
  end
42
+
43
+ if route_name == :permalink && false
44
+ PresetRoutes.delayed[route_name] = delayed
45
+ else
46
+ delayed.call(original_route_set)
47
+ end
35
48
  end
36
49
 
37
50
  private
@@ -12,7 +12,7 @@ module Scrivito
12
12
  false
13
13
  end
14
14
 
15
- # fix silly assumptions
15
+ # properly handle the only two workspaces
16
16
  def self.use(id_or_title)
17
17
  self.current = if id_or_title =~ /(published|rtc)/
18
18
  find(id_or_title)
@@ -20,6 +20,8 @@ module Scrivito
20
20
  find_by_title(id_or_title) or
21
21
  raise ResourceNotFound, "Could not find #{self} with title #{id_or_title}"
22
22
  end
23
+ rescue ResourceNotFound
24
+ raise ResourceNotFound, %{Could not find #{self} with title or ID "#{id_or_title}"}
23
25
  end
24
26
  end
25
27
  end
@@ -0,0 +1,63 @@
1
+ # This class allows to access objects linking to
2
+ # given object, i.e. super objects
3
+ #
4
+ # It provides two modes of searching: preview nad live
5
+ module Fiona7
6
+ class SuperObjectFinder
7
+ def initialize(model=::Fiona7::WriteObj, connection=nil, instance_name=RailsConnector::CmsBaseModel.instance_name)
8
+ @instance_name = instance_name
9
+ @conn = connection || model.connection
10
+ @model = model
11
+ end
12
+
13
+ def find(type=:preview, obj)
14
+ case type
15
+ when :preview
16
+ preview(obj)
17
+ when :live
18
+ live(obj)
19
+ else
20
+ raise ArgumentError, "Uknown type #{type.inspect} expected :preview or :ive"
21
+ end
22
+ end
23
+
24
+ # This method returns the results of search for objects
25
+ # in preview mode.
26
+ #
27
+ # This means that all objects that are reachable in preview
28
+ # are returned (unreleased, commited etc.)
29
+ def preview(obj)
30
+ query = "SELECT #{objects_table}.object_id FROM #{links_table} INNER JOIN #{objects_table} ON #{links_table}.content_id = #{objects_table}.edited_content_id WHERE #{links_table}.sub_object_id = #{obj.obj_id.to_i} #{self.obj_class_condition} UNION SELECT #{objects_table}.object_id FROM #{links_table} INNER JOIN #{objects_table} ON #{links_table}.content_id = #{objects_table}.committed_cont_id WHERE #{links_table}.sub_object_id = #{obj.obj_id.to_i} #{self.obj_class_condition} UNION SELECT #{objects_table}.object_id FROM #{links_table} INNER JOIN #{objects_table} ON #{links_table}.content_id = #{objects_table}.released_cont_id WHERE #{links_table}.sub_object_id = #{obj.obj_id.to_i} AND #{objects_table}.committed_cont_id IS NULL AND #{objects_table}.edited_content_id IS NULL #{self.obj_class_condition}"
31
+ ids = self.sql_query(query).to_a.flatten
32
+ @model.find(ids).select(&:exportable?)
33
+ end
34
+
35
+ # This method returns the results of search for objects
36
+ # in live mode.
37
+ #
38
+ # This means that only the objects that are reachable in
39
+ # live are returned, i.e. avaiable for outside world
40
+ def live(obj)
41
+ query = "SELECT #{objects_table}.object_id FROM #{links_table} INNER JOIN #{objects_table} ON #{links_table}.content_id = #{objects_table}.released_cont_id WHERE #{links_table}.sub_object_id = #{obj.obj_id.to_i} #{self.obj_class_condition}"
42
+ ids = self.sql_query(query).to_a.flatten
43
+ @model.find(ids).select(&:exportable?)
44
+ end
45
+
46
+ protected
47
+ def links_table
48
+ "#{@instance_name}_links"
49
+ end
50
+
51
+ def obj_class_condition
52
+ ""
53
+ end
54
+
55
+ def objects_table
56
+ "#{@instance_name}_objects"
57
+ end
58
+
59
+ def sql_query(query, *args)
60
+ @conn.execute(query, *args)
61
+ end
62
+ end
63
+ end
@@ -8,6 +8,9 @@ require "fiona7/attribute_name_mangler"
8
8
 
9
9
 
10
10
  module Fiona7
11
+ class TypeSystemError < ::ArgumentError
12
+ end
13
+
11
14
  class TypeRegister
12
15
  include Singleton
13
16
 
@@ -17,24 +20,35 @@ module Fiona7
17
20
  referencelist: :linklist,
18
21
  widgetlist: :linklist,
19
22
  binary: :linklist,
23
+ number: :string,
20
24
  stringlist: :text
21
25
  }.freeze
22
26
 
23
27
  class TypeDefinition
24
28
  class Attribute < Struct.new(:name, :type, :real_name, :real_type, :values)
25
- class Core < Struct.new(:name, :type)
26
- end
27
-
28
29
  def eql?(other)
29
30
  other.kind_of?(self.class) &&
30
31
  self.name.eql?(other.name)
31
- #Core.new(self.name, self.type).eql?(Core.new(other.name, other.type))
32
32
  end
33
33
 
34
34
  def hash
35
35
  return self.name.hash
36
- #Core.new(self.name, self.type).hash
37
36
  end
37
+
38
+ def values_set
39
+ return @values_set if defined?(@values_set)
40
+
41
+ if self.values.present?
42
+ @values_set = self.values.to_set
43
+ else
44
+ @values_set = Set[]
45
+ end
46
+
47
+ return @values_set
48
+ end
49
+
50
+ protected
51
+ attr_writer :name, :type, :real_name, :real_type, :values
38
52
  end
39
53
 
40
54
  attr_accessor :name
@@ -143,7 +157,6 @@ module Fiona7
143
157
  end
144
158
 
145
159
  def ad_hoc_synchronize(type_definition)
146
- #puts "Ad hoc synchronize of #{type_definition.name}"
147
160
  obj_class = type_definition.name
148
161
 
149
162
  existing_definition = self.usr_defs[obj_class]
@@ -157,7 +170,7 @@ module Fiona7
157
170
  self.cms_def_present?(obj_class) &&
158
171
  defs_compatible?(self.cms_defs[obj_class], type_definition)
159
172
 
160
- puts "Ad hoc synchronization required of #{type_definition.name}"
173
+ Rails.logger.warn "Ad hoc synchronization required of #{type_definition.name}"
161
174
 
162
175
  self.synchronize(obj_class)
163
176
  self.load(obj_class)
@@ -196,13 +209,25 @@ module Fiona7
196
209
  # has a proper definition
197
210
  true
198
211
  else
199
- #raise "Attribute types for #{attr_name} incompatible: CMS uses #{cms_type} but the application provided #{usr_type}"
200
- puts "Attribute types for #{attr_name} incompatible: CMS uses #{cms_type} but the application provided #{usr_type}"
212
+ message = "Attribute types for #{attr_name} incompatible: CMS uses #{cms_type} but the application provided #{usr_type}"
213
+ if ::Fiona7.config.dont_yell_at_me_for_abusing_attributes
214
+ Rails.logger.error("TYPE SYNCHRONIZATION: " + message)
215
+ else
216
+ raise TypeSystemError, message
217
+ end
218
+
201
219
  false
202
220
  end
203
221
  end
204
222
  end
205
223
 
224
+ def value_lists_compatabile?(usr_attr, cms_attr)
225
+ return true unless [:multienum, :enum].include?(usr_attr.type)
226
+ return true unless [:multienum, :enum].include?(cms_attr.type)
227
+
228
+ return cms_attr.values_set.superset?(usr_attr.values_set)
229
+ end
230
+
206
231
  def defs_compatible?(cms_def, usr_def)
207
232
  cms_attr_map = {}
208
233
  cms_def.attrs.each do |attr|
@@ -212,6 +237,7 @@ module Fiona7
212
237
  usr_def.attrs.each do |attr|
213
238
  return false if !cms_attr_map[attr.name]
214
239
  return false if !type_compatible?(attr.name, cms_attr_map[attr.name].type, attr.type)
240
+ return false if !value_lists_compatabile?(attr, cms_attr_map[attr.name])
215
241
  end
216
242
 
217
243
  return true