safrano 0.6.5 → 0.6.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b71032a7ee1e048867f3b54f57d920ba772a44f29a3419a598d2206d50e949c7
4
- data.tar.gz: d203df34eda2c7aad9385a84e866d273f1a1f37ba981ffdcc8956de9dad35633
3
+ metadata.gz: a93263d81a1f266029f7aac03d6b7226477f10d27d33255462e08133955ab759
4
+ data.tar.gz: 894a0bfab2eeeee57543bee7dd0c1ec93b5bc73e0afc6fe5f979c7b7e7067039
5
5
  SHA512:
6
- metadata.gz: d5cb1583e62f42f9007368204d24f101273049c05e75723dbcd7796732d83e1ac29a1515df0a876a2002c212b0da8204c498070104688fd4b493092072e13dee
7
- data.tar.gz: 96aa136d330148331b98943807c83b42e466aa7357c8b360b3f5a66843b9472df41015309b2bef19d993bdabf5f4d1d41e983e7082a1f06d34015370bc87a034
6
+ metadata.gz: f0900d4f692a9139226d4fb84703f8a0c47a071b97b0a46c8455016f6a7d0d09caf2b12f32e616c9880a10a0b50e09917ca22afc4af7fc0f4cddac690193b25c
7
+ data.tar.gz: 30a623f667830e0dc4342bcf240843d313173ef12c0e877dc1814e779fc7f53459e7ec7e958aedd22b4387c9390907844a0c2c84a639db8d98dc62805203a671
@@ -21,7 +21,7 @@ module Safrano
21
21
  class Static < Handler
22
22
  def initialize(root: nil, mediaklass:)
23
23
  @root = File.absolute_path(root || Dir.pwd)
24
- @file_server = ::Rack::File.new(@root)
24
+ @file_server = ::Rack::Files.new(@root)
25
25
  @media_class = mediaklass
26
26
  @media_dir_name = mediaklass.to_s
27
27
  register
@@ -81,9 +81,9 @@ module Safrano
81
81
  end
82
82
 
83
83
  # needed for ComplexType result
84
- def to_odata_json(_req)
84
+ def to_odata_json(req)
85
85
  t = self.class.klassmod.output_template
86
- innerh = _req.service.get_entity_odata_h(entity: @value, template: t)
86
+ innerh = req.service.get_entity_odata_h(entity: @value, template: t)
87
87
  innerj = innerh.to_json
88
88
 
89
89
  "#{DJ_OPEN}#{innerj}#{DJ_CLOSE}"
data/lib/odata/error.rb CHANGED
@@ -48,6 +48,13 @@ module Safrano
48
48
  end
49
49
  end
50
50
 
51
+ # used in function import error handling. cf. func import / do_execute_func
52
+ def self.with_error(result)
53
+ if result.respond_to?(:error) && (err = result.error)
54
+ yield err
55
+ end
56
+ end
57
+
51
58
  # base module for HTTP errors, when used as a Error Class
52
59
  module ErrorClass
53
60
  include ::Safrano::Contract::Invalid
@@ -94,10 +101,20 @@ module Safrano
94
101
  # generic http 500 server err
95
102
  class ServerError
96
103
  extend ErrorClass
104
+ include ErrorInstance
97
105
  HTTP_CODE = 500
98
106
  @msg = 'Server error'
99
107
  end
100
108
 
109
+ class ServiceOperationError
110
+ extend ErrorClass
111
+ include ErrorInstance
112
+ HTTP_CODE = 500
113
+ def initialize(msg:, sopname: nil)
114
+ @msg = "Error in service operation #{sopname}: #{msg}"
115
+ end
116
+ end
117
+
101
118
  # for outputing Sequel exceptions that we could not prevent
102
119
  class SequelExceptionError < ServerError
103
120
  include ErrorInstance
@@ -10,6 +10,21 @@ module Safrano
10
10
  end
11
11
 
12
12
  module FunctionImport
13
+ # error classes
14
+ class DefinitionMissing < StandardError
15
+ def initialize(fnam)
16
+ msg = "Function import #{fnam}: definition is missing. Provide definition either as a return code block or with .definition(lambda)"
17
+ super(msg)
18
+ end
19
+ end
20
+ class ProcRedefinition < StandardError
21
+ def initialize(fnam)
22
+ msg = "Function import #{fnam}: Block/lambda Redefinition . Provide definition either as a return code block or with .definition(lambda) but not both"
23
+ super(msg)
24
+ end
25
+ end
26
+
27
+ # Function import object
13
28
  class Function
