scrivito_sdk 1.2.0 → 1.3.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/scrivito/blobs_controller.rb +5 -3
  3. data/app/controllers/scrivito/obj_class_controller.rb +58 -0
  4. data/app/controllers/scrivito/objs_controller.rb +1 -6
  5. data/app/controllers/scrivito/proxy/objs_controller.rb +34 -0
  6. data/app/controllers/scrivito/resolve_paths_controller.rb +21 -0
  7. data/app/controllers/scrivito/sessions_controller.rb +7 -0
  8. data/app/controllers/scrivito/webservice_controller.rb +11 -0
  9. data/app/controllers/scrivito/workspaces_controller.rb +7 -9
  10. data/app/helpers/scrivito_helper.rb +1 -1
  11. data/app/views/scrivito/obj_class/defaults.json.jbuilder +1 -0
  12. data/app/views/scrivito/proxy/index.json.jbuilder +1 -0
  13. data/app/views/scrivito/resolve_paths/resolve.json.jbuilder +1 -0
  14. data/app/views/scrivito/sessions/update.json.jbuilder +1 -0
  15. data/app/views/scrivito/ui/index.html.erb +1 -0
  16. data/app/views/scrivito/webservice/_workspace.json.jbuilder +0 -2
  17. data/config/ca-bundle.crt +55 -669
  18. data/config/precedence_routes.rb +7 -1
  19. data/lib/assets/images/scrivito/image_placeholder.gif +0 -0
  20. data/lib/assets/javascripts/scrivito_ui.js +6259 -3918
  21. data/lib/assets/stylesheets/scrivito.css +1 -1
  22. data/lib/assets/stylesheets/scrivito_ui.css +1 -1
  23. data/lib/scrivito/attribute_content.rb +43 -8
  24. data/lib/scrivito/attribute_deserializer.rb +11 -1
  25. data/lib/scrivito/attribute_serializer.rb +44 -8
  26. data/lib/scrivito/basic_obj.rb +3 -3
  27. data/lib/scrivito/binary.rb +17 -3
  28. data/lib/scrivito/binary_param_verifier.rb +2 -2
  29. data/lib/scrivito/client_attribute_serializer.rb +11 -1
  30. data/lib/scrivito/client_error.rb +1 -1
  31. data/lib/scrivito/cms_field_tag.rb +2 -0
  32. data/lib/scrivito/cms_rest_api.rb +6 -13
  33. data/lib/scrivito/{date_attribute.rb → date_conversion.rb} +2 -4
  34. data/lib/scrivito/float_conversion.rb +29 -0
  35. data/lib/scrivito/image_tag.rb +1 -1
  36. data/lib/scrivito/integer_conversion.rb +29 -0
  37. data/lib/scrivito/obj_params_parser.rb +1 -1
  38. data/lib/scrivito/obj_search_builder.rb +1 -1
  39. data/lib/scrivito/obj_search_enumerator.rb +19 -99
  40. data/lib/scrivito/obj_search_enumerator/facet_query.rb +105 -0
  41. data/lib/scrivito/page_config.rb +1 -0
  42. data/lib/scrivito/session.rb +23 -0
  43. data/lib/scrivito/task.rb +1 -1
  44. data/lib/scrivito/ui_config.rb +6 -0
  45. data/lib/scrivito/user.rb +4 -3
  46. data/lib/scrivito/user_definition.rb +7 -7
  47. data/lib/scrivito/workspace.rb +14 -3
  48. data/lib/scrivito/workspace_data.rb +5 -0
  49. metadata +18 -6
  50. data/lib/assets/images/scrivito/image_placeholder.png +0 -0
@@ -1,7 +1,7 @@
1
1
  module Scrivito
2
2
 
3
3
  # Adds support for string columns which contain ISO dates
4
- module DateAttribute
4
+ module DateConversion
5
5
  def self.deserialize_from_backend(iso_date_time)
6
6
  return nil unless iso_date_time
7
7
 
