From 0c0af54a8bd446733ec29ed87509d6c12b68d578 Mon Sep 17 00:00:00 2001 From: Isaac Lewis Date: Thu, 29 Mar 2018 10:58:24 -0700 Subject: [PATCH] error handling; cleanup; rename to `syspro-ruby` --- Gemfile | 1 - README.md | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------- bin/console | 11 ++--------- bin/setup | 2 -- lib/syspro.rb | 1 + lib/syspro/api_resource.rb | 7 ------- lib/syspro/errors.rb | 34 ++++++++++++++++++++++++++++++++++ lib/syspro/syspro_client.rb | 3 ++- lib/syspro/syspro_object.rb | 10 +++++++++- lib/syspro/syspro_response.rb | 22 +--------------------- lib/syspro/util.rb | 17 ++++++++++++++--- syspro-ruby.gemspec | 36 ++++++++++++++++++++++++++++++++++++ syspro.gemspec | 36 ------------------------------------ test/client_test.rb | 11 +++++++++++ 14 files changed, 165 insertions(+), 88 deletions(-) create mode 100644 lib/syspro/errors.rb create mode 100644 syspro-ruby.gemspec delete mode 100644 syspro.gemspec diff --git a/Gemfile b/Gemfile index 2751b83..d2fceab 100644 --- a/Gemfile +++ b/Gemfile @@ -2,5 +2,4 @@ source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } -# Specify your gem's dependencies in syspro.gemspec gemspec diff --git a/README.md b/README.md index abfc591..340d5c0 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ -# Syspro +# syspro-ruby -Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/syspro`. To experiment with that code, run `bin/console` for an interactive prompt. - -TODO: Delete this and the text above, and describe your gem +syspro-ruby is an adapter gem to connect to SYSPRO 7 ERP installations. You can use this gem to connect to the SYSPRO 7 WCF Service and build Ruby applications on top of your SYSPRO data. ## Installation @@ -22,7 +20,57 @@ Or install it yourself as: ## Usage -TODO: Write usage instructions here +### Utilities + +#### Logon + +```rb +user_id = Syspro::Logon.logon(username, password, company_id, company_password) +``` +`user_id` will be a `UserId` object that contains the `guid` supplied by SYSPRO. You will use this guid to make further requests to SYSPRO. + +#### GetUserProfile + +```rb +user_profile = Syspro::GetUserProfile.get_user_profile(guid) +``` +`user_profile` will be a `UserProfile` object that contains the following: + - `company_name` + - `operator_code` + - `operator_group` + - `operator_email_address` + - `operator_location` + - `operator_language_code` + - `system_language` + - `accounting_date` + - `company_date` + - `default_ar_branch` + - `default_ap_branch` + - `default_bank` + - `default_warehouse` + - `default_customer` + - `system_site_id` + - `system_nationality_code` + - `local_currency_code` + - `currency_description` + - `default_requisition_user` + - `xml_to_html_transform` + - `css_style` + - `css_suffix` + - `decimal_format` + - `date_format` + - `functional_role` + - `database_type` + - `syspro_version` + - `enet_version` + - `syspro_server_bit_width` + +#### Logoff + +```rb +logged_off = Syspro::Logoff.logoff(guid) +``` +`logged_off` will be `true` if the user has been successfully logged off, and will contain an error string if an error has occured. ## Development @@ -32,7 +80,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To ## Contributing -Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/syspro. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. +Bug reports and pull requests are welcome on GitHub at https://github.com/ike/syspro-ruby. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. ## License @@ -40,4 +88,4 @@ The gem is available as open source under the terms of the [MIT License](https:/ ## Code of Conduct -Everyone interacting in the Syspro project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/syspro/blob/master/CODE_OF_CONDUCT.md). +Everyone interacting in the Syspro project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/ike/syspro-ruby/blob/master/CODE_OF_CONDUCT.md). diff --git a/bin/console b/bin/console index 8cd9ffd..151318a 100755 --- a/bin/console +++ b/bin/console @@ -2,13 +2,6 @@ require "bundler/setup" require "syspro" +require "pry" -# You can add fixtures and/or initialization code here to make experimenting -# with your gem easier. You can also use a different console, if you like. - -# (If you use this, don't forget to add pry to your Gemfile!) -# require "pry" -# Pry.start - -require "irb" -IRB.start(__FILE__) +Pry.start diff --git a/bin/setup b/bin/setup index dce67d8..cf4ad25 100755 --- a/bin/setup +++ b/bin/setup @@ -4,5 +4,3 @@ IFS=$'\n\t' set -vx bundle install - -# Do any other automated setup that you need to do here diff --git a/lib/syspro.rb b/lib/syspro.rb index 2d65040..c7b64a8 100644 --- a/lib/syspro.rb +++ b/lib/syspro.rb @@ -5,6 +5,7 @@ require "logger" require "openssl" require "syspro/api_resource" +require "syspro/errors" require "syspro/get_logon_profile" require "syspro/get_version" require "syspro/logoff" diff --git a/lib/syspro/api_resource.rb b/lib/syspro/api_resource.rb index 2b32984..1858f7f 100644 --- a/lib/syspro/api_resource.rb +++ b/lib/syspro/api_resource.rb @@ -16,13 +16,6 @@ module Syspro "/#{CGI.escape(class_name.downcase)}" end - def resource_url - #unless (id = self["id"]) - #raise InvalidRequestError.new("Could not determine which URL to request: #{self.class} instance has invalid ID: #{id.inspect}", "id") - #end - #"#{self.class.resource_url}/#{CGI.escape(id)}" - end - def refresh resp, opts = request(:get, resource_url, @retrieve_params) initialize_from(resp.data, opts) diff --git a/lib/syspro/errors.rb b/lib/syspro/errors.rb new file mode 100644 index 0000000..7515992 --- /dev/null +++ b/lib/syspro/errors.rb @@ -0,0 +1,34 @@ +module Syspro + class SysproError < StandardError + attr_reader :message, :response, :code, :http_body, :http_headers, + :http_status, :data, :request_id + + # Initializes a SysproError. + def initialize(message = nil, http_status: nil, http_body: nil, data: nil, + http_headers: nil, code: nil) + @message = message + @http_status = http_status + @http_body = http_body + @http_headers = http_headers || {} + @data = data + @code = code + @request_id = @http_headers[:request_id] + end + + def to_s + status_string = @http_status.nil? ? "" : "(Status #{@http_status}) " + id_string = @request_id.nil? ? "" : "(Request #{@request_id}) " + "#{status_string}#{id_string}#{@message}" + end + end + + class AuthenticationError < SysproError + end + + class ApiConnectionError < SysproError + end + + class ApiError < SysproError + end + +end diff --git a/lib/syspro/syspro_client.rb b/lib/syspro/syspro_client.rb index 99e10f9..4532b51 100644 --- a/lib/syspro/syspro_client.rb +++ b/lib/syspro/syspro_client.rb @@ -40,6 +40,7 @@ module Syspro c.adapter Faraday.default_adapter end + # For now, we're not verifying SSL certificates. The warning will appear. #if Syspro.verify_ssl_certs #conn.ssl.verify = true #conn.ssl.cert_store = Syspro.ca_store @@ -129,7 +130,7 @@ module Syspro end def general_api_error(status, body) - APIError.new("Invalid response object from API: #{body.inspect} " \ + ApiError.new("Invalid response object from API: #{body.inspect} " \ "(HTTP response code was #{status})", http_status: status, http_body: body) end diff --git a/lib/syspro/syspro_object.rb b/lib/syspro/syspro_object.rb index d0eaa49..016510f 100644 --- a/lib/syspro/syspro_object.rb +++ b/lib/syspro/syspro_object.rb @@ -4,6 +4,14 @@ module Syspro def initialize(id = nil, opts = {}) @opts = Util.normalize_opts(opts) + @original_values = {} + @values = {} + + # This really belongs in APIResource, but not putting it there allows us + # to have a unified inspect method + @unsaved_values = Set.new + @transient_values = Set.new + @values[:id] = id if id end # Determines the equality of two Syspro objects. Syspro objects are @@ -52,7 +60,7 @@ module Syspro private # Produces a deep copy of the given object including support for arrays, - # hashes, and SysproObject. + # hashes, and SysproObjects. def self.deep_copy(obj) case obj when Array diff --git a/lib/syspro/syspro_response.rb b/lib/syspro/syspro_response.rb index a9c92d4..91958da 100644 --- a/lib/syspro/syspro_response.rb +++ b/lib/syspro/syspro_response.rb @@ -1,29 +1,11 @@ require "nokogiri" module Syspro - # SysproResponse encapsulates some vitals of a response that came back from - # the Syspro API. class SysproResponse - # The data contained by the HTTP body of the response deserialized from - # JSON. - attr_accessor :data - - # The raw HTTP body of the response. - attr_accessor :http_body - - # A Hash of the HTTP headers of the response. - attr_accessor :http_headers - - # The integer HTTP status code of the response. - attr_accessor :http_status - - # The Syspro request ID of the response. - attr_accessor :request_id + attr_accessor :data, :http_body, :http_headers, :http_status, :request_id # Initializes a SysproResponse object from a Hash like the kind returned as # part of a Faraday exception. - # - # This may throw JSON::ParserError if the response body is not valid JSON. def self.from_faraday_hash(http_resp) resp = SysproResponse.new resp.http_body = http_resp[:body] @@ -35,8 +17,6 @@ module Syspro end # Initializes a SysproResponse object from a Faraday HTTP response object. - # - # This may throw JSON::ParserError if the response body is not valid JSON. def self.from_faraday_response(http_resp) resp = SysproResponse.new resp.http_body = http_resp.body diff --git a/lib/syspro/util.rb b/lib/syspro/util.rb index 150baa6..eebf93c 100644 --- a/lib/syspro/util.rb +++ b/lib/syspro/util.rb @@ -2,9 +2,21 @@ module Syspro class Util # Options that a user is allowed to specify. OPTS_USER_SPECIFIED = Set[ - # :syspro_version + :user_id ].freeze + # Options that should be copyable from one StripeObject to another + # including options that may be internal. + OPTS_COPYABLE = ( + OPTS_USER_SPECIFIED + Set[:api_base] + ).freeze + + # Options that should be persisted between API requests. This includes + # client, which is an object containing an HTTP client to reuse. + OPTS_PERSISTABLE = ( + OPTS_USER_SPECIFIED + Set[:client] + ).freeze + def self.objects_to_ids(h) case h @@ -45,8 +57,7 @@ module Syspro end end - - # The secondary opts argument can either be a string or hash + # The secondary opts argument can either be a string or hash # Turn this value into an api_key and a set of headers def self.normalize_opts(opts) case opts diff --git a/syspro-ruby.gemspec b/syspro-ruby.gemspec new file mode 100644 index 0000000..b63b0d8 --- /dev/null +++ b/syspro-ruby.gemspec @@ -0,0 +1,36 @@ +lib = File.expand_path("../lib", __FILE__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require "syspro/version" + +Gem::Specification.new do |spec| + spec.name = "syspro-ruby" + spec.version = Syspro::VERSION + spec.authors = ["Isaac Lewis"] + spec.email = ["isaac@ike.io"] + + spec.summary = %q{SYSPRO 7 Api Ruby adapter} + spec.license = "MIT" + + # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host' + # to allow pushing to a single host or delete this section to allow pushing to any host. + if spec.respond_to?(:metadata) + spec.metadata["allowed_push_host"] = "http://rubygems.org" + else + raise "RubyGems 2.0 or newer is required to protect against " \ + "public gem pushes." + end + + spec.files = `git ls-files -z`.split("\x0").reject do |f| + f.match(%r{^(test|spec|features)/}) + end + spec.bindir = "exe" + spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } + spec.require_paths = ["lib"] + + spec.add_dependency("faraday", "~> 0.10") + + spec.add_development_dependency "bundler", "~> 1.16" + spec.add_development_dependency "pry", "~> 0.11" + spec.add_development_dependency "rake", "~> 10.0" + spec.add_development_dependency "minitest", "~> 5.0" +end diff --git a/syspro.gemspec b/syspro.gemspec deleted file mode 100644 index a32fa3f..0000000 --- a/syspro.gemspec +++ /dev/null @@ -1,36 +0,0 @@ -lib = File.expand_path("../lib", __FILE__) -$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) -require "syspro/version" - -Gem::Specification.new do |spec| - spec.name = "syspro" - spec.version = Syspro::VERSION - spec.authors = ["Isaac Lewis"] - spec.email = ["ike@wild.land"] - - spec.summary = %q{SYSPRO 7 Api Ruby adapter} - spec.license = "MIT" - - # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host' - # to allow pushing to a single host or delete this section to allow pushing to any host. - if spec.respond_to?(:metadata) - spec.metadata["allowed_push_host"] = "http://rubygems.org" - else - raise "RubyGems 2.0 or newer is required to protect against " \ - "public gem pushes." - end - - spec.files = `git ls-files -z`.split("\x0").reject do |f| - f.match(%r{^(test|spec|features)/}) - end - spec.bindir = "exe" - spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } - spec.require_paths = ["lib"] - - spec.add_dependency("faraday", "~> 0.10") - - spec.add_development_dependency "bundler", "~> 1.16" - spec.add_development_dependency "pry", "~> 0.11" - spec.add_development_dependency "rake", "~> 10.0" - spec.add_development_dependency "minitest", "~> 5.0" -end diff --git a/test/client_test.rb b/test/client_test.rb index 654b234..659e15b 100644 --- a/test/client_test.rb +++ b/test/client_test.rb @@ -5,4 +5,15 @@ class SysproClientTest < Minitest::Test client = ::Syspro::SysproClient.new assert_match (/(\d+\.)?(\d+\.)?(\d+\.)?(\d+)/), client.get_syspro_version.version end + + def test_client_block_execution + client = ::Syspro::SysproClient.new + + version, resp = client.request { + Syspro::GetVersion.get_version + } + + assert_match version.version, resp.http_body + assert_match (/(\d+\.)?(\d+\.)?(\d+\.)?(\d+)/), version.version + end end -- libgit2 0.21.4