accessgrid 0.1.2 → 0.1.3
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/README.md +62 -33
- data/lib/accessgrid/access_cards.rb +30 -10
- data/lib/accessgrid/console.rb +31 -15
- data/lib/accessgrid/version.rb +1 -1
- data/lib/accessgrid.rb +81 -9
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2f95e77022beec6a20cd5a55350ff8cd5ad15233ec74d13b22d49587d8fafed9
|
4
|
+
data.tar.gz: 9c20b6923726a61c5865b9b58c7f55fe008e7756e0d99f800e2a6efaca3e18aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5d48b2324e989be2ecb79c152b27cda9aae991990aa3de176cf080aee89ffed78c262fd06116fdfa3eb65da719031554a03065e7c6862d5c27c9329bc6104020
|
7
|
+
data.tar.gz: 9d5585bc8bccb446f0432fa6116d30ddfbac4a358638c5a3b9ee31e7f0879dfe3a55e46cde0793a282c8abc10cec12d0689ceb9a9a09ca75ea53193afce7eceb
|
data/README.md
CHANGED
@@ -37,14 +37,14 @@ client = AccessGrid.new(account_id, secret_key)
|
|
37
37
|
|
38
38
|
### Access Cards
|
39
39
|
|
40
|
-
####
|
40
|
+
#### Issue a new card
|
41
41
|
|
42
42
|
```ruby
|
43
|
-
card = client.access_cards.
|
44
|
-
card_template_id:
|
43
|
+
card = client.access_cards.issue(
|
44
|
+
card_template_id: card_template_id,
|
45
45
|
employee_id: "123456789",
|
46
|
+
card_number: "16187",
|
46
47
|
tag_id: "DDEADB33FB00B5",
|
47
|
-
allow_on_multiple_devices: true,
|
48
48
|
full_name: "Employee name",
|
49
49
|
email: "employee@yourwebsite.com",
|
50
50
|
phone_number: "+19547212241",
|
@@ -54,6 +54,13 @@ card = client.access_cards.provision(
|
|
54
54
|
employee_photo: "[image_in_base64_encoded_format]"
|
55
55
|
)
|
56
56
|
|
57
|
+
# Provision is an alias for issue (for backwards compatibility)
|
58
|
+
card = client.access_cards.provision(
|
59
|
+
card_template_id: card_template_id,
|
60
|
+
employee_id: "123456789",
|
61
|
+
# ...other parameters
|
62
|
+
)
|
63
|
+
|
57
64
|
puts "Install URL: #{card.url}"
|
58
65
|
```
|
59
66
|
|
@@ -61,32 +68,41 @@ puts "Install URL: #{card.url}"
|
|
61
68
|
|
62
69
|
```ruby
|
63
70
|
card = client.access_cards.update(
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
71
|
+
"0xc4rd1d",
|
72
|
+
{
|
73
|
+
employee_id: "987654321",
|
74
|
+
full_name: "Updated Employee Name",
|
75
|
+
classification: "contractor",
|
76
|
+
expiration_date: "2025-02-22T21:04:03.664Z",
|
77
|
+
employee_photo: "[image_in_base64_encoded_format]"
|
78
|
+
}
|
70
79
|
)
|
71
80
|
```
|
72
81
|
|
82
|
+
#### List cards
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
# List all cards for a template
|
86
|
+
cards = client.access_cards.list("template_id")
|
87
|
+
|
88
|
+
# List cards filtered by state
|
89
|
+
active_cards = client.access_cards.list("template_id", "active")
|
90
|
+
```
|
91
|
+
|
73
92
|
#### Manage card states
|
74
93
|
|
75
94
|
```ruby
|
76
95
|
# Suspend a card
|
77
|
-
client.access_cards.suspend(
|
78
|
-
card_id: "0xc4rd1d"
|
79
|
-
)
|
96
|
+
client.access_cards.suspend("0xc4rd1d")
|
80
97
|
|
81
98
|
# Resume a card
|
82
|
-
client.access_cards.resume(
|
83
|
-
card_id: "0xc4rd1d"
|
84
|
-
)
|
99
|
+
client.access_cards.resume("0xc4rd1d")
|
85
100
|
|
86
101
|
# Unlink a card
|
87
|
-
client.access_cards.unlink(
|
88
|
-
|
89
|
-
|
102
|
+
client.access_cards.unlink("0xc4rd1d")
|
103
|
+
|
104
|
+
# Delete a card
|
105
|
+
client.access_cards.delete("0xc4rd1d")
|
90
106
|
```
|
91
107
|
|
92
108
|
### Enterprise Console
|
@@ -124,17 +140,19 @@ template = client.console.create_template(
|
|
124
140
|
|
125
141
|
```ruby
|
126
142
|
template = client.console.update_template(
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
143
|
+
"0xd3adb00b5",
|
144
|
+
{
|
145
|
+
name: "Updated Employee NFC key",
|
146
|
+
allow_on_multiple_devices: true,
|
147
|
+
watch_count: 2,
|
148
|
+
iphone_count: 3,
|
149
|
+
support_info: {
|
150
|
+
support_url: "https://help.yourcompany.com",
|
151
|
+
support_phone_number: "+1-555-123-4567",
|
152
|
+
support_email: "support@yourcompany.com",
|
153
|
+
privacy_policy_url: "https://yourcompany.com/privacy",
|
154
|
+
terms_and_conditions_url: "https://yourcompany.com/terms"
|
155
|
+
}
|
138
156
|
}
|
139
157
|
)
|
140
158
|
```
|
@@ -142,14 +160,24 @@ template = client.console.update_template(
|
|
142
160
|
#### Read a template
|
143
161
|
|
144
162
|
```ruby
|
145
|
-
template = client.console.read_template(
|
146
|
-
card_template_id: "0xd3adb00b5"
|
147
|
-
)
|
163
|
+
template = client.console.read_template("0xd3adb00b5")
|
148
164
|
```
|
149
165
|
|
150
166
|
#### Get event logs
|
151
167
|
|
152
168
|
```ruby
|
169
|
+
# New method
|
170
|
+
logs = client.console.get_logs(
|
171
|
+
"0xd3adb00b5",
|
172
|
+
{
|
173
|
+
device: "mobile", # "mobile" or "watch"
|
174
|
+
start_date: (Time.now - 30*24*60*60).iso8601,
|
175
|
+
end_date: Time.now.iso8601,
|
176
|
+
event_type: "install"
|
177
|
+
}
|
178
|
+
)
|
179
|
+
|
180
|
+
# Legacy method still works
|
153
181
|
events = client.console.event_log(
|
154
182
|
card_template_id: "0xd3adb00b5",
|
155
183
|
filters: {
|
@@ -179,6 +207,7 @@ The SDK throws specific errors for various scenarios:
|
|
179
207
|
- `AccessGrid::AuthenticationError` - Invalid credentials
|
180
208
|
- `AccessGrid::ResourceNotFoundError` - Requested resource not found
|
181
209
|
- `AccessGrid::ValidationError` - Invalid parameters
|
210
|
+
- `AccessGrid::AccessGridError` - Base exception for AccessGrid-specific errors
|
182
211
|
- `AccessGrid::Error` - Generic API errors
|
183
212
|
|
184
213
|
Example error handling:
|
@@ -5,16 +5,26 @@ module AccessGrid
|
|
5
5
|
@client = client
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
8
|
+
def issue(params)
|
9
9
|
response = @client.make_request(:post, '/v1/key-cards', params)
|
10
10
|
Card.new(response)
|
11
11
|
end
|
12
|
+
|
13
|
+
# Alias provision to issue for backward compatibility
|
14
|
+
alias provision issue
|
12
15
|
|
13
|
-
def update(params)
|
14
|
-
|
15
|
-
response = @client.make_request(:put, "/v1/key-cards/#{card_id}", params)
|
16
|
+
def update(card_id, params)
|
17
|
+
response = @client.make_request(:patch, "/v1/key-cards/#{card_id}", params)
|
16
18
|
Card.new(response)
|
17
19
|
end
|
20
|
+
|
21
|
+
def list(template_id, state = nil)
|
22
|
+
params = { template_id: template_id }
|
23
|
+
params[:state] = state if state
|
24
|
+
|
25
|
+
response = @client.make_request(:get, '/v1/key-cards', nil, params)
|
26
|
+
response.fetch('keys', []).map { |item| Card.new(item) }
|
27
|
+
end
|
18
28
|
|
19
29
|
private def manage_state(card_id, action)
|
20
30
|
response = @client.make_request(
|
@@ -25,16 +35,20 @@ module AccessGrid
|
|
25
35
|
Card.new(response)
|
26
36
|
end
|
27
37
|
|
28
|
-
def suspend(
|
29
|
-
manage_state(
|
38
|
+
def suspend(card_id)
|
39
|
+
manage_state(card_id, 'suspend')
|
30
40
|
end
|
31
41
|
|
32
|
-
def resume(
|
33
|
-
manage_state(
|
42
|
+
def resume(card_id)
|
43
|
+
manage_state(card_id, 'resume')
|
34
44
|
end
|
35
45
|
|
36
|
-
def unlink(
|
37
|
-
manage_state(
|
46
|
+
def unlink(card_id)
|
47
|
+
manage_state(card_id, 'unlink')
|
48
|
+
end
|
49
|
+
|
50
|
+
def delete(card_id)
|
51
|
+
manage_state(card_id, 'delete')
|
38
52
|
end
|
39
53
|
end
|
40
54
|
|
@@ -48,5 +62,11 @@ module AccessGrid
|
|
48
62
|
@full_name = data['full_name']
|
49
63
|
@expiration_date = data['expiration_date']
|
50
64
|
end
|
65
|
+
|
66
|
+
def to_s
|
67
|
+
"Card(name='#{@full_name}', id='#{@id}', state='#{@state}')"
|
68
|
+
end
|
69
|
+
|
70
|
+
alias inspect to_s
|
51
71
|
end
|
52
72
|
end
|
data/lib/accessgrid/console.rb
CHANGED
@@ -11,22 +11,33 @@ module AccessGrid
|
|
11
11
|
Template.new(response)
|
12
12
|
end
|
13
13
|
|
14
|
-
def update_template(params)
|
15
|
-
card_template_id = params.delete(:card_template_id)
|
14
|
+
def update_template(template_id, params)
|
16
15
|
transformed_params = transform_template_params(params)
|
17
|
-
response = @client.make_request(:put, "/v1/console/card-templates/#{
|
16
|
+
response = @client.make_request(:put, "/v1/console/card-templates/#{template_id}", transformed_params)
|
18
17
|
Template.new(response)
|
19
18
|
end
|
20
19
|
|
21
|
-
def read_template(
|
22
|
-
response = @client.make_request(:get, "/v1/console/card-templates/#{
|
20
|
+
def read_template(template_id)
|
21
|
+
response = @client.make_request(:get, "/v1/console/card-templates/#{template_id}")
|
23
22
|
Template.new(response)
|
24
23
|
end
|
25
24
|
|
25
|
+
def get_logs(template_id, params = {})
|
26
|
+
response = @client.make_request(:get, "/v1/console/card-templates/#{template_id}/logs", nil, params)
|
27
|
+
|
28
|
+
# Return full response to match Python's behavior
|
29
|
+
if response['logs']
|
30
|
+
response['logs'] = response['logs'].map { |log| Event.new(log) }
|
31
|
+
end
|
32
|
+
|
33
|
+
response
|
34
|
+
end
|
35
|
+
|
36
|
+
# Keep event_log for backwards compatibility
|
26
37
|
def event_log(params)
|
27
|
-
|
28
|
-
response =
|
29
|
-
response['logs']
|
38
|
+
template_id = params.delete(:card_template_id)
|
39
|
+
response = get_logs(template_id, params)
|
40
|
+
response['logs'] || []
|
30
41
|
end
|
31
42
|
|
32
43
|
private
|
@@ -49,18 +60,23 @@ module AccessGrid
|
|
49
60
|
end
|
50
61
|
|
51
62
|
class Template
|
52
|
-
attr_reader :id, :name, :platform, :protocol, :
|
53
|
-
:
|
63
|
+
attr_reader :id, :name, :platform, :protocol, :use_case, :created_at,
|
64
|
+
:last_published_at, :issued_keys_count, :active_keys_count,
|
65
|
+
:allowed_device_counts, :support_settings, :terms_settings, :style_settings
|
54
66
|
|
55
67
|
def initialize(data)
|
56
68
|
@id = data['id']
|
57
69
|
@name = data['name']
|
58
70
|
@platform = data['platform']
|
59
71
|
@protocol = data['protocol']
|
60
|
-
@
|
61
|
-
@
|
62
|
-
@
|
63
|
-
@
|
72
|
+
@use_case = data['use_case']
|
73
|
+
@created_at = data['created_at']
|
74
|
+
@last_published_at = data['last_published_at']
|
75
|
+
@issued_keys_count = data['issued_keys_count']
|
76
|
+
@active_keys_count = data['active_keys_count']
|
77
|
+
@allowed_device_counts = data['allowed_device_counts']
|
78
|
+
@support_settings = data['support_settings']
|
79
|
+
@terms_settings = data['terms_settings']
|
64
80
|
@style_settings = data['style_settings']
|
65
81
|
end
|
66
82
|
end
|
@@ -71,7 +87,7 @@ module AccessGrid
|
|
71
87
|
def initialize(data)
|
72
88
|
@type = data['event']
|
73
89
|
@timestamp = data['created_at']
|
74
|
-
@user_id = data['metadata']['user_id']
|
90
|
+
@user_id = data['metadata']['user_id'] if data['metadata'] && data['metadata']['user_id']
|
75
91
|
@ip_address = data['ip_address']
|
76
92
|
@user_agent = data['user_agent']
|
77
93
|
@metadata = data['metadata']
|
data/lib/accessgrid/version.rb
CHANGED
data/lib/accessgrid.rb
CHANGED
@@ -15,13 +15,24 @@ module AccessGrid
|
|
15
15
|
class ResourceNotFoundError < Error; end
|
16
16
|
class ValidationError < Error; end
|
17
17
|
|
18
|
+
# Additional error classes to match Python version
|
19
|
+
class AccessGridError < Error; end
|
20
|
+
|
18
21
|
class Client
|
19
22
|
attr_reader :account_id, :api_secret, :api_host
|
20
23
|
|
21
24
|
def initialize(account_id, api_secret, api_host = 'https://api.accessgrid.com')
|
25
|
+
if account_id.nil? || account_id.empty?
|
26
|
+
raise ArgumentError, "Account ID is required"
|
27
|
+
end
|
28
|
+
|
29
|
+
if api_secret.nil? || api_secret.empty?
|
30
|
+
raise ArgumentError, "API Secret is required"
|
31
|
+
end
|
32
|
+
|
22
33
|
@account_id = account_id
|
23
34
|
@api_secret = api_secret
|
24
|
-
@api_host = api_host
|
35
|
+
@api_host = api_host.chomp('/')
|
25
36
|
end
|
26
37
|
|
27
38
|
def access_cards
|
@@ -32,8 +43,14 @@ module AccessGrid
|
|
32
43
|
@console ||= Console.new(self)
|
33
44
|
end
|
34
45
|
|
35
|
-
def make_request(method, path, body = nil)
|
46
|
+
def make_request(method, path, body = nil, params = nil)
|
36
47
|
uri = URI.parse("#{api_host}#{path}")
|
48
|
+
|
49
|
+
# Add query parameters if present
|
50
|
+
if params && !params.empty?
|
51
|
+
uri.query = URI.encode_www_form(params)
|
52
|
+
end
|
53
|
+
|
37
54
|
http = Net::HTTP.new(uri.host, uri.port)
|
38
55
|
http.use_ssl = uri.scheme == 'https'
|
39
56
|
|
@@ -45,6 +62,8 @@ module AccessGrid
|
|
45
62
|
Net::HTTP::Post.new(uri.request_uri)
|
46
63
|
when :put
|
47
64
|
Net::HTTP::Put.new(uri.request_uri)
|
65
|
+
when :patch
|
66
|
+
Net::HTTP::Patch.new(uri.request_uri)
|
48
67
|
else
|
49
68
|
raise ArgumentError, "Unsupported HTTP method: #{method}"
|
50
69
|
end
|
@@ -52,12 +71,56 @@ module AccessGrid
|
|
52
71
|
# Set headers
|
53
72
|
request['Content-Type'] = 'application/json'
|
54
73
|
request['X-ACCT-ID'] = account_id
|
74
|
+
request['User-Agent'] = "accessgrid.rb @ v#{AccessGrid::VERSION}"
|
75
|
+
|
76
|
+
# Extract resource ID from the path if needed for signature
|
77
|
+
resource_id = nil
|
78
|
+
if method == :get || (method == :post && (body.nil? || body.empty?))
|
79
|
+
parts = path.strip.split('/')
|
80
|
+
if parts.length >= 2
|
81
|
+
if ['suspend', 'resume', 'unlink', 'delete'].include?(parts.last)
|
82
|
+
resource_id = parts[-2]
|
83
|
+
else
|
84
|
+
resource_id = parts.last
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Handle signature generation
|
90
|
+
if method == :get || (method == :post && (body.nil? || body.empty?))
|
91
|
+
payload = resource_id ? { id: resource_id }.to_json : '{}'
|
92
|
+
|
93
|
+
# Include sig_payload in query params if needed
|
94
|
+
if resource_id
|
95
|
+
if params.nil?
|
96
|
+
params = {}
|
97
|
+
end
|
98
|
+
params[:sig_payload] = { id: resource_id }.to_json
|
99
|
+
|
100
|
+
# Update the URI with the new params
|
101
|
+
uri.query = URI.encode_www_form(params)
|
102
|
+
request = case method
|
103
|
+
when :get
|
104
|
+
Net::HTTP::Get.new(uri.request_uri)
|
105
|
+
when :post
|
106
|
+
Net::HTTP::Post.new(uri.request_uri)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Reset headers after creating new request
|
110
|
+
request['Content-Type'] = 'application/json'
|
111
|
+
request['X-ACCT-ID'] = account_id
|
112
|
+
request['User-Agent'] = "accessgrid.rb @ v#{AccessGrid::VERSION}"
|
113
|
+
end
|
114
|
+
else
|
115
|
+
payload = body ? body.to_json : ""
|
116
|
+
end
|
117
|
+
|
118
|
+
# Generate signature
|
119
|
+
request['X-PAYLOAD-SIG'] = generate_signature(payload)
|
55
120
|
|
56
|
-
#
|
57
|
-
if body
|
58
|
-
|
59
|
-
request['X-PAYLOAD-SIG'] = generate_signature(json_body)
|
60
|
-
request.body = json_body
|
121
|
+
# Add the body to the request
|
122
|
+
if body && method != :get
|
123
|
+
request.body = body.to_json
|
61
124
|
end
|
62
125
|
|
63
126
|
# Make request
|
@@ -71,7 +134,7 @@ module AccessGrid
|
|
71
134
|
|
72
135
|
def generate_signature(payload)
|
73
136
|
# Base64 encode the payload
|
74
|
-
encoded_payload = Base64.strict_encode64(payload)
|
137
|
+
encoded_payload = Base64.strict_encode64(payload.to_s)
|
75
138
|
|
76
139
|
# Generate SHA256 hash
|
77
140
|
OpenSSL::HMAC.hexdigest(
|
@@ -87,12 +150,21 @@ module AccessGrid
|
|
87
150
|
JSON.parse(response.body)
|
88
151
|
when 401
|
89
152
|
raise AuthenticationError, 'Invalid credentials'
|
153
|
+
when 402
|
154
|
+
raise Error, 'Insufficient account balance'
|
90
155
|
when 404
|
91
156
|
raise ResourceNotFoundError, 'Resource not found'
|
92
157
|
when 422
|
93
158
|
raise ValidationError, JSON.parse(response.body)['message']
|
94
159
|
else
|
95
|
-
|
160
|
+
error_message = response.body.empty? ? "HTTP Status #{response.code}" : response.body
|
161
|
+
begin
|
162
|
+
error_data = JSON.parse(response.body)
|
163
|
+
error_message = error_data['message'] if error_data['message']
|
164
|
+
rescue JSON::ParserError
|
165
|
+
# If it's not valid JSON, just use the response body
|
166
|
+
end
|
167
|
+
raise Error, "API request failed: #{error_message}"
|
96
168
|
end
|
97
169
|
end
|
98
170
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: accessgrid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Auston Bunsen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-03-
|
11
|
+
date: 2025-03-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|