Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor errors #96

Merged
merged 27 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a1c0875
Rename SeamHttpApiError to HttpApiError
andrii-balitskyi Aug 20, 2024
7640fdf
Rename SeamHttpUnauthorizedError to UnauthorizedError
andrii-balitskyi Aug 20, 2024
d99db3b
Rename UnauthorizedError to HttpUnauthorizedError
andrii-balitskyi Aug 20, 2024
cfacfef
Rename SeamHttpInvalidInputError to InvalidInputError
andrii-balitskyi Aug 20, 2024
64c7ebd
Rename SeamActionAttemptError to ActionAttemptError
andrii-balitskyi Aug 20, 2024
df81b94
Rename SeamActionAttemptFailedError to ActionAttemptFailedError
andrii-balitskyi Aug 20, 2024
adabd21
More SeamActionAttemptFailedError rename
andrii-balitskyi Aug 20, 2024
4fb1ca3
Rename SeamActionAttemptTimeoutError to ActionAttemptTimeoutError
andrii-balitskyi Aug 20, 2024
88ed48d
ci: Format code
seambot Aug 20, 2024
62e8761
Fix tests, move SeamInvalidTokenError to Http module
andrii-balitskyi Aug 20, 2024
db2129a
Rename Http to Client and HttptMultiWorkspace to ClientMultiWorkspace
andrii-balitskyi Sep 19, 2024
b0d8526
Leftover renames
andrii-balitskyi Sep 19, 2024
5f69fd5
Renames in lib/seam.rb
andrii-balitskyi Sep 19, 2024
84b1b3c
Move http errors to http module, fix specs
andrii-balitskyi Sep 19, 2024
a7c1a17
Merge branch 'main' of github.com:seamapi/ruby-next into refactor-errors
andrii-balitskyi Sep 19, 2024
ec8edae
Put action attempt errors under errors module
andrii-balitskyi Sep 19, 2024
6a590df
Rename SeamWebhook to Webhook
andrii-balitskyi Oct 3, 2024
e8538f0
Make Http a module with http errors, SingleWorkspace and MultiWorkspa…
andrii-balitskyi Oct 3, 2024
4defdc8
Bump generator to 1.14.5 to put resource related stuff under Resource…
andrii-balitskyi Oct 3, 2024
aafc34f
Alias factory methods
andrii-balitskyi Oct 3, 2024
2d3558f
Clean up public exports
andrii-balitskyi Oct 3, 2024
8f192d3
Bump generator to include base client and resource imports in the routes
andrii-balitskyi Oct 3, 2024
5e105ce
Move action attempt errors under WaitForActionAttempt module
andrii-balitskyi Oct 3, 2024
a5c2c1d
Merge branch 'main' of github.com:seamapi/ruby-next into refactor-errors
andrii-balitskyi Oct 3, 2024
644f08b
Remove Http prefix from http errors
andrii-balitskyi Oct 10, 2024
781f22b
Reduce nesting of wait for action attempt errors
andrii-balitskyi Oct 10, 2024
fc69841
Refactor SeamOptions and SeamAuth
andrii-balitskyi Oct 10, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 4 additions & 14 deletions lib/seam.rb
Original file line number Diff line number Diff line change
@@ -1,31 +1,21 @@
# frozen_string_literal: true

require_relative "seam/version"
require_relative "seam/lts_version"
require_relative "seam/default_endpoint"
require_relative "seam/request"
require_relative "seam/logger"
require_relative "seam/http"
require_relative "seam/http_multi_workspace"
require_relative "seam/base_client"
require_relative "seam/base_resource"
require_relative "seam/errors"
require_relative "seam/seam_webhook"

require_relative "seam/routes/resources/index"
require_relative "seam/routes/clients/index"
require_relative "seam/wait_for_action_attempt"
require_relative "seam/webhook"

module Seam
def self.new(**args)
Http.new(**args)
end

def self.from_api_key(api_key, endpoint: nil, wait_for_action_attempt: false, debug: false)
new(api_key: api_key, endpoint: endpoint, wait_for_action_attempt: wait_for_action_attempt, debug: debug)
Http.from_api_key(api_key, endpoint: endpoint, wait_for_action_attempt: wait_for_action_attempt, debug: debug)
end

def self.from_personal_access_token(personal_access_token, workspace_id, endpoint: nil, wait_for_action_attempt: false, debug: false)
new(personal_access_token: personal_access_token, workspace_id: workspace_id, endpoint: endpoint, wait_for_action_attempt: wait_for_action_attempt, debug: debug)
Http.from_personal_access_token(personal_access_token, workspace_id, endpoint: endpoint, wait_for_action_attempt: wait_for_action_attempt, debug: debug)
end

def self.lts_version
Expand Down
216 changes: 110 additions & 106 deletions lib/seam/auth.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,112 +3,116 @@
require_relative "options"
require_relative "token"