@@ -18,9 +18,7 @@ module Scrivito
18
18
  DateTime.iso8601(iso8601_date_time).in_time_zone
19
19
  rescue ArgumentError
20
20
  raise Scrivito::ClientError.new(
21
- "The value is not a valid ISO 8601 date time: #{iso8601_date_time.inspect}",
22
- 400
23
- )
21
+ "The value is not a valid ISO 8601 date time: #{iso8601_date_time.inspect}")
24
22
  end
25
23
 
26
24
  def self.serialize_for_backend(attribute_value)
@@ -0,0 +1,29 @@
1
+ module Scrivito
2
+ module FloatConversion
3
+ FLOAT_STRING_REGEX = /\A-?\d+(\.\d+)?\z/.freeze
4
+ DEFAULT_VALUE = 0.0
5
+
6
+ def self.deserialize_from_backend(backend_value)
7
+ case backend_value
8
+ when Integer, Float, FLOAT_STRING_REGEX
9
+ value = backend_value.to_f
10
+ value.finite? ? value : DEFAULT_VALUE
11
+ when nil, String
12
+ DEFAULT_VALUE
13
+ else
14
+ raise Scrivito::InternalError,
15
+ "invalid value #{backend_value} (class: #{backend_value.class})"
16
+ end
17
+ end
18
+
19
+ def self.serialize_for_backend(value, attr_name)
20
+ serialized_value = value.to_f
21
+ unless serialized_value.finite?
22
+ raise ClientError.new(
23
+ "Value #{value} for attribute #{attr_name} is not supported.")
24
+ end
25
+
26
+ value
27
+ end
28
+ end
29
+ end
@@ -13,7 +13,7 @@ class ImageTag < Struct.new(:view_context)
13
13
  def src(obj_or_widget, attribute_name, editing_options)
14
14
  path(obj_or_widget, attribute_name, editing_options) ||
15
15
  editing_options[:placeholder] ||
16
- view_context.image_path('scrivito/image_placeholder.png')
16
+ view_context.image_path('scrivito/image_placeholder.gif')
17
17
  end
18
18
 
19
19
  def alt(obj_or_widget, attribute_name)
@@ -0,0 +1,29 @@
1
+ module Scrivito
2
+ module IntegerConversion
3
+ INTEGER_STRING_REGEX = /\A-?\d+\z/.freeze
4
+ DEFAULT_VALUE = 0
5
+ RANGE = Range.new(-(2**53 - 1), (2**53 - 1)).freeze
6
+
7
+ def self.deserialize_from_backend(backend_value)
8
+ case backend_value
9
+ when Integer, Float, INTEGER_STRING_REGEX
10
+ value = backend_value.to_i
11
+ RANGE.include?(value) ? value : DEFAULT_VALUE
12
+ when nil, String
13
+ DEFAULT_VALUE
14
+ else
15
+ raise Scrivito::InternalError,
16
+ "invalid value #{backend_value} (class: #{backend_value.class})"
17
+ end
18
+ end
19
+
20
+ def self.serialize_for_backend(value, attr_name)
21
+ unless RANGE.include?(value)
22
+ raise ClientError.new(
23
+ "Value #{value} for attribute #{attr_name} is out of range: #{RANGE}")
24
+ end
25
+
26
+ value
27
+ end
28
+ end
29
+ end
@@ -19,7 +19,7 @@ module Scrivito
19
19
  when 'link' then ContentConversion.convert_link(value, host, port)
20
20
  when 'linklist' then ContentConversion.convert_linklist_urls(value, host, port)
21
21
  when 'widgetlist' then parse_widgetlist_params(value)
22
- when 'date' then DateAttribute.deserialize_from_client(value)
22
+ when 'date' then DateConversion.deserialize_from_client(value)
23
23
  else value
24
24
  end
25
25
  end
@@ -54,7 +54,7 @@ class ObjSearchBuilder < Struct.new(:query)
54
54
  def deserialize_values(values)
