scrivito_sdk 0.66.0 → 0.70.0.rc1

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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/scrivito/blobs_controller.rb +5 -0
  3. data/app/controllers/scrivito/objs_controller.rb +2 -1
  4. data/app/controllers/scrivito/ui_controller.rb +33 -3
  5. data/app/helpers/scrivito_helper.rb +14 -20
  6. data/app/views/scrivito/objs/update.json.jbuilder +1 -1
  7. data/app/views/scrivito/ui/index.html.erb +1 -1
  8. data/app/views/scrivito/webservice/_workspace.json.jbuilder +2 -1
  9. data/config/ca-bundle.crt +1 -1
  10. data/config/precedence_routes.rb +3 -2
  11. data/lib/assets/javascripts/scrivito.js +46 -0
  12. data/lib/assets/javascripts/scrivito_ui.js +931 -501
  13. data/lib/assets/stylesheets/scrivito.css +1 -0
  14. data/lib/assets/stylesheets/scrivito_ui.css +1 -1
  15. data/lib/generators/scrivito/install/templates/app/views/page/index.html.erb +3 -3
  16. data/lib/generators/scrivito/page/page_generator.rb +3 -0
  17. data/lib/generators/scrivito/page/templates/model.erb +3 -0
  18. data/lib/generators/scrivito/widget/templates/model.erb +3 -0
  19. data/lib/generators/scrivito/widget/widget_generator.rb +3 -0
  20. data/lib/scrivito/attribute_content.rb +93 -60
  21. data/lib/scrivito/attribute_definition.rb +3 -3
  22. data/lib/scrivito/attribute_serializer.rb +2 -2
  23. data/lib/scrivito/backend/obj_data_cache.rb +22 -9
  24. data/lib/scrivito/basic_obj.rb +238 -130
  25. data/lib/scrivito/basic_widget.rb +32 -20
  26. data/lib/scrivito/binary.rb +74 -45
  27. data/lib/scrivito/binary_routing.rb +52 -0
  28. data/lib/scrivito/cache_middleware.rb +0 -5
  29. data/lib/scrivito/client_attribute_serializer.rb +134 -0
  30. data/lib/scrivito/cms_backend.rb +51 -33
  31. data/lib/scrivito/cms_data_cache.rb +1 -0
  32. data/lib/scrivito/cms_dispatch_controller.rb +1 -1
  33. data/lib/scrivito/cms_env.rb +1 -11
  34. data/lib/scrivito/cms_field_tag.rb +10 -7
  35. data/lib/scrivito/cms_rest_api/rate_limit.rb +5 -5
  36. data/lib/scrivito/cms_rest_api/request_timer.rb +27 -0
  37. data/lib/scrivito/cms_rest_api/widget_extractor.rb +8 -6
  38. data/lib/scrivito/cms_rest_api.rb +107 -54
  39. data/lib/scrivito/cms_routing.rb +13 -25
  40. data/lib/scrivito/configuration.rb +5 -2
  41. data/lib/scrivito/controller_actions.rb +68 -7
  42. data/lib/scrivito/controller_runtime.rb +8 -0
  43. data/lib/scrivito/date_attribute.rb +8 -0
  44. data/lib/scrivito/errors.rb +6 -3
  45. data/lib/scrivito/generator_helper.rb +13 -0
  46. data/lib/scrivito/image_tag.rb +24 -30
  47. data/lib/scrivito/layout_tags.rb +12 -6
  48. data/lib/scrivito/link.rb +46 -30
  49. data/lib/scrivito/log_subscriber.rb +15 -0
  50. data/lib/scrivito/membership.rb +3 -3
  51. data/lib/scrivito/membership_collection.rb +10 -10
  52. data/lib/scrivito/meta_data_collection.rb +22 -0
  53. data/lib/scrivito/model_library.rb +7 -1
  54. data/lib/scrivito/obj_collection.rb +18 -16
  55. data/lib/scrivito/obj_params_parser.rb +1 -1
  56. data/lib/scrivito/obj_search_enumerator.rb +35 -35
  57. data/lib/scrivito/page_config.rb +55 -0
  58. data/lib/scrivito/request_homepage.rb +23 -0
  59. data/lib/scrivito/routing_helper.rb +8 -8
  60. data/lib/scrivito/sdk_engine.rb +2 -3
  61. data/lib/scrivito/ui_config.rb +85 -0
  62. data/lib/scrivito/user.rb +30 -23
  63. data/lib/scrivito/user_definition.rb +48 -47
  64. data/lib/scrivito/widget_tag.rb +11 -0
  65. data/lib/scrivito/workspace.rb +93 -35
  66. data/lib/scrivito/workspace_selection_middleware.rb +8 -1
  67. data/lib/scrivito_sdk.rb +24 -24
  68. metadata +24 -33
  69. data/lib/assets/javascripts/scrivito_sdk.js +0 -57
  70. data/lib/assets/stylesheets/scrivito_sdk.css +0 -1
  71. data/lib/scrivito/client_config.rb +0 -113
  72. data/lib/scrivito/editing_context_helper.rb +0 -19
  73. data/lib/scrivito/named_link.rb +0 -39