14
29
  @allowed_transitions = [Safrano::TransitionEnd]
15
30
  attr_reader :name
@@ -53,8 +68,6 @@ module Safrano
53
68
  alias auto_query_params auto_query_parameters
54
69
 
55
70
  def return(klassmod, &proc)
56
- raise('Please provide a code block') unless block_given?
57
-
58
71
  @returning = if klassmod.respond_to? :return_as_instance_descriptor
59
72
  klassmod.return_as_instance_descriptor
60
73
  else
@@ -62,13 +75,35 @@ module Safrano
62
75
  # --> assume it is a Primitive
63
76
  ResultDefinition.asPrimitiveType(klassmod)
64
77
  end
65
- @proc = proc
78
+ # block is optional since 0.6.7
79
+ # the function definition can now also be made with .definition(lambda)
80
+ # consistency check that there is a single definition either as a
81
+ # return-block or a definition lambda is made on publish finalise
82
+
83
+ if block_given?
84
+ # proc already defined...
85
+ raise Redefinition.new(@name) if @proc
86
+
87
+ @proc = proc
88
+ end
89
+
66
90
  self
67
91
  end
68
92
 
69
- def return_collection(klassmod, &proc)
70
- raise('Please provide a code block') unless block_given?
93
+ def definition(lambda)
94
+ raise('Please provide a lambda') unless lambda
95
+ # proc already defined...
96
+ raise ProcRedefinition.new(@name) if @proc
97
+
98
+ @proc = lambda
99
+ end
100
+
101
+ # this is called from service.finalize_publishing
102
+ def check_definition
103
+ raise DefinitionMissing.new(@name) unless @proc
104
+ end
71
105
 
106
+ def return_collection(klassmod, lambda: nil, &proc)
72
107
  @returning = if klassmod.respond_to? :return_as_collection_descriptor
73
108
  klassmod.return_as_collection_descriptor
74
109
  else
@@ -77,7 +112,14 @@ module Safrano
77
112
  # ResultAsPrimitiveTypeColl.new(klassmod)
78
113
  ResultDefinition.asPrimitiveTypeColl(klassmod)
79
114
  end
80
- @proc = proc
115
+ # block is optional since 0.6.7
116
+ if block_given?
117
+ # proc already defined...
118
+ raise ProcRedefinition.new(@name) if @proc
119
+
120
+ @proc = proc
121
+ end
122
+
81
123
  self
82
124
  end
83
125
  # def initialize_params
@@ -151,14 +193,31 @@ module Safrano
151
193
  def with_transition_validated(req)
152
194
  # initialize_params
153
195
  @params = req.params
154
- return yield unless (@error = check_url_func_params)
155
-
196
+ unless (@error = check_url_func_params)
197
+ begin
198
+ return yield
199
+ rescue LocalJumpError => e
200
+ @error = Safrano::ServiceOperationReturnError.new
201
+ end
202
+ end
156
203
  [nil, :error, @error] if @error
157
204
  end
158
205
 
159
206
  def do_execute_func(req)
160
207
  with_transition_validated(req) do
161
208
  result = @proc.call(**@funcparams)
209
+
210
+ # (application-)error handling
211
+ # the result is an Error object or class
212
+
213
+ # Note: Sequel::Error exceptions are already
214
+ # handled on rack app level (cf. the call methode )
215
+ Safrano::with_error(result) do |error|
216
+ @error = error
217
+ return [nil, :error, @error] # this is return from do_execute_func !
218
+ end
219
+
220
+ # non error case
162
221
  [@returning.do_execute_func_result(result, req, @auto_query_params), :run]
163
222
  end
164
223
  end
@@ -753,7 +753,8 @@ module Safrano
753
753
  # json is default content type so we dont need to specify it here again
754
754
  # TODO quirks array mode !
755
755
  # [201, EMPTY_HASH, new_entity.to_odata_post_json(service: req.service)]
756
- [201, { 'Location' => new_entity.uri }, new_entity.to_odata_create_json(request: req)]
756
+ [201, { Safrano::LOCATION => new_entity.uri },
757
+ new_entity.to_odata_create_json(request: req)]
757
758
  else # TODO: other formats
758
759
  415
759
760
  end
@@ -1,9 +1,15 @@
1
1
  require 'json'
2
2
  require 'time'