55
55
  values.map do |(type, value)|
56
56
  if type == 'date'
57
- DateAttribute.deserialize_from_client(value)
57
+ DateConversion.deserialize_from_client(value)
58
58
  else
59
59
  value
60
60
  end
@@ -149,8 +149,8 @@ module Scrivito
149
149
  include Enumerable
150
150
 
151
151
  attr_reader :workspace
152
-
153
152
  attr_reader :query
153
+
154
154
  def initialize(workspace, batch_size = nil)
155
155
  @workspace = workspace
156
156
  @batch_size = batch_size
@@ -288,7 +288,7 @@ module Scrivito
288
288
  #
289
289
  def batch_size(size)
290
290
  @batch_size = size
291
- @preload_search_result = true
291
+ @preload_batch = true
292
292
 
293
293
  self
294
294
  end
@@ -497,17 +497,16 @@ module Scrivito
497
497
  # @raise [Scrivito::ClientError] If the maximum number of results has been exceeded.
498
498
  # The number of results is limited to 100 with respect to the facets themselves and the included Objs.
499
499
  #
500
- def facet(*args)
501
- if args.length == 1 && args[0].is_a?(Hash)
502
- return {} if args[0].empty?
503
- facets_params = multiple_facet_params(args)
504
- get_facet_value_objs(facets_params, args[0].keys)
505
- else
506
- facets_params = [single_facet_params(*args)]
507
- attribute_name = args[0]
508
- result = get_facet_value_objs(facets_params, [attribute_name])
509
- result[attribute_name]
510
- end
500
+ def facet(*facet_params)
501
+ search_params = search_dsl_params
502
+ search_params[:size] = 0 unless @preload_batch
503
+
504
+ facet_query = FacetQuery.new(facet_params, search_params, workspace)
505
+ facet_query.execute!
506
+
507
+ @preloaded_batch = facet_query.batch if @preload_batch
508
+
509
+ facet_query.result
511
510
  end
512
511
 
513
512
  def fetch_batch(continuation=nil)
@@ -539,87 +538,16 @@ module Scrivito
539
538
  end
540
539
 
541
540
  def convert_single_value(value)
542
- if value.is_a?(Time) || value.is_a?(Date)
543
- DateAttribute.serialize_for_backend(value)
541
+ case value
542
+ when Time, Date
543
+ DateConversion.serialize_for_backend(value)
544
+ when Integer, Float
545
+ value
544
546
  else
545
547
  value.to_s
546
548
  end
547
549
  end
548
550
 
549
- def create_facet_value_objs(facet_arrays, obj_collection)
550
- result = []
551
- facet_arrays.map do |facet|
552
- included_objs = []
553
- if included_ids = get_objs_facet_ids(facet)
554
- obj_collection.each do |basic_obj|
555
- if included_ids.include? basic_obj.id
556
- included_objs << basic_obj unless included_objs.include? basic_obj
557
- end
558
- end
559
- end
560
- result << ObjFacetValue.new(facet["value"], facet["total"], included_objs)
561
- end
562
- result
563
- end
564
-
565
- def get_all_facets_ids(facet_array)
566
- result = []
567
- facet_array.map do |facet|
568
- result += get_objs_facet_ids(facet)
569
- end
570
- result
571
- end
572
-
573
- def multiple_facet_params(facets)
574
- facet_params = []
575
- facets.first.map do |k, v|
576
- facet_params << single_facet_params(k, v)
577
- end
578
- facet_params
579
- end
580
-
581
- def single_facet_params(attribute, options = {})
582
- { attribute: attribute }.merge!(options)
583
- end
584
-
585
- def get_objs_facet_ids(facet)
586
- result = []
587
- if included_ids = facet["results"]
588
- included_ids.each { |obj| result << obj["id"] }
589
- end
590
- result
591
- end
592
-
593
- def get_facet_value_objs(facets_params, attributes_list = [])
594
- result = attributes_list.each_with_object({}) { |v,h| h[v] = [] }
595
- included_objs_ids = []
596
-
597
- params = prepare_facet_search_params facets_params
598
-
599
- batch = QueryExecutor.new(workspace).call(params)
600
- @preloaded_batch = batch if @preload_search_result
601
-
602
- batch.facets.each do |facets_array|
603
- included_objs_ids += get_all_facets_ids(facets_array)
604
- end
605
-
606
- obj_collection = workspace.objs.find(included_objs_ids)
607
- batch.facets.each_with_index do |facets_array, index|
608
- result[result.keys[index]] += create_facet_value_objs(facets_array, obj_collection)
609
- end
610
- result
611
- end
612
-
613
- def prepare_facet_search_params(facet_params)
614
- params = { facets: facet_params }
615
-
616
- if query
617
- params.merge! search_dsl_params
618
- end
619
-
620
- params.reverse_merge(size: 0)
621
- end
622
-
623
551
  def operator_mapping(operator)