@@ -20,10 +20,11 @@ module ControllerActions
20
20
  :show_widget,
21
21
  :widget_details,
22
22
  :page_details,
23
- :resource_details,
24
23
  ]
25
24
 
26
25
  before_filter :load_object
26
+
27
+ helper_method :scrivito_in_editable_view?
27
28
  end
28
29
 
29
30
  #
@@ -60,11 +61,70 @@ module ControllerActions
60
61
  render 'scrivito/page_details', layout: 'scrivito_dialog'
61
62
  end
62
63
 
63
- def resource_details
64
- assert_dialog_layout
65
- @scrivito_resource = editing_context.selected_workspace.objs
66
- .find_including_deleted(params[:resource_id])
67
- render text: '', layout: 'scrivito_dialog'
64
+ # How to handle widget errors in +production+.
65
+ #
66
+ # When an exception is raised from within a widget, the entire page is not available.
67
+ # Often, this is the case in production if the developer has forgotten to handle specific
68
+ # content scenarios such as empty date attributes, missing titles, unmanaged enum values, etc.
69
+ # but also for simple coding mistakes during development.
70
+ #
71
+ # Override this method to prevent the entire page from being unavailable due to widget errors.
72
+ #
73
+ # The overridden method allows to:
74
+ # * catch a widget error and replace it with an HTML placeholder.
75
+ # * report a widget error to an external service like Honeybadger or Airbrake.
76
+ #
77
+ # This method is _not_ called if Rails is in the +development+ or +test+ environment.
78
+ # In those environments, all widget errors are just raised.
79
+ #
80
+ # By default, this method just reraises the given error.
81
+ #
82
+ # @param widget [Scrivito::BasicWidget] the flawed widget
83
+ # @param error [StandardError] the error that occurred
84
+ # @raise [StandardError] if this method is not overridden, the +error+ passed to it is reraised.
85
+ #
86
+ # @example Notify external service about widget error and render an HTML placeholder:
87
+ # def on_scrivito_widget_error(widget, error)
88
+ # # Report error to external service (e.g. Honeybadger or Airbrake):
89
+ # Honeybadger.notify(error)
90
+ # notify_airbrake(error)
91
+ #
92
+ # # Replace corrupted widget output with a placeholder:
93
+ # message = "Rendering #{widget.description_for_editor} failed with #{error.message}"
94
+ # return "<!--#{message}-->".html_safe if Rails.env.production?
95
+ # "<p>#{message}</p>".html_safe
96
+ # end
97
+ # @api public
98
+ def on_scrivito_widget_error(widget, error)
99
+ raise error
100
+ end
101
+
102
+ #
103
+ # Returns whether the GUI is in the +editable+ view.
104
+ #
105
+ # +scrivito_in_editable_view?+ is also a helper method.
106
+ #
107
+ # @api public
108
+ # @return +true+ if the current visitor is an authenticated editor, the selected workspace is
109
+ # editable and the display mode is +editing+.
110
+ # @return +false+ otherwise.
111
+ #
112
+ def scrivito_in_editable_view?
113
+ editing_context.editable_display_mode?
114
+ end
115
+
116
+ #
117
+ # Returns the current user.
118
+ #
119
+ # +scrivito_user+ is also a helper method.
120
+ #
121
+ # @api public
122
+ # @return [Scrivito::User] if the {Scrivito::Configuration.editing_auth} callback returns an
123
+ # instance of {Scrivito::User}.
124
+ # @return +nil+ otherwise.
125
+ #
126
+ def scrivito_user
127
+ editing_context.editor
68
128
  end
69
129
 
70
130
  module ClassMethods