module SeamAuth
class SeamInvalidTokenError < StandardError
def initialize(message)
super("Seam received an invalid token: #{message}")
module Seam
module Http
module Auth
class SeamInvalidTokenError < StandardError
def initialize(message)
super("Seam received an invalid token: #{message}")
end
end

def self.get_auth_headers(api_key: nil, personal_access_token: nil, workspace_id: nil)
if Http::Options.seam_http_options_with_api_key?(api_key: api_key, personal_access_token: personal_access_token)
return get_auth_headers_for_api_key(api_key)
end

if Http::Options.seam_http_options_with_personal_access_token?(personal_access_token: personal_access_token, api_key: api_key,
workspace_id: workspace_id)
return get_auth_headers_for_personal_access_token(personal_access_token, workspace_id)
end

raise Http::Options::SeamInvalidOptionsError.new(
"Must specify an api_key or personal_access_token. " \
"Attempted reading configuration from the environment, " \
"but the environment variable SEAM_API_KEY is not set."
)
end

def self.get_auth_headers_for_api_key(api_key)
if Auth.client_session_token?(api_key)
raise SeamInvalidTokenError.new(
"A Client Session Token cannot be used as an api_key"
)
end

raise SeamInvalidTokenError.new("A JWT cannot be used as an api_key") if Auth.jwt?(api_key)

raise SeamInvalidTokenError.new("An Access Token cannot be used as an api_key") if Auth.access_token?(api_key)

if Auth.publishable_key?(api_key)
raise SeamInvalidTokenError.new(
"A Publishable Key cannot be used as an api_key"
)
end

unless Auth.seam_token?(api_key)
raise SeamInvalidTokenError.new(
"Unknown or invalid api_key format, expected token to start with #{Auth::TOKEN_PREFIX}"
)
end

{"authorization" => "Bearer #{api_key}"}
end

def self.get_auth_headers_for_personal_access_token(personal_access_token, workspace_id)
if Auth.jwt?(personal_access_token)
raise SeamInvalidTokenError.new(
"A JWT cannot be used as a personal_access_token"
)
end

if Auth.client_session_token?(personal_access_token)
raise SeamInvalidTokenError.new(
"A Client Session Token cannot be used as a personal_access_token"
)
end

if Auth.publishable_key?(personal_access_token)
raise SeamInvalidTokenError.new(
"A Publishable Key cannot be used as a personal_access_token"
)
end

unless Auth.access_token?(personal_access_token)
raise SeamInvalidTokenError.new(
"Unknown or invalid personal_access_token format, expected token to start with #{Auth::ACCESS_TOKEN_PREFIX}"
)
end

{
"authorization" => "Bearer #{personal_access_token}",
"seam-workspace" => workspace_id
}
end

def self.get_auth_headers_for_multi_workspace_personal_access_token(personal_access_token)
if Auth.jwt?(personal_access_token)
raise SeamInvalidTokenError.new(
"A JWT cannot be used as a personal_access_token"
)
end

if Auth.client_session_token?(personal_access_token)
raise SeamInvalidTokenError.new(
"A Client Session Token cannot be used as a personal_access_token"
)
end

if Auth.publishable_key?(personal_access_token)
raise SeamInvalidTokenError.new(
"A Publishable Key cannot be used as a personal_access_token"
)
end

unless Auth.access_token?(personal_access_token)
raise SeamInvalidTokenError.new(
"Unknown or invalid personal_access_token format, expected token to start with #{Auth::ACCESS_TOKEN_PREFIX}"
)
end

{"authorization" => "Bearer #{personal_access_token}"}
end
end
end

def self.get_auth_headers(api_key: nil, personal_access_token: nil, workspace_id: nil)
if SeamOptions.seam_http_options_with_api_key?(api_key: api_key, personal_access_token: personal_access_token)
return get_auth_headers_for_api_key(api_key)
end

if SeamOptions.seam_http_options_with_personal_access_token?(personal_access_token: personal_access_token, api_key: api_key,
workspace_id: workspace_id)
return get_auth_headers_for_personal_access_token(personal_access_token, workspace_id)
end

raise SeamOptions::SeamInvalidOptionsError.new(
"Must specify an api_key or personal_access_token. " \
"Attempted reading configuration from the environment, " \
"but the environment variable SEAM_API_KEY is not set."
)
end

def self.get_auth_headers_for_api_key(api_key)
if SeamAuth.client_session_token?(api_key)
raise SeamInvalidTokenError.new(
"A Client Session Token cannot be used as an api_key"
)
end

raise SeamInvalidTokenError.new("A JWT cannot be used as an api_key") if SeamAuth.jwt?(api_key)

raise SeamInvalidTokenError.new("An Access Token cannot be used as an api_key") if SeamAuth.access_token?(api_key)

