safrano 0.7.1 → 0.8.0

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: 56284ecd8544233a820d8163c324a4b86df3f87909e529ac993407dad3358132
4
- data.tar.gz: 3097012a5e22ccd3cc2b61e8ecc22427c35e8db12a02dfd3c9a819cfc13abd53
3
+ metadata.gz: 3c19f9f9e0a4700de60c1a177c1555663f50ab02e2e5fb0449e21f3c43751dbc
4
+ data.tar.gz: 0a56ca92c60b1e1a943f7710f7993c325b8e1e9d20b9df745b87dea954170722
5
5
  SHA512:
6
- metadata.gz: 23fffb3c40b6264ca8489ded795330c14410419db07fbad0f1fb9781a3ae31668264747df93df8e2d8df45dcdc546d4a6c61cf8d66cee54b7abb7b32e85bef2e
7
- data.tar.gz: a4473504fe30c922e3f6803dc608beb5495174ca3f884f4da04de479769a602fdc94df5f45c9a8edad2996146028d1cddacd626d61310b776ced641d32abbbd2
6
+ metadata.gz: 9f273cc9008c3bdab427268c5bf139aeb30093c515611714110da1b3f48d90b86ab40c62e6c96aea6dacc8eb7381793d126850fc8bccab991d89fcf010075647
7
+ data.tar.gz: 3d1e65f46c4e3fe1765288fb1f06e3f488b708216ce708103945fbf2aa12dd088e7fe6da8e06ebc8c6fa18b6bbd65b67506a5c8a8dde2097f405b57ceaa9d2b4
data/lib/odata/entity.rb CHANGED
@@ -184,16 +184,9 @@ module Safrano
184
184
  if req.walker.media_value
185
185
  odata_media_value_put(req)
186
186
  elsif req.accept?(APPJSON)
187
- data.delete('__metadata')
188
-
189
- if req.in_changeset
190
- set_fields(data, self.class.data_fields, missing: :skip)
191
- save(transaction: false)
192
- else
193
- update_fields(data, self.class.data_fields, missing: :skip)
194
- end
195
-
196
- [202, EMPTY_HASH, to_odata_post_json(service: req.service)]
187
+
188
+ AlreadyExistsUnprocessableError.odata_get(req)
189
+
197
190
  else # TODO: other formats
198
191
  415
199
192
  end
data/lib/odata/error.rb CHANGED
@@ -142,7 +142,11 @@ module Safrano
142
142
  @msg = reason
143
143
  end
144
144
  end
145
-
145
+
146
+ class AlreadyExistsUnprocessableError < UnprocessableEntityError
147
+ @msg = 'The ressource you are trying to create already exists'
148
+ end
149
+
146
150
  # http Bad Req.
147
151
  class BadRequestError
148
152
  extend ErrorClass
@@ -8,7 +8,7 @@ require_relative 'response'
8
8
  module Safrano
9
9
  # Note there is a strong 1 to 1 relation between an app instance
10
10
  # and a published service. --> actually means also
11
- # we only support on service per App-class because publishing is
11
+ # we only support one service per App-class because publishing is
12
12
  # made on app class level
13
13
  class ServerApp
14
14
  def initialize
@@ -36,7 +36,12 @@ module Safrano
36
36
  def self.get_service_base
37
37
  @service_base
38
38
  end
39
-
39
+
40
+ # needed for safrano-rack_builder
41
+ def get_path_prefix
42
+ self.class.get_service_base.xpath_prefix
43
+ end
44
+
40
45
  def self.set_servicebase(sbase)
41
46
  @service_base = sbase
42
47
  @service_base.enable_v1_service
@@ -7,12 +7,73 @@ module Rack
7
7
  module Safrano
8
8
  # just a Wrapper to ensure (force?) that mandatory middlewares are acutally
9
9
  # used
10
+ LOCALHOST_ANY_PORT_RGX = /\A(?:https?:\/\/)?localhost(?::\d+)?\z/
10
11
  class Builder < ::Rack::Builder
12
+
11
13
  def initialize(default_app = nil, &block)
12
14
  super(default_app) {}
13
- use ::Rack::Cors
15
+ @middlewares = []
16
+
14
17
  instance_eval(&block) if block_given?
15
- use ::Rack::ContentLength
18
+ prepend_rackcors_ifneeded
19
+ end
20
+
21
+ def use(middleware, *args, &block)
22
+ @middlewares << middleware
23
+ super(middleware, *args, &block)
24
+ end
25
+
26
+ def prepend_rackcors_ifneeded
27
+ return if stack_has_rackcors
28
+
29
+ # get the safrano app path prefix
30
+ # normally @run is a Safrano Server app
31
+ return unless @run.is_a? ::Safrano::ServerApp
32
+
33
+
34
+ service_path_prefix = @run.get_path_prefix.dup
35
+
36
+ # due to a bug in rack-cors
37
+ # we cant use the batch ressource path as
38
+ # a string but need to pass it as a regexp
39
+ # ( bug fixed in rack-cors git / new release? but still need to workaround it for
40
+ # current/old releases ),
41
+ batch_path_regexp = if service_path_prefix.empty?
42
+ # Ressource /$batch
43
+ /\A\/\$batch\z/
44
+ else
45
+ # Ressource like /foo/bar/baz/$batch
46
+ service_path_prefix.sub!(::Safrano::TRAILING_SLASH_RGX, '')
47
+ service_path_prefix.sub!(::Safrano::LEADING_SLASH_RGX, '')
48
+ # now is foo/bar/baz
49
+ path_prefix_rgx = Regexp.escape("/#{service_path_prefix}/$batch")
50
+ # now escaped path regexp /foo/bar/baz/$batch
51
+ # finaly just add start / end anchors
52
+ /\A#{path_prefix_rgx}\z/
53
+ end
54
+ # this will append rack-cors mw
55
+ # per default allow GET * from everywhere
56
+ # allow POST $batch from localhost only
57
+ use ::Rack::Cors do
58
+ allow do
59
+ origins LOCALHOST_ANY_PORT_RGX
60
+ resource (batch_path_regexp), headers: :any, methods: [:post, :head, :options]
61
+ resource '*', headers: :any, methods: [:get, :post, :put, :patch, :head, :options]
62
+ end
63
+ allow do
64
+ origins '*'
65
+ resource '*', headers: :any, methods: [:get, :head, :options]
66
+ end
67
+
68
+ end
69
+
70
+ # we need it in first place... move last element to beginin of mw stack
71
+ rackcors = @use.delete_at(-1)
72
+ @use.insert(0, rackcors)
73
+ end
74
+
75
+ def stack_has_rackcors
76
+ @middlewares.find{|mw| mw == Rack::Cors }
16
77
  end