@@ -126,7 +186,8 @@ module ControllerActions
126
186
  # @api public
127
187
  #
128
188
  def deliver_file
129
- if url = @obj.binary_url
189
+ if binary = @obj.binary
190
+ url = BinaryRouting.new(request, scrivito_engine).resolved_binary_obj_url(@obj, binary)
130
191
  redirect_to CmsRouting.match_protocol(url, request)
131
192
  else
132
193
  render text: 'Empty Blob', status: 404
@@ -9,6 +9,14 @@ protected
9
9
 
10
10
  attr_internal :scrivito_runtime
11
11
 
12
+ def process_action(action, *args)
13
+ # We also need to reset the runtime before each action
14
+ # because of queries in middleware or in cases we are streaming
15
+ # and it won't be cleaned up by the method below.
16
+ reset_scrivito_runtime
17
+ super
18
+ end
19
+
12
20
  def cleanup_view_runtime
13
21
  self.scrivito_runtime = reset_scrivito_runtime
14
22
 
@@ -12,6 +12,14 @@ module Scrivito
12
12
  end
13
13
  end
14
14
 
15
+ def self.parse_iso8601(iso8601_date_time)
16
+ return unless iso8601_date_time
17
+
18
+ DateTime.iso8601(iso8601_date_time).in_time_zone
19
+ rescue ArgumentError
20
+ raise "The value is not a valid ISO 8601 date time: #{iso8601_date_time.inspect}"
21
+ end
22
+
15
23
  def self.serialize(attribute_value)
16
24
  attribute_value = case attribute_value
17
25
  when Date then attribute_value.to_time
@@ -17,7 +17,7 @@ end
17
17
  class InternalError < ScrivitoError
18
18
  end
19
19
 
20
- # @api beta
20
+ # @api public
21
21
  class TransformationError < ScrivitoError
22
22
  attr_reader :code
23
23
 
@@ -27,12 +27,15 @@ class TransformationError < ScrivitoError
27
27
  end
28
28
  end
29
29
 
30
- # @api beta
30
+ # @api public
31
31
  class TransformationSourceError < TransformationError
32
32
  end
33
33
 
34
- # @api beta
34
+ # @api public
35
35
  class TransformationDefinitionError < TransformationError
36
36
  end
37
37
 
38
+ class TransferModificationsError < ScrivitoError
39
+ end
40
+
38
41
  end # module Scrivito
@@ -0,0 +1,13 @@
1
+ module Scrivito
2
+ module GeneratorHelper
3
+ class << self
4
+ def attribute_definition(arg)
5
+ if %w(enum multienum).include?(arg.type.to_s)
6
+ "attribute :#{arg.name}, :#{arg.type}, values: []"
7
+ else
8
+ "attribute :#{arg.name}, :#{arg.type}"
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,51 +1,45 @@
1
1
  module Scrivito
2
2
 
3
3
  class ImageTag < Struct.new(:view_context)
4
- def options(obj, attribute_name, tag_options, editing_options)
4
+ def options(obj_or_widget, attribute_name, tag_options, editing_options)
5
5
  tag_options.reverse_merge(
6
- src: src(obj, attribute_name, editing_options),
7
- alt: alt(obj, attribute_name)
6
+ src: src(obj_or_widget, attribute_name, editing_options),
7
+ alt: alt(obj_or_widget, attribute_name)
8
8
  )
9
9
  end
10
10
 
11
11
  private
12
12
 
13
- def src(obj, attribute_name, editing_options)
14
- path(obj, attribute_name, editing_options) ||
13
+ def src(obj_or_widget, attribute_name, editing_options)
14
+ path(obj_or_widget, attribute_name, editing_options) ||
15
15
  editing_options[:placeholder] ||
16
16
  view_context.image_path('scrivito/image_placeholder.png')
17
17
  end
18
18
 
19
- def alt(obj, attribute_name)
20
- case target = obj[attribute_name]
21
- when Binary then obj.try(:alt_description)
19
+ def alt(obj_or_widget, attribute_name)
20
+ case target = obj_or_widget[attribute_name]
21
+ when Binary then obj_or_widget.try(:alt_description)
22
22
  when Enumerable then target.first.try(:alt_description)
23
23
  else target.try(:alt_description)
24
24
  end
25
25
  end
26
26
 