if SeamAuth.publishable_key?(api_key)
raise SeamInvalidTokenError.new(
"A Publishable Key cannot be used as an api_key"
)
end

unless SeamAuth.seam_token?(api_key)
raise SeamInvalidTokenError.new(
"Unknown or invalid api_key format, expected token to start with #{SeamAuth::TOKEN_PREFIX}"
)
end

{"authorization" => "Bearer #{api_key}"}
end

def self.get_auth_headers_for_personal_access_token(personal_access_token, workspace_id)
if SeamAuth.jwt?(personal_access_token)
raise SeamInvalidTokenError.new(
"A JWT cannot be used as a personal_access_token"
)
end

if SeamAuth.client_session_token?(personal_access_token)
raise SeamInvalidTokenError.new(
"A Client Session Token cannot be used as a personal_access_token"
)
end

if SeamAuth.publishable_key?(personal_access_token)
raise SeamInvalidTokenError.new(
"A Publishable Key cannot be used as a personal_access_token"
)
end

unless SeamAuth.access_token?(personal_access_token)
raise SeamInvalidTokenError.new(
"Unknown or invalid personal_access_token format, expected token to start with #{SeamAuth::ACCESS_TOKEN_PREFIX}"
)
end

{
"authorization" => "Bearer #{personal_access_token}",
"seam-workspace" => workspace_id
}
end

def self.get_auth_headers_for_multi_workspace_personal_access_token(personal_access_token)
if SeamAuth.jwt?(personal_access_token)
raise SeamInvalidTokenError.new(
"A JWT cannot be used as a personal_access_token"
)
end

if SeamAuth.client_session_token?(personal_access_token)
raise SeamInvalidTokenError.new(
"A Client Session Token cannot be used as a personal_access_token"
)
end

if SeamAuth.publishable_key?(personal_access_token)
raise SeamInvalidTokenError.new(
"A Publishable Key cannot be used as a personal_access_token"
)
end

unless SeamAuth.access_token?(personal_access_token)
raise SeamInvalidTokenError.new(
"Unknown or invalid personal_access_token format, expected token to start with #{SeamAuth::ACCESS_TOKEN_PREFIX}"
)
end

{"authorization" => "Bearer #{personal_access_token}"}
end
end
78 changes: 40 additions & 38 deletions lib/seam/base_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,59 +3,61 @@
require_relative "deep_hash_accessor"

module Seam
class BaseResource
attr_accessor :data, :client
module Resources
class BaseResource
attr_accessor :data, :client

def initialize(data, client = nil)
@data = data
@client = client
def initialize(data, client = nil)
@data = data
@client = client

@data.each do |key, value|
value = Seam::DeepHashAccessor.new(value) if value.is_a?(Hash)
instance_variable_set(:"@#{key}", value)
@data.each do |key, value|
value = Seam::DeepHashAccessor.new(value) if value.is_a?(Hash)
instance_variable_set(:"@#{key}", value)
end
end
end

def update_from_response(data)
@data = data
@data.each do |key, value|
instance_variable_set(:"@#{key}", value)
def update_from_response(data)
@data = data
@data.each do |key, value|
instance_variable_set(:"@#{key}", value)
end
end
end

def self.load_from_response(data, client = nil)
if data.is_a?(Array)
data.map { |d| new(d, client) }
else
new(data, client)
def self.load_from_response(data, client = nil)
if data.is_a?(Array)
data.map { |d| new(d, client) }
else
new(data, client)
end
end
end

def inspect
"<#{self.class.name}:#{"0x00%x" % (object_id << 1)}\n" + # rubocop:disable Style/StringConcatenation, Style/FormatString
instance_variables
.map { |k| k.to_s.sub("@", "") }
.filter { |k| k != "data" and k != "client" and respond_to? k }
.map { |k| " #{k}=#{send(k).inspect}" }
.join("\n") + ">"
end
def inspect
"<#{self.class.name}:#{"0x00%x" % (object_id << 1)}\n" + # rubocop:disable Style/StringConcatenation, Style/FormatString
instance_variables
.map { |k| k.to_s.sub("@", "") }
.filter { |k| k != "data" and k != "client" and respond_to? k }
.map { |k| " #{k}=#{send(k).inspect}" }
.join("\n") + ">"
end

def self.date_accessor(*attrs)
attrs.each do |attr|
define_method(attr) do
value = instance_variable_get(:"@#{attr}")
def self.date_accessor(*attrs)
attrs.each do |attr|
define_method(attr) do
value = instance_variable_get(:"@#{attr}")

raise "No value for #{attr} set" if value.nil?
raise "No value for #{attr} set" if value.nil?

parse_datetime(value)
parse_datetime(value)
end
end
end
end

protected
protected

def parse_datetime(value)
Time.parse(value)
def parse_datetime(value)
Time.parse(value)
end
end
end
end
Loading