infopark_cloud_connector 6.9.4 → 6.9.5

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 (61) hide show
  1. checksums.yaml +15 -0
  2. data/README +1 -3
  3. data/app/controllers/cms_controller.rb +7 -0
  4. data/app/controllers/rails_connector/default_cms_controller.rb +43 -0
  5. data/app/controllers/rails_connector/objs_controller.rb +29 -0
  6. data/app/controllers/rails_connector/widget_renderer.rb +1 -1
  7. data/app/controllers/rails_connector/workspaces_controller.rb +4 -0
  8. data/app/helpers/cms_helper.rb +7 -0
  9. data/app/helpers/cms_routing_helper.rb +7 -0
  10. data/app/helpers/rails_connector/cms_asset_helper.rb +24 -17
  11. data/app/helpers/rails_connector/cms_tag_helper.rb +9 -6
  12. data/app/helpers/rails_connector/default_cms_helper.rb +23 -0
  13. data/app/helpers/rails_connector/default_cms_routing_helper.rb +101 -0
  14. data/app/helpers/rails_connector/display_helper.rb +4 -30
  15. data/app/helpers/rails_connector/editing_helper.rb +3 -0
  16. data/app/helpers/rails_connector/layout_helper.rb +29 -0
  17. data/app/helpers/rails_connector/table_of_contents_helper.rb +22 -0
  18. data/app/models/named_link.rb +2 -0
  19. data/app/views/cms/_index.html.erb +7 -0
  20. data/app/views/cms/index.html.erb +1 -0
  21. data/app/views/errors/403_forbidden.html.erb +3 -0
  22. data/app/views/errors/410_gone.html.erb +7 -0
  23. data/app/views/rails_connector/_editing_javascript.html.erb +2 -0
  24. data/config/ca-bundle.crt +1 -1
  25. data/config/cms_routes.rb +14 -0
  26. data/config/locales/de.rails_connector.errors.yml +11 -0
  27. data/config/locales/de.rails_connector.lib.yml +6 -0
  28. data/config/locales/de.rails_connector.views.yml +9 -0
  29. data/config/locales/en.rails_connector.errors.yml +10 -0
  30. data/config/locales/en.rails_connector.lib.yml +6 -0
  31. data/config/locales/en.rails_connector.views.yml +9 -0
  32. data/config/routes.rb +4 -0
  33. data/lib/assets/javascripts/infopark_editing.js +689 -285
  34. data/lib/assets/stylesheets/infopark_editing.css +17 -0
  35. data/lib/infopark_cloud_connector.rb +22 -0
  36. data/lib/obj.rb +3 -0
  37. data/lib/rails_connector/attribute_content.rb +190 -0
  38. data/lib/rails_connector/authenticable.rb +30 -0
  39. data/lib/rails_connector/basic_obj.rb +25 -139
  40. data/lib/rails_connector/basic_widget.rb +35 -0
  41. data/lib/rails_connector/cms_accessible.rb +114 -0
  42. data/lib/rails_connector/cms_cache_storage.rb +1 -1
  43. data/lib/rails_connector/cms_dispatch_controller.rb +46 -0
  44. data/lib/rails_connector/cms_env.rb +68 -0
  45. data/lib/rails_connector/cms_test_request.rb +23 -0
  46. data/lib/rails_connector/configuration.rb +3 -2
  47. data/lib/rails_connector/core_extensions.rb +1 -0
  48. data/lib/rails_connector/core_extensions/time.rb +18 -0
  49. data/lib/rails_connector/date_attribute.rb +1 -17
  50. data/lib/rails_connector/engine.rb +57 -0
  51. data/lib/rails_connector/html_string.rb +19 -0
  52. data/lib/rails_connector/link.rb +102 -17
  53. data/lib/rails_connector/link_resolvable.rb +9 -0
  54. data/lib/rails_connector/migrations/migrator.rb +8 -4
  55. data/lib/rails_connector/migrations/workspace_lock.rb +3 -2
  56. data/lib/rails_connector/named_link.rb +1 -1
  57. data/lib/rails_connector/obj_data_from_service.rb +18 -0
  58. data/lib/rails_connector/string_tagging.rb +29 -0
  59. data/lib/rails_connector/type_computer.rb +30 -0
  60. data/lib/widget.rb +3 -0
  61. metadata +103 -18
