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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 15b5d0cfdff13339d74d78a8204778a5eb0d36df704b6e2b67899dc4d9799d82
4
- data.tar.gz: c2429ef868beb9ce1e45d2535451ee8c1909bafbd446555d04be72c989ba2770
3
+ metadata.gz: 2f95e77022beec6a20cd5a55350ff8cd5ad15233ec74d13b22d49587d8fafed9
4
+ data.tar.gz: 9c20b6923726a61c5865b9b58c7f55fe008e7756e0d99f800e2a6efaca3e18aa
5
5
  SHA512:
6
- metadata.gz: c43a8a49895d402425966639e9b43f66daa745d29f8c26f00429cc42b364a4e6835c3c9277ddd675743bfa223d2b34848edcf666cd37aa1a2e6b4383088c2918
7
- data.tar.gz: 9d3de9854fd135763cb15035655abac79078ef709d257cab99e8850f1a23821aa08004b80a47d94abfd78b90467af353b560b2a266bc0aa6cf940e088d9f587b
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
- #### Provision a new card
40
+ #### Issue a new card
41
41
 
42
42
  ```ruby
43
- card = client.access_cards.provision(
44
- card_template_id: "0xd3adb00b5",
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
- card_id: "0xc4rd1d",
65
- employee_id: "987654321",
66
- full_name: "Updated Employee Name",
67
- classification: "contractor",
68
- expiration_date: "2025-02-22T21:04:03.664Z",
69
- employee_photo: "[image_in_base64_encoded_format]"
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
- card_id: "0xc4rd1d"
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
- card_template_id: "0xd3adb00b5",
128
- name: "Updated Employee NFC key",
129
- allow_on_multiple_devices: true,
130
- watch_count: 2,
131
- iphone_count: 3,
132
- support_info: {
133
- support_url: "https://help.yourcompany.com",
134
- support_phone_number: "+1-555-123-4567",
135
- support_email: "support@yourcompany.com",
136
- privacy_policy_url: "https://yourcompany.com/privacy",
137
- terms_and_conditions_url: "https://yourcompany.com/terms"
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 provision(params)
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
- card_id = params.delete(:card_id)
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(params)
29
- manage_state(params[:card_id], 'suspend')
38
+ def suspend(card_id)
39
+ manage_state(card_id, 'suspend')
30
40
  end
31
41
 
32
- def resume(params)
33
- manage_state(params[:card_id], 'resume')
42
+ def resume(card_id)
43
+ manage_state(card_id, 'resume')
34
44
  end
35
45
 
36
- def unlink(params)
37
- manage_state(params[:card_id], 'unlink')
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
@@ -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/#{card_template_id}", transformed_params)
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(params)
22
- response = @client.make_request(:get, "/v1/console/card-templates/#{params[:card_template_id]}")
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
- card_template_id = params.delete(:card_template_id)
28
- response = @client.make_request(:get, "/v1/console/card-templates/#{card_template_id}/logs", params)
29
- response['logs'].map { |log| Event.new(log) }
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, :allow_on_multiple_devices,
53
- :watch_count, :iphone_count, :support_info, :style_settings
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
- @allow_on_multiple_devices = data['allowed_device_counts']['allow_on_multiple_devices']
61
- @watch_count = data['allowed_device_counts']['watch']
62
- @iphone_count = data['allowed_device_counts']['iphone']
63
- @support_info = data['support_settings']
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']
@@ -1,4 +1,4 @@
1
1
  # lib/accessgrid/version.rb
2
2
  module AccessGrid
3
- VERSION = '0.1.2'
3
+ VERSION = '0.1.3'
4
4
  end
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
- # Generate signature if body present
57
- if body
58
- json_body = body.to_json
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
- raise Error, "API request failed with status #{response.code}: #{response.body}"
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.2
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-01 00:00:00.000000000 Z
11
+ date: 2025-03-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler