Skip to content

Commit

Permalink
Refactor errors (#96)
Browse files Browse the repository at this point in the history
* Rename SeamHttpApiError to HttpApiError

* Rename SeamHttpUnauthorizedError to UnauthorizedError

* Rename UnauthorizedError to HttpUnauthorizedError

* Rename SeamHttpInvalidInputError to InvalidInputError

* Rename SeamActionAttemptError to ActionAttemptError

* Rename SeamActionAttemptFailedError to ActionAttemptFailedError

* More SeamActionAttemptFailedError rename

* Rename SeamActionAttemptTimeoutError to ActionAttemptTimeoutError

* ci: Format code

* Fix tests, move SeamInvalidTokenError to Http module

* Rename Http to Client and HttptMultiWorkspace to ClientMultiWorkspace

* Leftover renames

* Renames in lib/seam.rb

* Move http errors to http module, fix specs

* Put action attempt errors under errors module

* Rename SeamWebhook to Webhook

* Make Http a module with http errors, SingleWorkspace and MultiWorkspace classes

* Bump generator to 1.14.5 to put resource related stuff under Resources module

* Alias factory methods

* Clean up public exports

* Bump generator to include base client and resource imports in the routes

* Move action attempt errors under WaitForActionAttempt module

* Remove Http prefix from http errors

* Reduce nesting of wait for action attempt errors

* Refactor SeamOptions and SeamAuth

---------

Co-authored-by: Seam Bot <[email protected]>
  • Loading branch information
andrii-balitskyi and seambot authored Oct 14, 2024
1 parent cb96dcf commit 14effe0
Show file tree
Hide file tree
Showing 99 changed files with 764 additions and 650 deletions.
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

0 comments on commit 14effe0

Please sign in to comment.