skippr-rb 0.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d0d1a7e9bcb6c2111da2ba20f4cc3112cdd6a605
4
+ data.tar.gz: 5633a4a7f39ae5105bb1adafe6d5ba293fd2fece
5
+ SHA512:
6
+ metadata.gz: 8548bc1eb8df7d3e4f6f19d6939366260661b25afd4a598ec2c98fdfea5c38c91a7d0bc891def0740a6cd5253170cd15c784f64522d8b8f0ae4ff86f8a544712
7
+ data.tar.gz: 023a17fb0656f7dd85dd4d1b1974861dabc0744a33a477d2680f8744ecc1d246427884303c29719288e7f25b436daea35d4b1e0aea946c51d56d847b301261dd
@@ -0,0 +1,21 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.swp
19
+ *.swo
20
+
21
+ .idea
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in skippr-rb.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Sebastian M. Gauck
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,89 @@
1
+ # Skippr::Rb
2
+
3
+ Skippr api gem - this is WIP!
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'skippr-rb'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install skippr-rb
18
+
19
+ ## Usage
20
+
21
+ Skippr::Api.configure({
22
+ client_name: "fortytools",
23
+ app_key: "awesome_skippr_app",
24
+ app_token: "098172398723419887",
25
+ client_user_api_key: "skippr_client_user_key", # ATTENTION: has to refer to the same client as the 'client_name' does
26
+ client_user_api_token: "0987654321zonk",
27
+ })
28
+
29
+ # The Endpoint is per default configured to be
30
+ # https://skippr.com/api/v2
31
+ # so in general you're done with the configuration above
32
+
33
+
34
+ # But just in case you'd like to tweak this endpoint, then provide a conf hash with any of the following
35
+ Skippr::Api.configure_endpoint({
36
+ protocol: "http",
37
+ domain: "skippr.local",
38
+ port: 3030,
39
+ path: '/superapi/v33/', # path is always surrounded by '/'
40
+ user: 'basicauthuser', # if the api is protected by http basic auth
41
+ password: 'basicauthpassword', # if the api is protected by http basic auth
42
+ })
43
+ # that's for 'http://batzen.skippr.local:3030/superapi/v33/' with basic auth
44
+
45
+
46
+
47
+ # Now use it in your models and controllers like follows:
48
+
49
+ Skippr::Customer.all
50
+
51
+ c = Skippr::Customer.new
52
+ c.name = "fortytools gmbh"
53
+ c.street = "Georgsplatz 10"
54
+ c.zip = "20099"
55
+ c.city = "Hamburg"
56
+ c.customer_state_id = Skippr::CustomerState.all.select{|s| s.name == "Kunde"}.first
57
+ c.save
58
+
59
+ i = Skippr::Invoice.new
60
+ i.date = Date.today
61
+ i.customer_id = 4711
62
+ i.line_items_attributes = [
63
+ { title: "Development Gricker.com",
64
+ quantity: 15,
65
+ price: 1234,
66
+ service_period_start: 5.days.ago,
67
+ service_period_end: 4.days.ago,
68
+ service_type_id: Skippr::ServiceType.all.first.id
69
+ }
70
+ ]
71
+ i.save
72
+
73
+
74
+ ## Thread safety
75
+ - The Skippr::Api and Skippr::Endpoint classes are thread safe. They do not store anything in class variables but in
76
+ thread locals (the thread_container). Hence, you can use several threads using the code above with varying credentials
77
+ and endpoints without interfering with each other.
78
+
79
+ ## TODO
80
+
81
+ - add dependencies to gemspec
82
+
83
+ ## Contributing
84
+
85
+ 1. Fork it
86
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
87
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
88
+ 4. Push to the branch (`git push origin my-new-feature`)
89
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,26 @@
1
+ require "skippr/version"
2
+
3
+ require 'active_resource'
4
+ require "skippr/active_resource/base"
5
+
6
+ require "skippr/exceptions"
7
+ require "skippr/api"
8
+
9
+
10
+ require "skippr/resources/account"
11
+ require "skippr/resources/attachment_type"
12
+ require "skippr/resources/bank_account"
13
+ require "skippr/resources/customer"
14
+ require "skippr/resources/customer_state"
15
+ require "skippr/resources/event"
16
+ require "skippr/resources/invoice"
17
+ require "skippr/resources/invoice_position"
18
+ require "skippr/resources/item"
19
+ require "skippr/resources/item_category"
20
+ require "skippr/resources/item_order"
21
+ require "skippr/resources/offer"
22
+ require "skippr/resources/service_type"
23
+ require "skippr/resources/supplier"
24
+ require "skippr/resources/task"
25
+ require "skippr/resources/unit"
26
+ require "skippr/resources/user"
@@ -0,0 +1,43 @@
1
+ class ActiveResource::Base
2
+ class << self
3
+
4
+ def reset_connection
5
+ @connection = nil
6
+ end
7
+
8
+ =begin
9
+ def site=site
10
+ thread_container['site'] = site
11
+ end
12
+ def site
13
+ s = thread_container['site']
14
+ if s.is_a?(String)
15
+ URI.parse(s)
16
+ else
17
+ s
18
+ end
19
+ end
20
+
21
+ def password=password
22
+ thread_container['password'] = password
23
+ end
24
+ def password
25
+ thread_container['password']
26
+ end
27
+
28
+ def user=user
29
+ thread_container['user'] = user
30
+ end
31
+ def user
32
+ thread_container['user']
33
+ end
34
+
35
+ def thread_container
36
+ Thread.current['active_resource.conf'] ||= {}
37
+ Thread.current['active_resource.conf']
38
+ end
39
+ =end
40
+
41
+
42
+ end
43
+ end
@@ -0,0 +1,171 @@
1
+ module Skippr
2
+
3
+ class Api < ActiveResource::Base
4
+
5
+
6
+ def get(custom_method_name, options={})
7
+ super(custom_method_name, options.merge(self.class.auth_params))
8
+ end
9
+ def post(custom_method_name, options={})
10
+ super(custom_method_name, options.merge(self.class.auth_params))
11
+ end
12
+ def put(custom_method_name, options={})
13
+ super(custom_method_name, options.merge(self.class.auth_params))
14
+ end
15
+ def delete(custom_method_name, options={})
16
+ super(custom_method_name, options.merge(self.class.auth_params))
17
+ end
18
+
19
+
20
+ class << self
21
+
22
+ ### ActiveResource API
23
+ timeout = 30
24
+ def include_root_in_json
25
+ false
26
+ end
27
+
28
+ # Thread safety for active_resource, see monkey patch in monkey.rb
29
+
30
+ def element_path(id, prefix_options = {}, query_options = nil)
31
+ prefix_options, query_options = split_options(prefix_options) if query_options.nil?
32
+ query_options = ( query_options || {} ).merge(self.auth_params)
33
+ "#{prefix(prefix_options)}#{collection_name}/#{id}#{query_string(query_options)}"
34
+ end
35
+
36
+ def collection_path(prefix_options = {}, query_options = nil)
37
+ prefix_options, query_options = split_options(prefix_options) if query_options.nil?
38
+ query_options = ( query_options || {} ).merge(self.auth_params)
39
+ "#{prefix(prefix_options)}#{collection_name}#{query_string(query_options)}"
40
+ end
41
+
42
+ def get(custom_method_name, options={})
43
+ super(custom_method_name, options.merge(self.auth_params))
44
+ end
45
+ def post(custom_method_name, options={})
46
+ super(custom_method_name, options.merge(self.auth_params))
47
+ end
48
+ def put(custom_method_name, options={})
49
+ super(custom_method_name, options.merge(self.auth_params))
50
+ end
51
+ def delete(custom_method_name, options={})
52
+ super(custom_method_name, options.merge(self.auth_params))
53
+ end
54
+
55
+ ### END ActiveResource API
56
+
57
+ def valid?
58
+ begin
59
+ uri = URI.parse(self.site.to_s + 'auth/valid?' + self.auth_params.to_param)
60
+ http = Net::HTTP.new(uri.host, uri.port)
61
+ if self.site.scheme == 'https'
62
+ http.use_ssl= true
63
+ end
64
+ rq = Net::HTTP::Get.new(uri.request_uri)
65
+ unless self.user.blank?
66
+ rq.basic_auth(self.user, self.password)
67
+ end
68
+ response = http.request(rq)
69
+ body = response.read_body
70
+ if response.code == '200' && body == 'Ok'
71
+ true
72
+ else
73
+ Rails.logger.info "Server responded: (#{response.code}) #{body}"
74
+ false
75
+ end
76
+
77
+ rescue Timeout::Error
78
+ Rails.logger.warn "timeout"
79
+ false
80
+ rescue Errno::ECONNREFUSED
81
+ Rails.logger.warn "no api connection"
82
+ false
83
+ rescue
84
+ Rails.logger.info "exception when trying to authenticate"
85
+ false
86
+ end
87
+ end
88
+
89
+ # Thread safe auth params
90
+ def auth_params
91
+ assert_configuration!(self.thread_container)
92
+
93
+ valid_until = 1.hour.from_now
94
+ sig_src = [self.client_user_api_token, self.app_token, valid_until.to_time.to_i.to_s].join(":")
95
+ signature = Digest::SHA2.hexdigest(sig_src)
96
+ {
97
+ app: self.app_key,
98
+ user: self.client_user_api_key,
99
+ validuntil: valid_until.to_time.to_i.to_s,
100
+ signature: signature
101
+ }
102
+ end
103
+
104
+
105
+ def configure(configuration_hash)
106
+ configuration_hash.each do |key, value|
107
+ self.thread_container["#{key}"] = value
108
+ end
109
+
110
+ reset_connection
111
+ end
112
+
113
+ def configure_endpoint(configuration_hash)
114
+ configuration_hash[:protocol] ||= "https"
115
+ configuration_hash[:domain] ||= "skippr.com"
116
+ endpoint_site = [configuration_hash[:protocol], configuration_hash[:domain]].join("://")
117
+ endpoint_site += ":" + configuration_hash[:port].to_s if configuration_hash[:port].present?
118
+ self.site = endpoint_site + "/api/v2/"
119
+ reset_connection
120
+ end
121
+
122
+ def client_name
123
+ self.thread_container['client_name']
124
+ end
125
+
126
+ def app_key
127
+ self.thread_container['app_key']
128
+ end
129
+
130
+ def app_token
131
+ self.thread_container['app_token']
132
+ end
133
+
134
+ def client_user_api_key
135
+ self.thread_container['client_user_api_key']
136
+ end
137
+
138
+ def client_user_api_token
139
+ self.thread_container['client_user_api_token']
140
+ end
141
+
142
+ def thread_container
143
+ Thread.current['skippr.api.conf'] ||= {}
144
+ Thread.current['skippr.api.conf']
145
+ end
146
+
147
+ def assert_configuration!(conf_hash)
148
+ required_confs = [:app_key, :app_token, :client_user_api_key, :client_user_api_token, :client_name]
149
+
150
+ unknowns = conf_hash.symbolize_keys.except(*required_confs)
151
+ unless unknowns.empty?
152
+ raise Skippr::UnknownConfigurationError.new("Unknown in api configuration: #{unknowns.keys}")
153
+ end
154
+
155
+ missings = required_confs - conf_hash.symbolize_keys.keys
156
+ unless missings.empty?
157
+ raise Skippr::MissingConfigurationError.new("Missing in api configuration: #{missings}")
158
+ end
159
+ end
160
+ end
161
+
162
+
163
+ end
164
+
165
+ # Delegator for convenience, checks whether current skippr api settings allow for a valid connection
166
+ def self.valid?
167
+ Api.valid?
168
+ end
169
+ end
170
+
171
+
@@ -0,0 +1,8 @@
1
+ module Skippr
2
+
3
+ class MissingConfigurationError < StandardError
4
+ end
5
+ class UnknownConfigurationError < StandardError
6
+ end
7
+
8
+ end
@@ -0,0 +1,5 @@
1
+ module Skippr
2
+ class Account < Api
3
+
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Skippr
2
+ class AttachmentType < Api
3
+
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Skippr
2
+ class BankAccount < Api
3
+
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Skippr
2
+ class Customer < Api
3
+
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Skippr
2
+ class CustomerState < Api
3
+
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ module Skippr
2
+ class Employee < Api
3
+
4
+ end
5
+ end
6
+
@@ -0,0 +1,5 @@
1
+ module Skippr
2
+ class Event < Api
3
+
4
+ end
5
+ end
@@ -0,0 +1,21 @@
1
+ module Skippr
2
+ class Invoice < Api
3
+
4
+ ACCOUNTED = 0
5
+ PRINTED = 1
6
+ DRAFT = 4
7
+
8
+ def accounted?
9
+ state == ACCOUNTED
10
+ end
11
+
12
+ def printed?
13
+ state <= PRINTED
14
+ end
15
+
16
+ def draft?
17
+ state == DRAFT
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,5 @@
1
+ module Skippr
2
+ class InvoicePosition < Api
3
+
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Skippr
2
+ class Item < Api
3
+
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Skippr
2
+ class ItemCategory < Api
3
+
4
+ end
5
+ end
@@ -0,0 +1,13 @@
1
+ module Skippr
2
+ class ItemOrder < Api
3
+
4
+ def draft?
5
+ number.nil?
6
+ end
7
+
8
+ def printed?
9
+ !draft?
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ module Skippr
2
+ class Offer < Api
3
+
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Skippr
2
+ class ServiceType < Api
3
+
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Skippr
2
+ class Supplier < Api
3
+
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Skippr
2
+ class Task < Api
3
+
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Skippr
2
+ class Unit < Api
3
+
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Skippr
2
+ class User < Api
3
+
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module Skippr
2
+ VERSION = "0.0.3"
3
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'skippr/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "skippr-rb"
8
+ spec.version = Skippr::VERSION
9
+ spec.authors = ["Sebastian M. Gauck"]
10
+ spec.email = ["smg@42ls.de"]
11
+ spec.description = %q{gem to consume the api of our invoicing tool https://skippr.com}
12
+ spec.summary = %q{skippr api gem}
13
+ spec.homepage = "http://github.com/fortytools/skippr-rb"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+
24
+ spec.add_dependency("activeresource")
25
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: skippr-rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Sebastian M. Gauck
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-10-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activeresource
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: gem to consume the api of our invoicing tool https://skippr.com
56
+ email:
57
+ - smg@42ls.de
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - lib/skippr-rb.rb
68
+ - lib/skippr/active_resource/base.rb
69
+ - lib/skippr/api.rb
70
+ - lib/skippr/exceptions.rb
71
+ - lib/skippr/resources/account.rb
72
+ - lib/skippr/resources/attachment_type.rb
73
+ - lib/skippr/resources/bank_account.rb
74
+ - lib/skippr/resources/customer.rb
75
+ - lib/skippr/resources/customer_state.rb
76
+ - lib/skippr/resources/employee.rb
77
+ - lib/skippr/resources/event.rb
78
+ - lib/skippr/resources/invoice.rb
79
+ - lib/skippr/resources/invoice_position.rb
80
+ - lib/skippr/resources/item.rb
81
+ - lib/skippr/resources/item_category.rb
82
+ - lib/skippr/resources/item_order.rb
83
+ - lib/skippr/resources/offer.rb
84
+ - lib/skippr/resources/service_type.rb
85
+ - lib/skippr/resources/supplier.rb
86
+ - lib/skippr/resources/task.rb
87
+ - lib/skippr/resources/unit.rb
88
+ - lib/skippr/resources/user.rb
89
+ - lib/skippr/version.rb
90
+ - skippr-rb.gemspec
91
+ homepage: http://github.com/fortytools/skippr-rb
92
+ licenses:
93
+ - MIT
94
+ metadata: {}
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubyforge_project:
111
+ rubygems_version: 2.4.5.1
112
+ signing_key:
113
+ specification_version: 4
114
+ summary: skippr api gem
115
+ test_files: []