27
- def path(obj, attribute_name, editing_options)
28
- if target = target(obj, attribute_name, editing_options)
29
- image_options = editing_options.slice(:transform)
30
- cms_routing = CmsRouting.new(request, main_app, scrivito_engine, image_options)
31
- cms_routing.path_or_url(target, :path)
32
- end
33
- end
34
-
35
- def target(obj, attribute_name, editing_options)
36
- target = obj[attribute_name]
37
- target = link_target(target) if target.is_a?(Link)
38
- target = linklist_target(target) if target.is_a?(Enumerable)
39
- target
40
- end
41
-
42
- def link_target(link)
43
- link.internal? ? link.obj : link
44
- end
45
-
46
- def linklist_target(linklist)
47
- if linklist.any?
48
- link_target(linklist.first)
27
+ def path(obj_or_widget, attribute_name, editing_options)
28
+ attribute_value = obj_or_widget[attribute_name]
29
+ return if attribute_value.blank?
30
+
31
+ image_options = editing_options.slice(:transform)
32
+
33
+ if attribute_value.is_a?(Binary)
34
+ if obj_or_widget.is_a?(Widget)
35
+ raise ScrivitoError, 'scrivito_image_tag does not accept widgets with binary attributes'
36
+ end
37
+ BinaryRouting.new(request, scrivito_engine)
38
+ .binary_obj_url(obj_or_widget, attribute_value, image_options)
39
+ else
40
+ path = CmsRouting.new(request, main_app, scrivito_engine, image_options)
41
+ .path_or_url(attribute_value, :path)
42
+ path unless path == CmsRouting::LINK_TO_EMPTY_BLOB
49
43
  end
50
44
  end
51
45
 
@@ -1,14 +1,14 @@
1
1
  module Scrivito
2
2
 
3
3
  class LayoutTags < Struct.new(:view)
4
- def client_config(obj, resource)
4
+ def page_config(obj)
5
5
  if view.scrivito_user