624
552
  case operator.to_sym
625
553
  when :contains
@@ -640,17 +568,9 @@ module Scrivito
640
568
  end
641
569
 
642
570
  def search_dsl_params
643
- patches = {
644
- query: query,
645
- }
571
+ patches = {query: query}
646
572
  patches[:size] = @batch_size if @batch_size
647
-
648
- if @include_deleted
649
- patches[:options] = {
650
- include_deleted: true
651
- }
652
- end
653
-
573
+ patches[:options] = {include_deleted: true} if @include_deleted
654
574
  options.merge(patches)
655
575
  end
656
576
 
@@ -0,0 +1,105 @@
1
+ module Scrivito
2
+ class ObjSearchEnumerator
3
+ #
4
+ # Response format (assuming we've requested facets for attributes "color" and "size"):
5
+ #
6
+ # [
7
+ # # Facets for attribute "color"
8
+ # [
9
+ # {value: "red", total: 2, results: [{id: "xxx"}, {id: "yyy"}]},
10
+ # {value: "blue", total: 1, results: [{id: "xxx"}]},
11
+ # {value: "green", total: 0, results: []},
12
+ # ],
13
+ #
14
+ # # Facets for attribute "size"
15
+ # [
16
+ # {value: "large", total: 2, results: [{id: "xxx"}, {id: "yyy"}]},
17
+ # {value: "medium", total: 1, results: [{id: "xxx"}]},
18
+ # {value: "small", total: 0, results: []},
19
+ # ]
20
+ # ]
21
+ #
22
+ #
23
+ class FacetQuery < Struct.new(:facet_params, :search_params, :workspace)
24
+ attr_reader :batch, :result
25
+
26
+ def execute!
27
+ @result = case
28
+ when facet_params.first.empty?
29
+ {}
30
+ when facet_params.one? && facet_params.first.is_a?(Hash)
31
+ fetch_result(multi_facet_params, facet_params.first.keys)
32
+ else
33
+ attribute_name = facet_params.first
34
+ fetch_result([single_facet_params(*facet_params)], [attribute_name])[attribute_name]
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def fetch_result(params, attribute_names)
41
+ result = attribute_names.each_with_object({}) { |v, h| h[v] = [] }
42
+
43
+ @batch = QueryExecutor.new(workspace).call(build_search_params(params))
44
+ objs = workspace.objs.find(obj_ids_from_batch)
45
+
46
+ @batch.facets.each_with_index do |facets_per_attribute, i|
47
+ result[result.keys[i]] += obj_facet_values(facets_per_attribute, objs)
48
+ end
49
+
50
+ result
51
+ end
52
+
53
+ def obj_ids_from_batch
54
+ ids = []
55
+
56
+ @batch.facets.each do |facets_per_attribute|
57
+ facets_per_attribute.each do |facet_hash|
58
+ ids += obj_ids_from_facet_hash(facet_hash)
59
+ end
60
+ end
61
+
62
+ ids
63
+ end
64
+
65
+ def multi_facet_params
66
+ facet_params.first.map do |attribute_name, options|
67
+ single_facet_params(attribute_name, options)
68
+ end
69
+ end
70
+
71
+ def single_facet_params(attribute, options = {})
72
+ {attribute: attribute}.merge!(options)
73
+ end
74
+
75
+ def obj_facet_values(facets_per_attribute, objs)
76
+ results = []
77
+
78
+ facets_per_attribute.map do |facet_hash|
79
+ obj_ids = obj_ids_from_facet_hash(facet_hash)
80
+ included_objs = []
81
+
82
+ objs.each do |obj|
83
+ if obj_ids.include?(obj.id) && !included_objs.include?(obj)
84
+ included_objs << obj
85
+ end
86
+ end
87
+
88
+ results << ObjFacetValue.new(facet_hash['value'], facet_hash['total'], included_objs)
89
+ end
90
+
91
+ results
92
+ end
93
+
94
+ def obj_ids_from_facet_hash(facet_hash)
95
+ facet_hash['results'].map { |obj_hash| obj_hash['id'] }
96
+ end
97
+
98
+ def build_search_params(params)
99
+ params = {facets: params}
100
+ params.merge!(search_params) if search_params
101
+ params.reverse_merge(size: 0)
102
+ end
103
+ end
104
+ end
105
+ end
@@ -24,6 +24,7 @@ class PageConfig < Struct.new(:obj, :editing_context, :lookup_context)
24
24
  {
25
25
  id: obj.id,
26
26
  obj_class: obj.obj_class,
27
+ description_for_editor: obj.description_for_editor,
27
28
  has_children: obj.children.any?,
28
29
  has_conflict: obj.has_conflict?,
29
30
  has_details_view: obj_has_details_view?,
@@ -0,0 +1,23 @@
1
+ module Scrivito
2
+ class Session
3
+ def self.renew(id, user)
4
+ payload = {
5
+ session: {
6
+ role: 'editor',
7
+ user_id: user.id,
8
+ permissions: permissions(user),
9
+ },
10
+ }
11
+
12
+ CmsRestApi.task_unaware_request(:put, "sessions/#{id}", payload)
13
+ end
14
+
15
+ def self.permissions(user)
16
+ Hash[user.explicit_rules.map do |permission, verb, _, _|
17
+ [verb, permission.to_s]
18
+ end]
19
+ end
20
+
21
+ private_class_method :permissions
22
+ end
23
+ end
data/lib/scrivito/task.rb CHANGED
@@ -34,7 +34,7 @@ module Scrivito
34
34
  def result
35
35
  case
36
36
  when success? then @result
37
- when error? then raise ClientError.new(@message, 400, @code)
37
+ when error? then raise ClientError.new(@message, backend_code: @code)
38
38
  else
39
39
  poll
40
40
  result
@@ -10,6 +10,7 @@ class UiConfig < Struct.new(:editing_context, :resource, :return_to, :app_extens
10
10
  {
11
11
  app_extension_tags: app_extension_tags,
12
12
  editing_context: editing_context_config,
13
+ session: session_config,
13
14
  i18n: i18n_config,
14
15
  is_development_mode: Rails.env.development?,
15
16
  resource_dialog: resource_dialog_config,
@@ -30,6 +31,10 @@ class UiConfig < Struct.new(:editing_context, :resource, :return_to, :app_extens
30
31
  }
31
32
  end
32
33
 
34
+ def session_config
35
+ Session.renew(SecureRandom.hex(8), editor)
36
+ end
37
+
33
38
  def workspace_config(workspace)
34
39
  {
35
40
  id: workspace.id,
@@ -41,6 +46,7 @@ class UiConfig < Struct.new(:editing_context, :resource, :return_to, :app_extens
41
46
  }
42
47
  end,
43
48
  outdated: workspace.outdated?,
49
+ auto_update: workspace.auto_update?,
44
50
  title: workspace.title,
45
51
  }
46
52
  end