@@ -368,6 +368,23 @@ html.ip_bottombar_on {
368
368
  color: #eee;
369
369
  text-shadow: 0 1px 0 #333;
370
370
  }
371
+ .ip_menu_box .ip_menu_item.disabled span:hover,
372
+ .ip_menu_box .ip_menu_item.disabled a:hover {
373
+ color: #fff;
374
+ cursor: help;
375
+ background-color: transparent;
376
+ background-image: none;
377
+ background-repeat: no-repeat;
378
+ filter: none;
379
+ color: #696969;
380
+ }
381
+ .ip_menu_box .ip_menu_item.disabled span,
382
+ .ip_menu_box .ip_menu_item.disabled a,
383
+ .ip_menu_box .ip_menu_item.disabled span .ip_icon,
384
+ .ip_menu_box .ip_menu_item.disabled a .ip_icon {
385
+ color: #696969;
386
+ cursor: help;
387
+ }
371
388
  .ip_topbar .ip_button_bar .ip_logo {
372
389
  display: block;
373
390
  padding: 0;
@@ -1,3 +1,24 @@
1
+ # @api public
2
+ module ::RailsConnector
3
+ PLATFORM_CLOUD = :cloud.freeze
4
+ PLATFORM_FIONA = :fiona.freeze
5
+
6
+ # return either <tt>:fiona</tt> or <tt>:cloud</tt> depending on the app's configuration.
7
+ # @return [Symbol]
8
+ def self.platform
9
+ PLATFORM_CLOUD
10
+ end
11
+
12
+ def self.platform_cloud?
13
+ true
14
+ end
15
+
16
+ def self.platform_fiona?
17
+ false
18
+ end
19
+ end
20
+
21
+ require 'rails_connector/core_extensions'
1
22
  require 'rails_connector/rack_middlewares'
2
23
  require "rails_connector/errors"
3
24
 
@@ -17,4 +38,5 @@ module RailsConnector
17
38
  autoload_all_sources
18
39
  end
19
40
 
41
+ require "rails_connector/engine" if defined?(Rails)
20
42
  require "rails_connector/cloud_engine" if defined?(Rails)
@@ -0,0 +1,3 @@
1
+ # empty implementation for Obj
2
+ # only unsed in case the app does not define Obj itself
3
+ ::Obj = Class.new(RailsConnector::BasicObj)
@@ -0,0 +1,190 @@
1
+ module RailsConnector
2
+
3
+ module AttributeContent
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ private
8
+ attr_accessor :data_from_cms
9
+ end
10
+
11
+ def respond_to?(method_id, include_private=false)
12
+ if has_attribute?(method_id)
13
+ true
14
+ else
15
+ super
16
+ end
17
+ end
18
+
19
+ def method_missing(method_name, *args)
20
+ if has_attribute?(method_name)
21
+ read_attribute(method_name.to_s)
22
+ else
23
+ super
24
+ end
25
+ end
26
+
27
+ def widgets(attribute_name)
28
+ unless (type_of_attribute(attribute_name) == 'widget')
29
+ raise "Not a widget field: #{attribute_name}."
30
+ end
31
+
32
+ widgets = read_attribute(attribute_name.to_s, false)
33
+
34
+ return [] unless widgets.present?
35
+
36
+ output_objs = []
37
+ (widgets['layout'] || []).each do |widget_hash|
38
+ begin
39
+ widget_obj = self.class.find(widget_hash['widget'])
40
+ rescue RailsConnector::ResourceNotFound => e
41
+ end
42
+ if widget_obj.present? && widget_obj.path.start_with?("/_widgets/#{id}/")
43
+ output_objs << widget_obj
44
+ end
45
+ end
46
+
47
+ output_objs
48
+ end
49
+
50
+ def read_attribute(attribute_name, skip_widgets = true)
51
+ if skip_widgets && (type_of_attribute(attribute_name) == 'widget')
52
+ raise "Field #{attribute_name} not (yet) available, since it's a widget"
53
+ end
54
+ @attribute_cache.fetch(attribute_name) do
55
+ (raw_value, attribute_type) = data_from_cms.value_and_type_of(attribute_name)
56
+ @attribute_cache[attribute_name] =
57
+ prepare_attribute_value(raw_value, attribute_type)
58
+ end
59
+ end
60
+
61
+ def has_attribute?(name)
62
+ data_from_cms.has_custom_attribute?(name.to_s)
63
+ end
64
+
65
+ # @return [String]
66
+ def type_of_attribute(field_name)
67
+ data_from_cms.type_of(field_name.to_s)
68
+ end
69
+
70
+ # Returns the value of an internal or external attribute specified by its name.
71
+ # Passing an invalid key will not raise an error, but return +nil+.
72
+ # @api public
73
+ def [](key)
74
+ key = key.to_s
75
+ has_attribute?(key) ? read_attribute(key) : nil
76
+ end
77
+
78
+ # Hook method to control which widget classes should be avaiable for this page.
79
+ # Override it to allow only certain classes or none.
80
+ # Must return either {NilClass}, or {Array}.
81
+ #
82
+ # If {NilClass} is returned, then all widget classes will be available for this page.
83
+ # By default {NilClass} is returned.
84
+ #
85
+ # If {Array} is returned, then it should include desired class names.
86
+ # Each class name must be either a {String} or a {Symbol}.
87
+ # Only this class names will be available for this page.
88
+ # Order of the class names will be preserved.
89
+ #
90
+ # @param [String] field_name Name of the widget field.
91
+ # @return [NilClass, Array<Symbol, String>]
92
+ # @api public
93
+ def valid_widget_classes_for(field_name)
94
+ end
95
+
96
+ private
97
+
98
+ def update_data(data)
99
+ self.data_from_cms = data
100
+ @attribute_cache = {}
101
+ end
102
+
103
+ def prepare_attribute_value(attribute_value, attribute_type)
104
+ case attribute_type
105
+ when "html"
106
+ StringTagging.tag_as_html(convert_links(attribute_value), self)
107
+ when "date"
108
+ DateAttribute.parse(attribute_value) if attribute_value
109
+ when "linklist"
110
+ build_links(attribute_value)
111
+ when "reference"
112
+ self.class.find([attribute_value]).first
113
+ when "referencelist"
114
+ self.class.find(attribute_value).compact
115
+ else
116
+ attribute_value
117
+ end
118
+ end
119
+
120
+ def convert_links(html)
121
+ if html
122
+ html.gsub(%r{<?\binternallink:(\d+)\b>?(['"]?)}) do
123
+ link, postfix = text_link_map[$1], $2
124
+ link ? convert_link(link, postfix) : missing_link_url(postfix)
125
+ end
126
+ end
127
+ end
128
+
129
+ def convert_link(link, postfix)
130
+ link.internal? ? convert_internal_link(link, postfix) : convert_external_link(link, postfix)
131
+ end
132
+
133
+ def convert_internal_link(link, postfix)
134
+ link.obj ? decorate_link_url(link.internal_url, link, postfix) : missing_link_url(postfix)
135
+ end
136
+
137
+ def convert_external_link(link, postfix)
138
+ decorate_link_url(link.external_url, link, postfix)
139
+ end
140
+
141
+ def decorate_link_url(url, link, postfix)
142
+ "#{url}#{link.query_and_fragment}#{postfix} #{link.html_attribute_snippet}"
143
+ end
144
+
145
+ def missing_link_url(postfix)
146
+ "#{CmsRoutingHelper::LINK_TO_UNREACHABLE}#{postfix}"
147
+ end
148
+
149
+ def text_link_map
150
+ @_text_link_map ||= text_links.each_with_object({}) { |link, map| map[link.id] = link }
151
+ end
152
+
153
+ def build_links(link_definitions)
154
+ if link_definitions.present?
155
+ link_definitions = link_definitions.map(&:with_indifferent_access)
156
+
157
+ object_ids = link_definitions.map { |link_data| link_data[:destination] }.compact.uniq
158
+ objects = object_ids.empty? ? [] : Obj.find(object_ids)
159
+ link_definitions.each_with_object([]) do |link_data, links|
160
+ obj = objects.detect { |o| o && o.id == link_data[:destination] }
161
+ link = Link.new(link_data.merge(obj: obj))
162
+ links << link if link.active?
163
+ end
164
+ else
165
+ []
166
+ end
167
+ end
168
+
169
+ module ClassMethods
170
+ # instantiate an Obj instance from obj_data.
171
+ # May result in an instance of a subclass of Obj according to STI rules.
172
+ #
173
+ # A CMS administrator can specify the <tt>obj_class</tt> for a given CMS object.
174
+ # In Rails, this could be either:
175
+ #
176
+ # * A valid and existing model name
177
+ # * A valid and non-existing model name
178
+ # * An invalid model name
179
+ #
180
+ # Rails' STI mechanism only considers the first case.
181
+ # In any other case, RailsConnector::Obj is used, except when explicitly asked
182
+ # for a model in the RailsConnector namespace (RailsConnector::Permission etc.)
183
+ def instantiate(obj_data)
184
+ obj_class = obj_data.value_of('_obj_class')
185
+ type_computer.compute_type(obj_class).new(obj_data)
186
+ end
187
+ end
188
+ end
189
+
190
+ end
@@ -0,0 +1,30 @@
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
+ define_method(method_name, InstanceMethods.method(method_name).to_proc)
9
+ end
10
+ end
11
+
12
+ mod.send(:helper_method, method_name)
13
+ end
14
+ end
15
+
16
+ module InstanceMethods
17
+ def self.logged_in?; false; end
18
+ def self.admin?; false; end
19
+ def self.current_user; nil; end
20
+ end
21
+
22
+ private
23
+
24
+ def self.instance_method_defined?(mod, method_name)
25
+ (
26
+ mod.instance_methods + mod.protected_instance_methods + mod.private_instance_methods
27
+ ).map(&:to_s).include?(method_name)
28
+ end
29
+ end
30
+ end
@@ -5,11 +5,21 @@ module RailsConnector
5
5
  # The CMS file class
6
6
  # @api public
7
7
  class BasicObj
8
+ WIDGET_POOL_ATTRIBUTE_NAME = '_widget_pool'.freeze
9
+
8
10
  extend ActiveModel::Naming
9
11
 
10
- include DateAttribute
12
+ include AttributeContent
11
13
  include ModelIdentity
12
14
 
15
+ def self.type_computer
16
+ @_type_computer ||= TypeComputer.new(RailsConnector::BasicObj, ::Obj)
17
+ end
18
+
19
+ def self.reset_type_computer!
20
+ @_type_computer = nil
21
+ end
22
+
13
23
  # Create a new Obj instance with the given values and attributes.
14
24
  # Normally this method should not be used.
15
25
  # Instead Objs should be loaded from the cms database.
@@ -21,13 +31,6 @@ module RailsConnector
21
31
  update_data(obj_data)
22
32
  end
23
33
 
24
- # instantiate an Obj instance from obj_data.
25
- # May result in an instance of a subclass of Obj according to STI rules.
26
- def self.instantiate(obj_data)
27
- obj_class = obj_data.value_of("_obj_class")
28
- BasicObj.compute_type(obj_class).new(obj_data)
29
- end
30
-
31
34
  # @api public
32
35
  def id
33
36
  read_attribute('_id')
@@ -168,26 +171,6 @@ module RailsConnector
168
171
  id
169
172
  end
170
173
 
171
- # A CMS administrator can specify the <tt>obj_class</tt> for a given CMS object.
172
- # In Rails, this could be either:
173
- #
174
- # * A valid and existing model name
175
- # * A valid and non-existing model name
176
- # * An invalid model name
177
- #
178
- # Rails' STI mechanism only considers the first case.
179
- # In any other case, RailsConnector::Obj is used, except when explicitly asked
180
- # for a model in the RailsConnector namespace (RailsConnector::Permission etc.)
181
-
182
- def self.compute_type(type_name)
183
- @compute_type_cache ||= {}
184
- @compute_type_cache[type_name] ||= try_type { type_name.constantize } || Obj
185
- end
186
-
187
- def self.reset_type_cache
188
- @compute_type_cache = {}
189
- end
190
-
191
174
  # return the Obj that is the parent of this Obj.
192
175
  # returns +nil+ for the root Obj.
193
176
  # @api public
@@ -394,11 +377,6 @@ module RailsConnector
394
377
  name
395
378
  end
396
379
 
397
- # @return [String]
398
- def type_of_attribute(field_name)
399
- data_from_cms.type_of(field_name.to_s)
400
- end
401
-
402
380
  # Returns an array with the names of groups that are permitted to access this Obj.
403
381
  # This corresponds to the cms permission "permissionLiveServerRead".
404
382
  def permitted_groups
@@ -531,10 +509,8 @@ module RailsConnector
531
509
  elsif key.start_with?('_') && OLD_INTERNAL_KEYS.include?(internal_key = key[1..-1])
532
510
  # For backwards compatibility reasons
533
511
  send(internal_key)
534
- elsif has_attribute?(key)
535
- read_attribute(key)
536
512
  else
537
- nil
513
+ super
538
514
  end
539
515
  end
540
516
 
@@ -651,45 +627,10 @@ module RailsConnector
651
627
  end
652
628
  end
653
629
 
654
- def respond_to?(method_id, include_private=false)
655
- if has_attribute?(method_id)
656
- true
657
- else
658
- super
659
- end
660
- end
661
-
662
630
  def inspect
663
631
  "<#{self.class} id=\"#{id}\" path=\"#{path}\">"
664
632
  end
665
633
 
666
- def has_attribute?(name)
667
- data_from_cms.has_custom_attribute?(name.to_s)
668
- end
669
-
670
- def widgets(attribute_name)
671
- unless (type_of_attribute(attribute_name) == 'widget')
672
- raise "Not a widget field: #{attribute_name}."
673
- end
674
-
675
- widgets = read_attribute(attribute_name.to_s, false)
676
-
677
- return [] unless widgets.present?
678
-
679
- output_objs = []
680
- (widgets['layout'] || []).each do |widget_hash|
681
- begin
682
- widget_obj = self.class.find(widget_hash['widget'])
683
- rescue RailsConnector::ResourceNotFound => e
684
- end
685
- if widget_obj.present? && widget_obj.path.start_with?("/_widgets/#{id}/")
686
- output_objs << widget_obj
687
- end
688
- end
689
-
690
- output_objs
691
- end
692
-
693
634
  def destroy
694
635
  if children.any?
695
636
  raise ClientError.new(I18n.t('rails_connector.errors.models.basic_obj.has_children'), 412)
@@ -702,62 +643,29 @@ module RailsConnector
702
643
  @widget_container ||= self.class.find(parent_path.split('/').last)
703
644
  end
704
645
 
705
- # Hook method to control which widget classes should be avaiable for this page.
706
- # Override it to allow only certain classes or none.
707
- # Must return either {NilClass}, or {Array}.
708
- #
709
- # If {NilClass} is returned, then all widget classes will be available for this page.
710
- # By default {NilClass} is returned.
711
- #
712
- # If {Array} is returned, then it should include desired class names.
713
- # Each class name must be either a {String} or a {Symbol}.
714
- # Only this class names will be available for this page.
715
- # Order of the class names will be preserved.
716
- #
717
- # @param [String] field_name Name of the widget field.
718
- # @return [NilClass, Array<Symbol, String>]
719
- # @api public
720
- def valid_widget_classes_for(field_name)
721
- end
722
-
723
646
  def edit_view_path
724
647
  "#{obj_class.underscore}/edit"
725
648
  end
726
649
 
727
- private
650
+ def widget_from_pool(widget_id)
651
+ widget_data = widget_data_from_pool(widget_id)
652
+ instantiate_widget(widget_id, widget_data) if widget_data
653
+ end
728
654
 
729
- attr_accessor :data_from_cms
655
+ private
730
656
 
731
- def update_data(data)
732
- self.data_from_cms = data
733
- @attribute_cache = {}
657
+ def widget_data_from_pool(widget_id)
658
+ read_widget_pool[widget_id]
734
659
  end
735
660
 
736
- def read_attribute(attribute_name, skip_widgets = true)
737
- if skip_widgets && (type_of_attribute(attribute_name) == 'widget')
738
- raise "Field #{attribute_name} not (yet) available, since it's a widget"
739
- end
740
- @attribute_cache.fetch(attribute_name) do
741
- (raw_value, attribute_type) = data_from_cms.value_and_type_of(attribute_name)
742
- @attribute_cache[attribute_name] =
743
- prepare_attribute_value(raw_value, attribute_type)
744
- end
661
+ def read_widget_pool
662
+ read_attribute(WIDGET_POOL_ATTRIBUTE_NAME)
745
663
  end
746
664
 
747
- def prepare_attribute_value(attribute_value, attribute_type)
748
- case attribute_type
749
- when "html"
750
- StringTagging.tag_as_html(attribute_value, self)
751
- when "date"
752
- DateAttribute.parse(attribute_value) if attribute_value
753
- when "linklist"
754
- LinkList.new(attribute_value)
755
- when "reference"
756
- self.class.find([attribute_value]).first
757
- when "referencelist"
758
- self.class.find(attribute_value).compact
759
- else
760
- attribute_value
665
+ def instantiate_widget(widget_id, widget_data)
666
+ BasicWidget.instantiate(widget_data).tap do |widget|
667
+ widget.id = widget_id
668
+ widget.obj = self
761
669
  end
762
670
  end
763
671
 
@@ -775,14 +683,6 @@ module RailsConnector
775
683
  Blob.find(blob_spec["id"]) if blob_spec
776
684
  end
777
685
 
778
- def method_missing(method_name, *args)
779
- if has_attribute?(method_name)
780
- read_attribute(method_name.to_s)
781
- else
782
- super
783
- end
784
- end
785
-
786
686
  def compare_on_sort_key(left_obj, right_obj, my_sort_key, my_sort_type)
787
687
  left_value = left_obj[my_sort_key]
788
688
  right_value = right_obj[my_sort_key]
@@ -806,20 +706,6 @@ module RailsConnector
806
706
  def converted_sort_type(attribute)
807
707
  read_attribute(attribute) == 1 ? "numeric" : "alphaNumeric"
808
708
  end
809
-
810
- class << self
811
- private
812
-
813
- def try_type
814
- klass = yield
815
- klass if klass.try(:descends_from_basic_obj?) # Descendants of BasicObj have this method
816
- rescue NameError
817
- end
818
-
819
- def descends_from_basic_obj?
820
- self != BasicObj
821
- end
822
- end
823
709
  end
824
710
 
825
711
  end