3
-
3
+ require 'base64'
4
4
  # client parsing functionality to ease testing
5
5
 
6
6
  module Safrano
7
+ module RFC2047
8
+ def self.encode(str)
9
+ "=?utf-8?b?#{Base64.strict_encode64(str)}?="
10
+ end
11
+ end
12
+
7
13
  module OData
8
14
  # this is used to parse inbound json payload on POST / PUT & co
9
15
  # it does not do symbolize but proper (hopefully) type casting when needed
data/lib/safrano/core.rb CHANGED
@@ -13,10 +13,10 @@ module Safrano
13
13
 
14
14
  # some prominent constants... probably already defined elsewhere eg in Rack
15
15
  # but lets KISS
16
- CONTENT_TYPE = 'Content-Type'
17
- CONTENT_LENGTH = 'Content-Length'
18
- LOCATION = 'Location'
19
- CTT_TYPE_LC = 'content-type'
16
+ CONTENT_TYPE = 'content-type'
17
+ CONTENT_LENGTH = 'content-length'
18
+ LOCATION = 'location'
19
+
20
20
  TEXTPLAIN_UTF8 = 'text/plain;charset=utf-8'
21
21
  APPJSON = 'application/json'
22
22
  APPXML = 'application/xml'
@@ -142,12 +142,12 @@ module MIME
142
142
  @lines = inpstr.readlines(@sep)
143
143
  else
144
144
  # rack input wrapper only has gets but not readlines
145
- sepsave = $INPUT_RECORD_SEPARATOR
146
- $INPUT_RECORD_SEPARATOR = @sep
147
- while (line = inpstr.gets)
148
- @lines << line
149
- end
150
- $INPUT_RECORD_SEPARATOR = sepsave
145
+ # BUT the rack SPEC says it only supports gets without argument!
146
+ # --> finally we end up using read and split into lines...
147
+ # normally should be ok for $batch POST payloads
148
+
149
+ # inpstr.read should be a String
150
+ @lines = inpstr.read.lines(@sep)
151
151
 
152
152
  end
153
153
  # tmp hack for test-tools that convert CRLF in payload to LF :-(
@@ -375,7 +375,7 @@ module Safrano
375
375
  def finalize_publishing
376
376
  # build the cmap
377
377
  @cmap = {}
378
- @collections.each do |klass|
378
+ @collections&.each do |klass|
379
379
  @cmap[klass.entity_set_name] = klass
380
380
  # set namespace needed to have qualified type name
381
381
  copy_namespace_to(klass)
@@ -393,7 +393,7 @@ module Safrano
393
393
  set_uribase
394
394
 
395
395
  # finalize the uri's and include NoMappingBeforeOutput or MappingBeforeOutput as needed
396
- @collections.each do |klass|
396
+ @collections&.each do |klass|
397
397
  klass.finalize_publishing(self)
398
398
 
399
399
  klass.build_uri(@uribase)
@@ -448,9 +448,14 @@ module Safrano
448
448
  Safrano::Filter::DateTimeLit.include Safrano::Filter::DateTimeDefault
449
449
  Safrano::Filter::DateTimeOffsetLit.include Safrano::Filter::DateTimeDefault
450
450
  end
451
+
452
+ # check function import definition
453
+ function_imports.each_value { |func| func.check_definition }
451
454
  end
452
455
 
453
456
  def execute_deferred_iblocks
457
+ return unless @collections
458
+
454
459
  @collections.each do |k|
455
460
  k.instance_eval(&k.deferred_iblock) if k.deferred_iblock
456
461
  end
@@ -460,6 +465,8 @@ module Safrano
460
465
  ## evaluated after '@collections' is filled !
461
466
  # A regexp matching all allowed base entities (eg product|categories )
462
467
  def base_url_regexp
468
+ return unless @collections
469
+
463
470
  @collections.map(&:entity_set_name).join('|')
464
471
  end
465
472
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Safrano
4
- VERSION = '0.6.5'
4
+ VERSION = '0.6.7'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: safrano
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.5
4
+ version: 0.6.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - oz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-28 00:00:00.000000000 Z
11
+ date: 2023-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.0'
33
+ version: '1.1'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.0'
40
+ version: '1.1'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rfc2047
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -114,14 +114,14 @@ dependencies:
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '1.0'
117
+ version: '2.0'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: '1.0'
124
+ version: '2.0'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: rake
127
127
  requirement: !ruby/object:Gem::Requirement