magic-admin 0.0.0 → 0.1.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.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +42 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
- data/.github/ISSUE_TEMPLATE/question.md +23 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +23 -0
- data/.gitignore +7 -0
- data/.rspec +6 -0
- data/.rubocop.yml +45 -0
- data/CHANGELOG.md +17 -0
- data/CONTRIBUTING.md +142 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +73 -0
- data/bin/magic-console +14 -0
- data/lib/magic-admin.rb +135 -0
- data/lib/magic-admin/config.rb +71 -0
- data/lib/magic-admin/errors.rb +98 -0
- data/lib/magic-admin/http/client.rb +136 -0
- data/lib/magic-admin/http/request.rb +89 -0
- data/lib/magic-admin/http/response.rb +95 -0
- data/lib/magic-admin/resource/token.rb +146 -0
- data/lib/magic-admin/resource/user.rb +130 -0
- data/lib/magic-admin/util.rb +61 -0
- data/lib/magic-admin/version.rb +5 -0
- data/magic-admin.gemspec +36 -0
- data/test/http/client_test.rb +79 -0
- data/test/http/request_test.rb +52 -0
- data/test/http/response_test.rb +192 -0
- data/test/magic_test.rb +124 -0
- data/test/resource/token_test.rb +187 -0
- data/test/resource/user_test.rb +98 -0
- data/test/spec_helper.rb +48 -0
- data/test/util_test.rb +42 -0
- metadata +140 -15
data/bin/magic-console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "irb"
|
5
|
+
require "irb/completion"
|
6
|
+
require "byebug"
|
7
|
+
require "#{::File.dirname(__FILE__)}/../lib/magic-admin"
|
8
|
+
|
9
|
+
# Config IRB to enable --simple-prompt and auto indent
|
10
|
+
IRB.conf[:PROMPT_MODE] = :SIMPLE
|
11
|
+
IRB.conf[:AUTO_INDENT] = true
|
12
|
+
|
13
|
+
puts "Loaded gem 'magic-admin'"
|
14
|
+
IRB.start
|
data/lib/magic-admin.rb
CHANGED
@@ -0,0 +1,135 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Magic Ruby bindings
|
4
|
+
require "etc"
|
5
|
+
require "json"
|
6
|
+
require "net/http"
|
7
|
+
require "uri"
|
8
|
+
require "base64"
|
9
|
+
require "eth"
|
10
|
+
|
11
|
+
# Version
|
12
|
+
require "magic-admin/version"
|
13
|
+
|
14
|
+
# Magic API Classes
|
15
|
+
require "magic-admin/util"
|
16
|
+
require "magic-admin/config"
|
17
|
+
require "magic-admin/errors"
|
18
|
+
|
19
|
+
# HTTP Classes
|
20
|
+
require "magic-admin/http/client"
|
21
|
+
require "magic-admin/http/request"
|
22
|
+
require "magic-admin/http/response"
|
23
|
+
|
24
|
+
# Magic Resource Classes
|
25
|
+
require "magic-admin/resource/token"
|
26
|
+
require "magic-admin/resource/user"
|
27
|
+
|
28
|
+
# Magic Class to access resources
|
29
|
+
class Magic
|
30
|
+
RETRIES = 3
|
31
|
+
TIMEOUT = 5
|
32
|
+
BACKOFF = 0.02
|
33
|
+
|
34
|
+
# attribute reader for magic api secret key
|
35
|
+
attr_reader :secret_key
|
36
|
+
|
37
|
+
# attribute reader for magic http client
|
38
|
+
attr_reader :http_client
|
39
|
+
|
40
|
+
# The constructor allows you to specify your own API secret key
|
41
|
+
# and HTTP request strategy when your application interacting
|
42
|
+
# with the Magic API.
|
43
|
+
#
|
44
|
+
# It will automatically configure required arguments
|
45
|
+
# using the following environment variables
|
46
|
+
# MAGIC_API_SECRET_KEY
|
47
|
+
# MAGIC_API_RETRIES
|
48
|
+
# MAGIC_API_TIMEOUT
|
49
|
+
# MAGIC_API_BACKOFF
|
50
|
+
#
|
51
|
+
# Arguments:
|
52
|
+
# api_secret_key: Your API Secret Key retrieved from the Magic Dashboard.
|
53
|
+
# retries: Total number of retries to allow.
|
54
|
+
# timeout: A period of time the request is going to wait for a response.
|
55
|
+
# backoff: A backoff factor to apply between retry attempts.
|
56
|
+
#
|
57
|
+
# Returns:
|
58
|
+
# A Magic object that provides access to all the supported resources.
|
59
|
+
#
|
60
|
+
# Examples:
|
61
|
+
#
|
62
|
+
# Magic.new
|
63
|
+
# Magic.new api_secret_key: "SECRET_KEY>"
|
64
|
+
# Magic.new api_secret_key: "SECRET_KEY>",
|
65
|
+
# retries: 2,
|
66
|
+
# timeout: 2,
|
67
|
+
# backoff: 0.2
|
68
|
+
#
|
69
|
+
#
|
70
|
+
|
71
|
+
def initialize(api_secret_key: nil,
|
72
|
+
retries: nil,
|
73
|
+
timeout: nil,
|
74
|
+
backoff: nil)
|
75
|
+
secret_key!(api_secret_key)
|
76
|
+
http_client!(retries, timeout, backoff)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Description:
|
80
|
+
# Method provides you User object
|
81
|
+
# for interacting with the Magic API.
|
82
|
+
#
|
83
|
+
# Returns:
|
84
|
+
# A User object that provides access to
|
85
|
+
# all the supported resources.
|
86
|
+
|
87
|
+
def user
|
88
|
+
MagicAdmin::Resource::User.new(self)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Description:
|
92
|
+
# Method provides you Token object
|
93
|
+
# for various utility methods of Token.
|
94
|
+
#
|
95
|
+
# Returns:
|
96
|
+
# A Token object that provides access to
|
97
|
+
# all the supported resources.
|
98
|
+
|
99
|
+
def token
|
100
|
+
MagicAdmin::Resource::Token.new
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def secret_key?
|
106
|
+
!(secret_key.nil? || secret_key.empty?)
|
107
|
+
end
|
108
|
+
|
109
|
+
def secret_key!(api_secret_key)
|
110
|
+
@secret_key = api_secret_key || ENV["MAGIC_API_SECRET_KEY"]
|
111
|
+
message = "Magic api secret key was not found."
|
112
|
+
|
113
|
+
raise MagicAdmin::MagicError, message unless secret_key?
|
114
|
+
end
|
115
|
+
|
116
|
+
def configure_retries(retries)
|
117
|
+
retries || ENV["MAGIC_API_RETRIES"] || RETRIES
|
118
|
+
end
|
119
|
+
|
120
|
+
def configure_timeout(timeout)
|
121
|
+
timeout || ENV["MAGIC_API_TIMEOUT"] || TIMEOUT
|
122
|
+
end
|
123
|
+
|
124
|
+
def configure_backoff(backoff)
|
125
|
+
backoff || ENV["MAGIC_API_BACKOFF"] || BACKOFF
|
126
|
+
end
|
127
|
+
|
128
|
+
def http_client!(retries, timeout, backoff)
|
129
|
+
@http_client = MagicAdmin::Http::Client
|
130
|
+
.new(MagicAdmin::Config.api_base,
|
131
|
+
configure_retries(retries),
|
132
|
+
configure_timeout(timeout),
|
133
|
+
configure_backoff(backoff))
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MagicAdmin
|
4
|
+
|
5
|
+
module Config
|
6
|
+
|
7
|
+
# Description:
|
8
|
+
# Method provides you platform information
|
9
|
+
#
|
10
|
+
# Returns:
|
11
|
+
# user platform information
|
12
|
+
def self.platform
|
13
|
+
RUBY_PLATFORM
|
14
|
+
end
|
15
|
+
|
16
|
+
# Description:
|
17
|
+
# Method provides you sdk programming language
|
18
|
+
#
|
19
|
+
# Returns:
|
20
|
+
# sdk programming language
|
21
|
+
def self.language
|
22
|
+
"ruby"
|
23
|
+
end
|
24
|
+
|
25
|
+
# Description:
|
26
|
+
# Method provides you sdk programming language version
|
27
|
+
#
|
28
|
+
# Returns:
|
29
|
+
# sdk programming language version
|
30
|
+
def self.language_version
|
31
|
+
RUBY_VERSION
|
32
|
+
end
|
33
|
+
|
34
|
+
# Description:
|
35
|
+
# Method provides you installation machine user_name
|
36
|
+
#
|
37
|
+
# Returns:
|
38
|
+
# installation machine user_name
|
39
|
+
def self.user_name
|
40
|
+
Etc.getpwnam(Etc.getlogin).gecos.split(/,/).first
|
41
|
+
end
|
42
|
+
|
43
|
+
# Description:
|
44
|
+
# Method provides you sdk publisher name
|
45
|
+
#
|
46
|
+
# Returns:
|
47
|
+
# sdk publisher name
|
48
|
+
def self.publisher
|
49
|
+
"MagicLabs"
|
50
|
+
end
|
51
|
+
|
52
|
+
# Description:
|
53
|
+
# Method provides you api base url
|
54
|
+
#
|
55
|
+
# Returns:
|
56
|
+
# api base url
|
57
|
+
def self.api_base
|
58
|
+
"https://api.magic.link"
|
59
|
+
end
|
60
|
+
|
61
|
+
# Description:
|
62
|
+
# Method provides you nbf grace period
|
63
|
+
#
|
64
|
+
# Returns:
|
65
|
+
# nbf grace period
|
66
|
+
def self.nbf_grace_period
|
67
|
+
300
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MagicAdmin
|
4
|
+
|
5
|
+
# MagicAdmin::MagicError class
|
6
|
+
class MagicError < StandardError
|
7
|
+
|
8
|
+
# attribute reader for error message
|
9
|
+
attr_reader :message
|
10
|
+
|
11
|
+
# Description:
|
12
|
+
# The constructor allows you to specify error message
|
13
|
+
#
|
14
|
+
# Arguments:
|
15
|
+
# message: error message.
|
16
|
+
def initialize(message)
|
17
|
+
@message = message
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# MagicAdmin::MagicError class
|
22
|
+
class DIDTokenError < MagicError; end
|
23
|
+
|
24
|
+
# RequestError Class
|
25
|
+
class RequestError < MagicError
|
26
|
+
# attribute reader for http response status
|
27
|
+
attr_reader :http_status
|
28
|
+
|
29
|
+
# attribute reader for http response code
|
30
|
+
attr_reader :http_code
|
31
|
+
|
32
|
+
# attribute reader for http response
|
33
|
+
attr_reader :http_response
|
34
|
+
|
35
|
+
# attribute reader for http response message
|
36
|
+
attr_reader :http_message
|
37
|
+
|
38
|
+
# attribute reader for http response error code
|
39
|
+
attr_reader :http_error_code
|
40
|
+
|
41
|
+
# attribute reader for http request params
|
42
|
+
attr_reader :http_request_params
|
43
|
+
|
44
|
+
# attribute reader for http request data
|
45
|
+
attr_reader :http_request_data
|
46
|
+
|
47
|
+
# attribute reader for http request method
|
48
|
+
attr_reader :http_method
|
49
|
+
|
50
|
+
# Description:
|
51
|
+
# The constructor allows you to specify error message
|
52
|
+
# and HTTP request and response info
|
53
|
+
#
|
54
|
+
# Arguments:
|
55
|
+
# message: request error message.
|
56
|
+
# opt: hash of request and response info of following keys:
|
57
|
+
# http_status
|
58
|
+
# http_code
|
59
|
+
# http_response
|
60
|
+
# http_message
|
61
|
+
# http_error_code
|
62
|
+
# http_request_params
|
63
|
+
# http_request_data
|
64
|
+
# http_method
|
65
|
+
# Returns:
|
66
|
+
# A Error object that provides additional error info for magic api call.
|
67
|
+
def initialize(message, opt = {})
|
68
|
+
super(message)
|
69
|
+
@http_status = opt[:http_status]
|
70
|
+
@http_code = opt[:http_code]
|
71
|
+
@http_response = opt[:http_response]
|
72
|
+
@http_message = opt[:http_message]
|
73
|
+
@http_error_code = opt[:http_error_code]
|
74
|
+
@http_request_params = opt[:http_request_params]
|
75
|
+
@http_request_data = opt[:http_request_data]
|
76
|
+
@http_method = opt[:http_method]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# MagicAdmin::MagicError class
|
81
|
+
class APIConnectionError < RequestError; end
|
82
|
+
|
83
|
+
# MagicAdmin::RateLimitingError class
|
84
|
+
class RateLimitingError < RequestError; end
|
85
|
+
|
86
|
+
# MagicAdmin::BadRequestError class
|
87
|
+
class BadRequestError < RequestError; end
|
88
|
+
|
89
|
+
# MagicAdmin::AuthenticationError class
|
90
|
+
class AuthenticationError < RequestError; end
|
91
|
+
|
92
|
+
# MagicAdmin::ForbiddenError class
|
93
|
+
class ForbiddenError < RequestError; end
|
94
|
+
|
95
|
+
# MagicAdmin::APIError class
|
96
|
+
class APIError < RequestError; end
|
97
|
+
|
98
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MagicAdmin
|
4
|
+
|
5
|
+
module Http
|
6
|
+
|
7
|
+
# Http Client and its methods are accessible
|
8
|
+
# on the Magic instance by the http_client attribute.
|
9
|
+
# It provides methods to interact with the http client.
|
10
|
+
class Client
|
11
|
+
|
12
|
+
# attribute reader for magic api max retries
|
13
|
+
attr_reader :retries
|
14
|
+
|
15
|
+
# attribute reader for magic api backoff factor
|
16
|
+
attr_reader :backoff
|
17
|
+
|
18
|
+
# attribute reader for magic api timeout
|
19
|
+
attr_reader :timeout
|
20
|
+
|
21
|
+
# attribute reader for magic api base api url
|
22
|
+
attr_reader :base_url
|
23
|
+
|
24
|
+
# attribute reader for magic http request class
|
25
|
+
attr_reader :http_request
|
26
|
+
|
27
|
+
# attribute reader for magic http response class
|
28
|
+
attr_reader :http_response
|
29
|
+
|
30
|
+
# The constructor allows you to configure HTTP request strategy
|
31
|
+
# when your application interacting with the Magic API
|
32
|
+
#
|
33
|
+
# Arguments:
|
34
|
+
# api_base: api base url.
|
35
|
+
# req_retries: Total number of retries to allow.
|
36
|
+
# req_timeout: A period of time the request is going
|
37
|
+
# to wait for a response.
|
38
|
+
# req_backoff: A backoff factor to apply between retry attempts.
|
39
|
+
#
|
40
|
+
# Returns:
|
41
|
+
# A Http Client object that provides access to
|
42
|
+
# all the supported resources.
|
43
|
+
#
|
44
|
+
# Examples:
|
45
|
+
# Client.new(<api_base>, <req_retries>, <req_timeout>, <req_backoff>)
|
46
|
+
def initialize(api_base, req_retries, req_timeout, req_backoff)
|
47
|
+
@retries = req_retries.to_i
|
48
|
+
@backoff = req_backoff.to_f
|
49
|
+
@timeout = req_timeout.to_f
|
50
|
+
@base_url = api_base
|
51
|
+
@http_request = Request
|
52
|
+
@http_response = Response
|
53
|
+
end
|
54
|
+
|
55
|
+
# Description:
|
56
|
+
# call create http request and provide response
|
57
|
+
#
|
58
|
+
# Arguments:
|
59
|
+
# method: http method
|
60
|
+
# path: api path
|
61
|
+
# options: a hash contains params and headers for request
|
62
|
+
#
|
63
|
+
# Returns:
|
64
|
+
# A response object
|
65
|
+
def call(method, path, options)
|
66
|
+
url = URI("#{base_url}#{path}")
|
67
|
+
req = http_request.request(method, url, options)
|
68
|
+
resp = backoff_retries(retries, backoff) do
|
69
|
+
base_client(url, req, timeout)
|
70
|
+
end
|
71
|
+
http_response.from_net_http(resp, req)
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
# Description:
|
77
|
+
# backoff_retries implementations of retries strategy
|
78
|
+
# with backoff factor
|
79
|
+
#
|
80
|
+
# Arguments:
|
81
|
+
# max_retries: max retries count
|
82
|
+
# backoff_factor: backoff factor for configure delay in retries
|
83
|
+
# block: block of code that uses retries backoff strategy
|
84
|
+
#
|
85
|
+
# Returns:
|
86
|
+
# it returns, block return object
|
87
|
+
def backoff_retries(max_retries, backoff_factor, &block)
|
88
|
+
attempts = 0
|
89
|
+
begin
|
90
|
+
attempts += 1
|
91
|
+
block.call
|
92
|
+
rescue StandardError => e
|
93
|
+
raise e if attempts >= max_retries
|
94
|
+
|
95
|
+
sleep_seconds = backoff_factor * (2**(attempts - 1))
|
96
|
+
sleep sleep_seconds
|
97
|
+
retry
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Description:
|
102
|
+
# use_ssl? provide true if url uses https protocol otherwise false
|
103
|
+
#
|
104
|
+
# Arguments:
|
105
|
+
# url: max retries count
|
106
|
+
#
|
107
|
+
# Returns:
|
108
|
+
# boolean value
|
109
|
+
def use_ssl?(url)
|
110
|
+
url.scheme == "https"
|
111
|
+
end
|
112
|
+
|
113
|
+
# Description:
|
114
|
+
# base_client is base http request/response mechanism
|
115
|
+
#
|
116
|
+
# Arguments:
|
117
|
+
# url: request url
|
118
|
+
# request: request object
|
119
|
+
# read_timeout: read_timeout for request
|
120
|
+
#
|
121
|
+
# Returns:
|
122
|
+
# response
|
123
|
+
def base_client(url, request, read_timeout)
|
124
|
+
begin
|
125
|
+
Net::HTTP.start(url.host, url.port, use_ssl: use_ssl?(url)) do |http|
|
126
|
+
http.read_timeout = read_timeout
|
127
|
+
http.request(request)
|
128
|
+
end
|
129
|
+
rescue SocketError => e
|
130
|
+
raise APIConnectionError.new(e.message)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|