6
- editing_context = EditingContextMiddleware.from_request(view.request)
7
- config = ClientConfig.new(obj, editing_context, view.lookup_context,
8
- resource: resource,
9
- return_to: view.params[:return_to]
6
+ page_config = PageConfig.new(
7
+ obj: obj,
8
+ editing_context: editing_context,
9
+ lookup_context: view.lookup_context,
10
10
  ).to_json
11
- view.content_tag(:div, '', 'data-scrivito-private-config' => config)
11
+ view.content_tag(:div, '', 'data-scrivito-private-page-config' => page_config)
12
12
  end
13
13
  end
14
14
 
@@ -21,6 +21,12 @@ class LayoutTags < Struct.new(:view)
21
21
  content << "; Version #{GemInfo.version}" if view.scrivito_user
22
22
  view.tag(:meta, name: 'generator', content: content)
23
23
  end
24
+
25
+ private
26
+
27
+ def editing_context
28
+ EditingContextMiddleware.from_request(view.request)
29
+ end
24
30
  end
25
31
 
26
32
  end
data/lib/scrivito/link.rb CHANGED
@@ -1,14 +1,14 @@
1
1
  require 'active_model/naming'
2
2
 
3
3
  module Scrivito
4
- # This class provides an interfaces for handling CMS Links.
5
- # To format a link for rendering in an html page, use the +scrivito_path+ or +scrivito_url+ methods.
4
+ # This class provides an interface for handling CMS links.
5
+ # To format a link for rendering on an HTML page, use the +scrivito_path+ or +scrivito_url+ methods.
6
6
  # @api public
7
7
  class Link
8
8
 
9
9
  extend ActiveModel::Naming
10
10
 
11
- # Parses a url and returns a {Link} object. Determines internal urls based on the given
11
+ # Parses a URL and returns a {Link} object. Determines internal URLs based on the given
12
12
  # +hostname+ and +port+.
13
13
  # @api public
14
14
  # @param [String] url
@@ -18,7 +18,9 @@ module Scrivito
18
18
  LinkParser.new(host, port).parse(url)
19
19
  end
20
20
 
21
- # Create a new link obj
21
+ # Create a new link object.
22
+ # @example Set the 'current_campaign' link of an object:
23
+ # obj.update(current_campaign: Scrivito::Link.new(obj: Obj.find('55dd1ce50ecc41c8')))
22
24
  # @api public
23
25
  # @param [Hash] link_data
24
26
  # @option link_data [String] url
@@ -31,57 +33,56 @@ module Scrivito
31
33
  @link_data = link_data.with_indifferent_access
32
34
  end
33
35
 
34
- # The link's external url. Only available for external links.
35
- # Warning: Do not output the url directly unless you know what you are doing.
36
- # Normally you want to use the +scrivito_path+ or +scrivito_url+ methods to format a link.
36
+ # The external URL of the link. Only available for external links.
37
+ # Warning: Do not output the URL directly unless you know what you are doing.
38
+ # Normally, you want to use the +scrivito_path+ or +scrivito_url+ methods to format a link.
37
39
  # @api public
38
40
  def url
39
41
  @link_data[:url]
40
42
  end
41
43
 
42
- # Set the link's external url. This will lead to an external link.
44
+ # Set the external URL of the link. This causes the link to become an external link.
43
45
  # @api public
44
46
  # @param value [String] the url of the link
45
47
  def url=(value)
46
48
  @link_data[:url] = value
47
49
  end
48
50
 
49
- # Returns the {BasicObj Obj} this link is referencing. May be nil if the
51
+ # Returns the {BasicObj Obj} this link references. May be +nil+ if the
50
52
  # link is external.
51
53
  # @api public
52
54
  def obj
53
55
  @link_data[:obj]
54
56
  end
55
57
 
56
- # Set the {BasicObj Obj} this link is referencing. May be nil if the
57
- # link is external.
58
+ # Set the {BasicObj Obj} this link should reference.
58
59
  # @api public
59
- # @param value [Obj] the obj this link should be referencing
60
+ # @param value [Obj] the obj this link should point to
60
61
  def obj=(value)
61
62
  @link_data[:obj] = value
62
63
  end
63
64
 
64
- # The link's title.
65
+ # Returns the title of the link.
65
66
  # @api public
66
67
  def title
67
68
  @link_data[:title]
68
69
  end
69
70
 
70
- # Set the link's title.
71
+ # Set the link title.
71
72
  # @api public
72
- # @param value [String] the link's title
73
+ # @param value [String] the title of the link
73
74
  def title=(value)
74
75
  @link_data[:title] = value
75
76
  end
76
77
 
77
- # Returns the link's query string as in "index.html?query_string".
78
+ # Returns the query string of the link as in "index.html?query_string".
78
79
  # See RFC3986 for details (http://www.ietf.org/rfc/rfc3986.txt).
79
80
  # @api public
80
81
  def query
81
82
  @link_data[:query]
82
83
  end
83
84
 
84
- # Set the link's query string as in "index.html?query_string".
85
+ # Set the query string of the link as in "index.html?query_string".
85
86
  # See RFC3986 for details (http://www.ietf.org/rfc/rfc3986.txt).
86
87
  # @api public
87
88
  # @param value [String] the query string of the link
@@ -89,31 +90,39 @@ module Scrivito
89
90
  @link_data[:query] = value
90
91
  end
91
92
 
92
- # Returns the link's anchor as in "index.html#anchor".
93
+ # Returns the anchor of the link as in "index.html#anchor".
93
94
  # See RFC3986 for details (http://www.ietf.org/rfc/rfc3986.txt).
94
95
  # @api public
95
96
  def fragment
96
97
  @link_data[:fragment]
97
98
  end
98
99
 
99
- # Set the link's anchor as in "index.html#anchor".
100
+ # Set the anchor of the link as in "index.html#anchor".
100
101
  # See RFC3986 for details (http://www.ietf.org/rfc/rfc3986.txt).
101
102
  # @api public
102
- # @param value [String] the anchor or fragement of the link
103
+ # @param value [String] the anchor or fragment of the link
103
104
  def fragment=(value)
104
105
  @link_data[:fragment] = value
105
106
  end
106
107
 
108
+ # Returns the link target. "target" refers to the equally-named HTML attribute,
109
+ # not the link destination.
110
+ # @api public
107
111
  def target
108
112
  @link_data[:target]
109
113
  end
110
114
 
115
+ # Set the link target. "target" refers to the equally-named HTML attribute,
116
+ # not the link destination.
117
+ # @api public
118
+ # @param value [String] the target of the link
111
119
  def target=(value)
112
120
  @link_data[:target] = value
113
121
  end
114
122
 
115
- # Returns the file extension (e.g. zip, pdf) of this link's (internal or external) target.
116
- # Returns an empty string if the file extension is can not be determined.
123
+ # Returns the file extension (e.g. zip, pdf) of the (internal or external) destination
124
+ # of this link.
125
+ # Returns an empty string if the file extension cannot be determined.
117
126
  # @api public
118
127
  def file_extension
119
128
  if internal?
@@ -124,9 +133,8 @@ module Scrivito
124
133
  end
125
134
  end
126
135
 
127
- # Returns the title of this Link if it is set.
128
- # Otherwise it returns the display_title of the destination object for internal Links
129
- # or the URL for external Links.
136
+ # Returns the title of this Link if it is set. If not, the +display_title+ of the destination
137
+ # object is returned for internal links, or the +url+ for external links.
130
138
  # @api public
131
139
  def display_title
132
140
  dt = title
@@ -135,10 +143,10 @@ module Scrivito
135
143
  dt
136
144
  end
137
145
 
138
- # The alt description of a +Link+ used for {ScrivitoHelper#scrivito_image_tag}.
146
+ # The alt description of a +Link+, used by {ScrivitoHelper#scrivito_image_tag}.
139
147
  #
140
- # By default this method returns the +title+ of this +Link+.
141
- # If +title+ is nil and this +Link+ references an {BasicObj Obj}
148
+ # By default, this method returns the +title+ of this +Link+.
149
+ # If +title+ is +nil+ and this +Link+ references an {BasicObj Obj}, the
142
150
  # +alt_description+ of that {BasicObj Obj} is used.
143
151
  #
144
152
  # @api public
@@ -147,13 +155,13 @@ module Scrivito
147
155
  obj.alt_description if internal?
148
156
  end
149
157
 
150
- # Returns true this Link links to a CMS Object.
158
+ # Returns true if this Link points to a CMS object.
151
159
  # @api public
152
160
  def internal?
153
161
  url.nil?
154
162
  end
155
163
 
156
- # Returns true if this Link links to an external URL.
164
+ # Returns true if this Link points to an external location.
157
165
  # @api public
158
166
  def external?
159
167
  !internal?
@@ -190,12 +198,20 @@ module Scrivito
190
198
  params[:title] = title if title
191
199
  params[:query] = query if query
192
200
  params[:fragment] = fragment if fragment
201
+ params[:target] = target if target
193
202
  else
194
203
  params[:url] = url
195
204
  params[:title] = title if title
205
+ params[:target] = target if target
196
206
  end
197
207
 
198
208
  params
199
209
  end
210
+
211
+ def ==(other)
212
+ return false unless other.is_a?(Link)
213
+
214
+ to_cms_api_linklist_params == other.to_cms_api_linklist_params
215
+ end
200
216
  end
201
217
  end
@@ -21,6 +21,21 @@ module Scrivito
21
21
  debug " #{name} #{event.payload[:index]} #{event.payload[:keys].inspect}"
22
22
  end
23
23
 
24
+ def backend_request(event)
25
+ self.class.runtime += event.duration
26
+ return unless logger.debug?
27
+
28
+ duration = '(%.1fms)' % [event.duration]
29
+
30
+ param = event.payload[:params]
31
+ param_text = " #{param}" if param
32
+
33
+ verb_text = event.payload[:verb].upcase
34
+ path_text = event.payload[:path]
35
+
36
+ debug " Scrivito #{verb_text} #{path_text}#{param_text} #{duration}"
37
+ end
38
+
24
39
  def logger
25
40
  Rails.logger
26
41
  end
@@ -1,7 +1,7 @@
1
1
  module Scrivito
2
2
 
3
3
  # @api public
4
- # Represents a Membership of a {User} in a {Workspace}
4
+ # Represents a Membership of a {User} in a {Workspace}.
5
5
  class Membership
6
6
 
7
7
  # @api public
@@ -15,7 +15,7 @@ module Scrivito
15
15
  #
16
16
  # @note Currently the only available role is "owner".
17
17
  #
18
- # @return [String] the name of role
18
+ # @return [String] the name of the role
19
19
  attr_reader :role
20
20
 
21
21
  def initialize(user_id, data)
@@ -28,7 +28,7 @@ module Scrivito
28
28
  # @api public
29
29
  # @return The value returned by the proc set in {Configuration.find_user}.
30
30
  # @return An unknown user if no proc is set in {Configuration.find_user} or the proc returns a
31
- # falsy value. The unknown user will have the id of the original user and no abilities.
31
+ # falsy value. The unknown user will have the id of the original user and no capabilities.
32
32
  # @see Scrivito::Configuration.find_user
33
33
  def user
34
34
  User.find(user_id) || User.unknown_user(user_id)
@@ -1,7 +1,7 @@
1
1
  module Scrivito
2
2
  # @api public
3
3
  # The MembershipCollection includes all members of a given {Workspace}.
4
- # You can access it using {Workspace#memberships} method.
4
+ # You can access it using the {Workspace#memberships} method.
5
5
  class MembershipCollection
6
6
  extend Forwardable
7
7
  include Enumerable
@@ -11,28 +11,28 @@ module Scrivito
11
11
  # @api public
12
12
  # @!method each
13
13
  # Iterate over all {Membership Memberships} of a specific {Workspace}. Allows
14
- # you to use all methods defined by ruby's Enumerable module.
14
+ # you to use all the methods defined by Ruby's Enumerable module.
15
15
  #
16
16
  # @yield [Membership]
17
17
  #
18
- # @return [Enumerator] if no block is given an Enumerator is returned
18
+ # @return [Enumerator] if no block is given, an Enumerator is returned
19
19
  #
20
20
  # @example
21
- # # Obtain all owners of a workspace
21
+ # # Obtain all owners of a workspace.
22
22
  # my_workspace.memberships.select do |membership|
23
23
  # membership.role == "owner"
24
24
  # end
25
25
  #
26
- # # Get an array of all the members' user_ids
26
+ # # Get an array of all the members' user_ids.
27
27
  # my_workspace.memberships.map { |membership| membership.user_id }
28
28
  #
29
- # # Or use it directly to iterate over all items
29
+ # # Or use it directly to iterate over all items.
30
30
  # my_workspace.memberships.each do |membership|
31
31
  # puts "User #{membership.user_id} has the role #{membership.role}"
32
32
  # end
33
33
  #
34
- # @note For a complete list of all provided methods please view the
35
- # documentation of the Enumerable module
34
+ # @note For a complete list of the provided methods, please refer to the
35
+ # documentation of the Enumerable module.
36
36
  def_delegator :memberships, :each
37
37
 
38
38
  def initialize(workspace)
@@ -40,7 +40,7 @@ module Scrivito
40
40
  end
41
41
 
42
42
  # @api public
43
- # return a hash where the keys are user_ids and the values are Membership-Instances
43
+ # Returns a hash where the keys are +user_id+s and the values are Membership instances.
44
44
  # @return [Hash<String, Membership>]
45
45
  def to_h
46
46
  memberships.inject(HashWithIndifferentAccess.new) do |hash, membership|
@@ -50,7 +50,7 @@ module Scrivito
50
50
  end
51
51
 
52
52
  # @api public
53
- # Returns the membership for a user or nil
53
+ # Returns the membership of a user or nil.
54
54
  #
55
55
  # @param [User, String] id_or_user
56
56
  # @return [Membership, nil]
@@ -0,0 +1,22 @@
1
+ module Scrivito
2
+ #
3
+ # This class represents a collection of meta data attributes.
4
+ #
5
+ # @api beta
6
+ #
7
+ class MetaDataCollection
8
+ def initialize(attributes)
9
+ @attributes = ActiveSupport::HashWithIndifferentAccess.new(attributes)
10
+ end
11
+
12
+ #
13
+ # Find value of a meta data attribute.
14
+ #
15
+ # @api beta
16
+ # @param name [Symbol, String] the name of the meta data attribute.
17
+ # @return [String, Array, Fixnum, Date, nil] meta data attribute value if found or +nil+ otherwise.
18
+ def [](name)
19
+ @attributes[name]
20
+ end
21
+ end
22
+ end
@@ -77,11 +77,17 @@ class ModelLibrary
77
77
  end
78
78
 
79
79
  def load_models_from_path(type, path, base_class)
80
- Dir["#{path}/**/*_#{type}.rb"].map do |file_path|
80
+ candidates_from_path(type, path).map do |file_path|
81
81
  load_model(file_path.gsub(path, '').gsub('.rb', '').classify, base_class)
82
82
  end
83
83
  end
84
84
 
85
+ def candidates_from_path(type, path)
86
+ result = Dir["#{path}/**/*_#{type}.rb"]
87
+ result += Dir["#{path}/**/page.rb"] if type == 'page'
88
+ result
89
+ end
90
+
85
91
  def load_model(class_name, base_class)
86
92
  model_class = class_name.constantize
87
93
  model_class if model_class.ancestors.include?(base_class)