fmrest 0.12.0 → 0.13.0

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -0
  3. data/CHANGELOG.md +11 -0
  4. data/README.md +175 -809
  5. metadata +61 -109
  6. data/.gitignore +0 -26
  7. data/.rspec +0 -3
  8. data/.travis.yml +0 -5
  9. data/Gemfile +0 -3
  10. data/Rakefile +0 -6
  11. data/UPGRADING +0 -15
  12. data/fmrest.gemspec +0 -49
  13. data/lib/fmrest.rb +0 -36
  14. data/lib/fmrest/connection_settings.rb +0 -124
  15. data/lib/fmrest/errors.rb +0 -30
  16. data/lib/fmrest/spyke.rb +0 -21
  17. data/lib/fmrest/spyke/base.rb +0 -9
  18. data/lib/fmrest/spyke/container_field.rb +0 -59
  19. data/lib/fmrest/spyke/model.rb +0 -33
  20. data/lib/fmrest/spyke/model/associations.rb +0 -86
  21. data/lib/fmrest/spyke/model/attributes.rb +0 -163
  22. data/lib/fmrest/spyke/model/auth.rb +0 -43
  23. data/lib/fmrest/spyke/model/connection.rb +0 -163
  24. data/lib/fmrest/spyke/model/container_fields.rb +0 -40
  25. data/lib/fmrest/spyke/model/global_fields.rb +0 -40
  26. data/lib/fmrest/spyke/model/http.rb +0 -77
  27. data/lib/fmrest/spyke/model/orm.rb +0 -256
  28. data/lib/fmrest/spyke/model/record_id.rb +0 -78
  29. data/lib/fmrest/spyke/model/serialization.rb +0 -99
  30. data/lib/fmrest/spyke/model/uri.rb +0 -29
  31. data/lib/fmrest/spyke/portal.rb +0 -55
  32. data/lib/fmrest/spyke/relation.rb +0 -359
  33. data/lib/fmrest/spyke/spyke_formatter.rb +0 -273
  34. data/lib/fmrest/spyke/validation_error.rb +0 -25
  35. data/lib/fmrest/string_date.rb +0 -220
  36. data/lib/fmrest/token_store.rb +0 -12
  37. data/lib/fmrest/token_store/active_record.rb +0 -74
  38. data/lib/fmrest/token_store/base.rb +0 -25
  39. data/lib/fmrest/token_store/memory.rb +0 -26
  40. data/lib/fmrest/token_store/moneta.rb +0 -41
  41. data/lib/fmrest/token_store/null.rb +0 -20
  42. data/lib/fmrest/token_store/redis.rb +0 -45
  43. data/lib/fmrest/v1.rb +0 -23
  44. data/lib/fmrest/v1/auth.rb +0 -30
  45. data/lib/fmrest/v1/connection.rb +0 -115
  46. data/lib/fmrest/v1/container_fields.rb +0 -114
  47. data/lib/fmrest/v1/dates.rb +0 -81
  48. data/lib/fmrest/v1/paths.rb +0 -47
  49. data/lib/fmrest/v1/raise_errors.rb +0 -57
  50. data/lib/fmrest/v1/token_session.rb +0 -133
  51. data/lib/fmrest/v1/token_store/active_record.rb +0 -13
  52. data/lib/fmrest/v1/token_store/memory.rb +0 -13
  53. data/lib/fmrest/v1/type_coercer.rb +0 -192
  54. data/lib/fmrest/v1/utils.rb +0 -94
  55. data/lib/fmrest/version.rb +0 -5
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FmRest
4
- module TokenStore
5
- autoload :Base, "fmrest/token_store/base"
6
- autoload :Memory, "fmrest/token_store/memory"
7
- autoload :Null, "fmrest/token_store/null"
8
- autoload :ActiveRecord, "fmrest/token_store/active_record"
9
- autoload :Moneta, "fmrest/token_store/moneta"
10
- autoload :Redis, "fmrest/token_store/redis"
11
- end
12
- end
@@ -1,74 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "fmrest/token_store/base"
4
- require "active_record"
5
-
6
- module FmRest
7
- module TokenStore
8
- # Heavily inspired by Moneta's ActiveRecord store:
9
- #
10
- # https://github.com/minad/moneta/blob/master/lib/moneta/adapters/activerecord.rb
11
- #
12
- class ActiveRecord < Base
13
- DEFAULT_TABLE_NAME = "fmrest_session_tokens".freeze
14
-
15
- @connection_lock = ::Mutex.new
16
- class << self
17
- attr_reader :connection_lock
18
- end
19
-
20
- attr_reader :connection_pool, :model
21
-
22
- delegate :with_connection, to: :connection_pool
23
-
24
- def initialize(options = {})
25
- super
26
-
27
- @connection_pool = ::ActiveRecord::Base.connection_pool
28
-
29
- create_table
30
-
31
- @model = Class.new(::ActiveRecord::Base)
32
- @model.table_name = table_name
33
- end
34
-
35
- def delete(key)
36
- model.where(scope: key).delete_all
37
- end
38
-
39
- def load(key)
40
- model.where(scope: key).pluck(:token).first
41
- end
42
-
43
- def store(key, value)
44
- record = model.find_or_initialize_by(scope: key)
45
- record.token = value
46
- record.save!
47
- value
48
- end
49
-
50
- private
51
-
52
- def create_table
53
- with_connection do |conn|
54
- return if conn.table_exists?(table_name)
55
-
56
- # Prevent multiple connections from attempting to create the table simultaneously.
57
- self.class.connection_lock.synchronize do
58
- conn.create_table(table_name, id: false) do |t|
59
- t.string :scope, null: false
60
- t.string :token, null: false
61
- t.datetime :updated_at
62
- end
63
- conn.add_index(table_name, :scope, unique: true)
64
- conn.add_index(table_name, [:scope, :token])
65
- end
66
- end
67
- end
68
-
69
- def table_name
70
- options[:table_name] || DEFAULT_TABLE_NAME
71
- end
72
- end
73
- end
74
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FmRest
4
- module TokenStore
5
- class Base
6
- attr_reader :options
7
-
8
- def initialize(options = {})
9
- @options = options
10
- end
11
-
12
- def load(key)
13
- raise NotImplementedError
14
- end
15
-
16
- def store(key, value)
17
- raise NotImplementedError
18
- end
19
-
20
- def delete(key)
21
- raise NotImplementedError
22
- end
23
- end
24
- end
25
- end
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "fmrest/token_store/base"
4
-
5
- module FmRest
6
- module TokenStore
7
- class Memory < Base
8
- def initialize(*args)
9
- super
10
- @tokens = {}
11
- end
12
-
13
- def delete(key)
14
- @tokens.delete(key)
15
- end
16
-
17
- def load(key)
18
- @tokens[key]
19
- end
20
-
21
- def store(key, value)
22
- @tokens[key] = value
23
- end
24
- end
25
- end
26
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "fmrest/token_store/base"
4
- require "moneta"
5
-
6
- module FmRest
7
- module TokenStore
8
- class Moneta < Base
9
- DEFAULT_ADAPTER = :Memory
10
- DEFAULT_PREFIX = "fmrest-token:".freeze
11
-
12
- attr_reader :moneta
13
-
14
- # @param options [Hash]
15
- # Options to pass to `Moneta.new`
16
- # @option options [Symbol] :adapter (:Memory)
17
- # The Moneta adapter to use
18
- # @option options [String] :prefix (DEFAULT_PREFIX)
19
- # The prefix to use for keys
20
- def initialize(options = {})
21
- options = options.dup
22
- super(options)
23
- adapter = options.delete(:adapter) || DEFAULT_ADAPTER
24
- options[:prefix] ||= DEFAULT_PREFIX
25
- @moneta = ::Moneta.new(adapter, options)
26
- end
27
-
28
- def load(key)
29
- moneta[key]
30
- end
31
-
32
- def delete(key)
33
- moneta.delete(key)
34
- end
35
-
36
- def store(key, value)
37
- moneta[key] = value
38
- end
39
- end
40
- end
41
- end
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "singleton"
4
-
5
- module FmRest
6
- module TokenStore
7
- module Null < Base
8
- include Singleton
9
-
10
- def delete(key)
11
- end
12
-
13
- def load(key)
14
- end
15
-
16
- def store(key, value)
17
- end
18
- end
19
- end
20
- end
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "fmrest/token_store/base"
4
- require "redis" unless defined?(MockRedis)
5
-
6
- module FmRest
7
- module TokenStore
8
- class Redis < Base
9
- DEFAULT_PREFIX = "fmrest-token:".freeze
10
-
11
- STORE_OPTIONS = [:redis, :prefix].freeze
12
-
13
- def initialize(options = {})
14
- super
15
- @redis = @options[:redis] || ::Redis.new(options_for_redis)
16
- @prefix = @options[:prefix] || DEFAULT_PREFIX
17
- end
18
-
19
- def load(key)
20
- @redis.get(prefix_key(key))
21
- end
22
-
23
- def store(key, value)
24
- @redis.set(prefix_key(key), value)
25
- value
26
- end
27
-
28
- def delete(key)
29
- @redis.del(prefix_key(key))
30
- end
31
-
32
- private
33
-
34
- def options_for_redis
35
- @options.dup.tap do |options|
36
- STORE_OPTIONS.each { |opt| options.delete(opt) }
37
- end
38
- end
39
-
40
- def prefix_key(key)
41
- "#{@prefix}#{key}"
42
- end
43
- end
44
- end
45
- end
data/lib/fmrest/v1.rb DELETED
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "fmrest/v1/connection"
4
- require "fmrest/v1/paths"
5
- require "fmrest/v1/container_fields"
6
- require "fmrest/v1/utils"
7
- require "fmrest/v1/dates"
8
- require "fmrest/v1/auth"
9
-
10
- module FmRest
11
- module V1
12
- extend Connection
13
- extend Paths
14
- extend ContainerFields
15
- extend Utils
16
- extend Dates
17
- extend Auth
18
-
19
- autoload :TokenSession, "fmrest/v1/token_session"
20
- autoload :RaiseErrors, "fmrest/v1/raise_errors"
21
- autoload :TypeCoercer, "fmrest/v1/type_coercer"
22
- end
23
- end
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FmRest
4
- module V1
5
- module Auth
6
- # Requests a token through basic auth
7
- #
8
- # @param connection [Faraday] the auth connection to use for
9
- # the request
10
- # @return The token if successful
11
- # @return `false` if authentication failed
12
- def request_auth_token(connection = FmRest::V1.auth_connection)
13
- request_auth_token!(connection)
14
- rescue FmRest::APIError::AccountError
15
- false
16
- end
17
-
18
- # Requests a token through basic auth, raising
19
- # `FmRest::APIError::AccountError` if auth fails
20
- #
21
- # @param (see #request_auth_token)
22
- # @return The token if successful
23
- # @raise [FmRest::APIError::AccountError] if authentication failed
24
- def request_auth_token!(connection = FmRest.V1.auth_connection)
25
- resp = connection.post(V1.session_path)
26
- resp.body["response"]["token"]
27
- end
28
- end
29
- end
30
- end
@@ -1,115 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "uri"
4
-
5
- module FmRest
6
- module V1
7
- module Connection
8
- BASE_PATH = "/fmi/data/v1/databases"
9
-
10
- AUTH_HEADERS = { "Content-Type" => "application/json" }.freeze
11
-
12
- # Builds a complete DAPI Faraday connection with middleware already
13
- # configured to handle authentication, JSON parsing, logging and DAPI
14
- # error handling. A block can be optionally given for additional
15
- # middleware configuration
16
- #
17
- # @option (see #base_connection)
18
- # @return (see #base_connection)
19
- def build_connection(settings = FmRest.default_connection_settings, &block)
20
- settings = ConnectionSettings.wrap(settings)
21
-
22
- base_connection(settings) do |conn|
23
- conn.use RaiseErrors
24
- conn.use TokenSession, settings
25
-
26
- # The EncodeJson and Multipart middlewares only encode the request
27
- # when the content type matches, so we can have them both here and
28
- # still play nice with each other, we just need to set the content
29
- # type to multipart/form-data when we want to submit a container
30
- # field
31
- conn.request :multipart
32
- conn.request :json
33
-
34
- # Allow overriding the default response middleware
35
- if block_given?
36
- yield conn, settings
37
- else
38
- conn.use TypeCoercer, settings
39
- conn.response :json
40
- end
41
-
42
- if settings.log
43
- conn.response :logger, nil, bodies: true, headers: true
44
- end
45
-
46
- conn.adapter Faraday.default_adapter
47
- end
48
- end
49
-
50
- # Builds a Faraday connection to use for DAPI basic auth login
51
- #
52
- # @option (see #base_connection)
53
- # @return (see #base_connection)
54
- def auth_connection(settings = FmRest.default_connection_settings)
55
- settings = ConnectionSettings.wrap(settings)
56
-
57
- base_connection(settings, { headers: AUTH_HEADERS }) do |conn|
58
- conn.use RaiseErrors
59
-
60
- conn.basic_auth settings.username!, settings.password!
61
-
62
- if settings.log
63
- conn.response :logger, nil, bodies: true, headers: true
64
- end
65
-
66
- conn.response :json
67
- conn.adapter Faraday.default_adapter
68
- end
69
- end
70
-
71
- # Builds a base Faraday connection with base URL constructed from
72
- # connection settings and passes it the given block
73
- #
74
- # @option settings [String] :host The hostname for the FM server
75
- # @option settings [String] :database The FM database name
76
- # @option settings [String] :username The username for DAPI authentication
77
- # @option settings [String] :account_name Alias of :username for
78
- # compatibility with Rfm gem
79
- # @option settings [String] :password The password for DAPI authentication
80
- # @option settings [String] :ssl SSL settings to forward to the Faraday
81
- # connection
82
- # @option settings [String] :proxy Proxy options to forward to the Faraday
83
- # connection
84
- # @param faraday_options [Hash] additional options for Faraday object
85
- # @return [Faraday] The new Faraday connection
86
- def base_connection(settings = FmRest.default_connection_settings, faraday_options = nil, &block)
87
- settings = ConnectionSettings.wrap(settings)
88
-
89
- host = settings.host!
90
-
91
- # Default to HTTPS
92
- scheme = "https"
93
-
94
- if host.match(/\Ahttps?:\/\//)
95
- uri = URI(host)
96
- host = uri.hostname
97
- host += ":#{uri.port}" if uri.port != uri.default_port
98
- scheme = uri.scheme
99
- end
100
-
101
- faraday_options = (faraday_options || {}).dup
102
- faraday_options[:ssl] = settings.ssl if settings.ssl?
103
- faraday_options[:proxy] = settings.proxy if settings.proxy?
104
-
105
- database = URI.encode_www_form_component(settings.database!)
106
-
107
- Faraday.new(
108
- "#{scheme}://#{host}#{BASE_PATH}/#{database}/".freeze,
109
- faraday_options,
110
- &block
111
- )
112
- end
113
- end
114
- end
115
- end
@@ -1,114 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module FmRest
4
- module V1
5
- module ContainerFields
6
- DEFAULT_UPLOAD_CONTENT_TYPE = "application/octet-stream".freeze
7
-
8
- # Given a container field URL it tries to fetch it and returns an IO
9
- # object with its body content (see Ruby's OpenURI for how the IO object
10
- # is extended with useful HTTP response information).
11
- #
12
- # This method uses OpenURI instead of Faraday for fetching the actual
13
- # container file.
14
- #
15
- # @raise [FmRest::ContainerFieldError] if any step fails
16
- # @param container_field_url [String] The URL to the container to
17
- # download
18
- # @param base_connection [Faraday::Connection] An optional Faraday
19
- # connection to use as base settings for the container requests, useful
20
- # if you need to set SSL or proxy settings. If given, this connection
21
- # will not be used directly, but rather a new one with copied SSL and
22
- # proxy options. If omitted, `FmRest.default_connection_settings`'s
23
- # `:ssl` and `:proxy` options will be used instead (if available)
24
- # @return [IO] The contents of the container
25
- def fetch_container_data(container_field_url, base_connection = nil)
26
- require "open-uri"
27
-
28
- begin
29
- url = URI(container_field_url)
30
- rescue ::URI::InvalidURIError
31
- raise FmRest::ContainerFieldError, "Invalid container field URL `#{container_field_url}'"
32
- end
33
-
34
- # Make sure we don't try to open anything on the file:/ URI scheme
35
- unless url.scheme.match(/\Ahttps?\Z/)
36
- raise FmRest::ContainerFieldError, "Container URL is not HTTP (#{container_field_url})"
37
- end
38
-
39
- ssl_options = base_connection && base_connection.ssl && base_connection.ssl.to_hash
40
- proxy_options = base_connection && base_connection.proxy && base_connection.proxy.to_hash
41
-
42
- conn =
43
- Faraday.new(nil,
44
- ssl: ssl_options || FmRest.default_connection_settings[:ssl],
45
- proxy: proxy_options || FmRest.default_connection_settings[:proxy]
46
- )
47
-
48
- # Requesting the container URL with no cookie set will respond with a
49
- # redirect and a session cookie
50
- cookie_response = conn.get url
51
-
52
- unless cookie = cookie_response.headers["Set-Cookie"]
53
- raise FmRest::ContainerFieldError, "Container field's initial request didn't return a session cookie, the URL may be stale (try downloading it again immediately after retrieving the record)"
54
- end
55
-
56
- # Now request the URL again with the proper session cookie using
57
- # OpenURI, which wraps the response in an IO object which also responds
58
- # to #content_type
59
- url.open(faraday_connection_to_openuri_options(conn).merge("Cookie" => cookie))
60
- end
61
-
62
- # Handles the core logic of uploading a file into a container field
63
- #
64
- # @param connection [Faraday::Connection] the Faraday connection to use
65
- # @param container_path [String] the path to the container
66
- # @param filename_or_io [String, IO] a path to the file to upload or an
67
- # IO object
68
- # @param options [Hash]
69
- # @option options [String] :content_type (DEFAULT_UPLOAD_CONTENT_TYPE)
70
- # The content type for the uploaded file
71
- # @option options [String] :filename The filename to use for the uploaded
72
- # file, defaults to `filename_or_io.original_filename` if available
73
- def upload_container_data(connection, container_path, filename_or_io, options = {})
74
- content_type = options[:content_type] || DEFAULT_UPLOAD_CONTENT_TYPE
75
-
76
- connection.post do |request|
77
- request.url container_path
78
- request.headers['Content-Type'] = ::Faraday::Request::Multipart.mime_type
79
-
80
- filename = options[:filename] || filename_or_io.try(:original_filename)
81
-
82
- request.body = { upload: Faraday::UploadIO.new(filename_or_io, content_type, filename) }
83
- end
84
- end
85
-
86
- private
87
-
88
- # Copies a Faraday::Connection's relevant options to
89
- # OpenURI::OpenRead#open format
90
- #
91
- def faraday_connection_to_openuri_options(conn)
92
- openuri_opts = {}
93
-
94
- if !conn.ssl.empty?
95
- openuri_opts[:ssl_verify_mode] =
96
- conn.ssl.fetch(:verify, true) ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
97
-
98
- openuri_opts[:ssl_ca_cert] = conn.ssl.cert_store if conn.ssl.cert_store
99
- end
100
-
101
- if conn.proxy && !conn.proxy.empty?
102
- if conn.proxy.user && conn.proxy.password
103
- openuri_opts[:proxy_http_basic_authentication] =
104
- [conn.proxy.uri.tap { |u| u.userinfo = ""}, conn.proxy.user, conn.proxy.password]
105
- else
106
- openuri_opts[:proxy] = conn.proxy.uri
107
- end
108
- end
109
-
110
- openuri_opts
111
- end
112
- end
113
- end
114
- end