17
78
  end
18
79
  end
@@ -7,14 +7,16 @@ module Safrano
7
7
  # handle GET PUT etc
8
8
  module MethodHandlers
9
9
  def odata_options
10
- @walker.finalize.tap_error { |err| return err.odata_get(self) }
11
- .if_valid do |_context|
12
- # cf. stackoverflow.com/questions/22924678/sinatra-delete-response-headers
13
- headers.delete('Content-Type')
14
- @response.headers.delete('Content-Type')
15
- @response.headers['Content-Type'] = ''
16
- [200, EMPTY_HASH, '']
17
- end
10
+ # cf. stackoverflow.com/questions/22924678/sinatra-delete-response-headers
11
+ headers.delete('Content-Type')
12
+ @response.headers.delete('Content-Type')
13
+ @response.headers['Content-Type'] = ''
14
+
15
+ # we only let rack-cors handle Cors OPTIONS .
16
+ # otherwise dont do it...
17
+ # see https://www.mnot.net/blog/2012/10/29/NO_OPTIONS
18
+ # 501 not implemented
19
+ [501, EMPTY_HASH, '']
18
20
  end
19
21
 
20
22
  def odata_delete
@@ -39,7 +41,7 @@ module Safrano
39
41
 
40
42
  def odata_post
41
43
  @walker.finalize.tap_error { |err| return err.odata_get(self) }
42
- .if_valid { |context| context.odata_post(self) }
44
+ .if_valid { |context| context.odata_post(self) }
43
45
  end
44
46
 
45
47
  def odata_head
@@ -107,6 +107,8 @@ module Safrano
107
107
  MIN_DATASERVICE_VERSION = '1'
108
108
  CV_MAX_DATASERVICE_VERSION = Contract.valid(MAX_DATASERVICE_VERSION).freeze
109
109
  CV_MIN_DATASERVICE_VERSION = Contract.valid(MIN_DATASERVICE_VERSION).freeze
110
+ TRAILING_SLASH_RGX = %r{/\z}.freeze
111
+ LEADING_SLASH_RGX = %r{\A/}.freeze
110
112
  include XMLNS
111
113
  # Base class for service. Subclass will be for V1, V2 etc...
112
114
  class ServiceBase
@@ -166,7 +168,6 @@ module Safrano
166
168
  instance_eval(&block) if block_given?
167
169
  end
168
170
 
169
- TRAILING_SLASH = %r{/\z}.freeze
170
171
  DEFAULT_PATH_PREFIX = '/'
171
172
  DEFAULT_SERVER_URL = 'http://localhost:9494'
172
173
 
@@ -200,13 +201,14 @@ module Safrano
200
201
  end
201
202
 
202
203
  def path_prefix(path_pr)
203
- @xpath_prefix = path_pr.sub(TRAILING_SLASH, '')
204
+ @xpath_prefix = path_pr.sub(TRAILING_SLASH_RGX, '')
205
+ @xpath_prefix.freeze
204
206
  (@v1.xpath_prefix = @xpath_prefix) if @v1
205
207
  (@v2.xpath_prefix = @xpath_prefix) if @v2
206
208
  end
207
209
 
208
210
  def server_url(surl)
209
- @xserver_url = surl.sub(TRAILING_SLASH, '')
211
+ @xserver_url = surl.sub(TRAILING_SLASH_RGX, '')
210
212
  (@v1.xserver_url = @xserver_url) if @v1
211
213
  (@v2.xserver_url = @xserver_url) if @v2
212
214
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Safrano
4
- VERSION = '0.7.1'
4
+ VERSION = '0.8.0'
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.7.1
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - oz
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-22 00:00:00.000000000 Z
11
+ date: 2023-10-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -253,7 +253,7 @@ metadata:
253
253
  changelog_uri: https://gitlab.com/dm0da/safrano/blob/master/CHANGELOG
254
254
  source_code_uri: https://gitlab.com/dm0da/safrano/tree/master
255
255
  documentation_uri: https://gitlab.com/dm0da/safrano/-/blob/master/README.md
256
- post_install_message:
256
+ post_install_message:
257
257
  rdoc_options: []
258
258
  require_paths:
259
259
  - lib
@@ -268,8 +268,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
268
268
  - !ruby/object:Gem::Version
269
269
  version: '0'
270
270
  requirements: []
271
- rubygems_version: 3.2.5
272
- signing_key:
271
+ rubygems_version: 3.3.15
272
+ signing_key:
273
273
  specification_version: 4
274
274
  summary: Safrano is an OData server library
275
275
  test_files: []