sk_api_schema 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/json/v1.0/address.json +1 -2
- data/json/v1.0/attachment.json +59 -0
- data/json/v1.0/invoice.json +7 -0
- data/lib/sk_api_schema.rb +65 -1
- data/sk_api_schema.gemspec +6 -6
- data/spec/sk_api_schema_spec.rb +76 -0
- data/spec/spec_helper.rb +1 -1
- metadata +7 -7
- data/lib/utils/serializer.rb +0 -66
- data/spec/utils/field_map_spec.rb +0 -73
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.2
|
data/json/v1.0/address.json
CHANGED
@@ -0,0 +1,59 @@
|
|
1
|
+
{ "type":"object",
|
2
|
+
"title": "attachment",
|
3
|
+
"description":"An file attachment",
|
4
|
+
"properties": {
|
5
|
+
"id": {
|
6
|
+
"description": "uuid of the object.",
|
7
|
+
"identity":true,
|
8
|
+
"readonly":true,
|
9
|
+
"type":"string"
|
10
|
+
},
|
11
|
+
"filename": {
|
12
|
+
"description": "The filename as set when uploaded",
|
13
|
+
"optional":true,
|
14
|
+
"readonly":true,
|
15
|
+
"type":"string"
|
16
|
+
},
|
17
|
+
"disk_filename": {
|
18
|
+
"description": "The filename as set by SK",
|
19
|
+
"optional":true,
|
20
|
+
"readonly":true,
|
21
|
+
"type":"string"
|
22
|
+
},
|
23
|
+
"url": {
|
24
|
+
"description": "File download url. Unique and valid for 15 minutes, public accessible.",
|
25
|
+
"optional":true,
|
26
|
+
"readonly":true,
|
27
|
+
"type":"string"
|
28
|
+
},
|
29
|
+
"content_type": {
|
30
|
+
"description": "Auto detected on upload. Might not always reflect the real content type",
|
31
|
+
"optional":true,
|
32
|
+
"readonly":true,
|
33
|
+
"type":"string"
|
34
|
+
},
|
35
|
+
"size": {
|
36
|
+
"description": "Filesize in kb. Auto detected on upload.",
|
37
|
+
"optional":true,
|
38
|
+
"readonly":true,
|
39
|
+
"type":"integer"
|
40
|
+
},
|
41
|
+
"is_signed": {
|
42
|
+
"description": "True if the file(pdf) has been digitally signed.",
|
43
|
+
"optional":true,
|
44
|
+
"type":"boolean"
|
45
|
+
},
|
46
|
+
"created_at": {
|
47
|
+
"description": "Date the object was created in SK. Never changes aftwerwards",
|
48
|
+
"format":"date-time",
|
49
|
+
"readonly":true, "type":"string"
|
50
|
+
},
|
51
|
+
"updated_at": {
|
52
|
+
"description": "Date the object was edited in SK.",
|
53
|
+
"format":"date-time",
|
54
|
+
"readonly":true,
|
55
|
+
"type":"string"
|
56
|
+
}
|
57
|
+
|
58
|
+
}
|
59
|
+
}
|
data/json/v1.0/invoice.json
CHANGED
@@ -76,6 +76,13 @@
|
|
76
76
|
"type":"object",
|
77
77
|
"properties":{"$ref":"./client.json#properties"}
|
78
78
|
},
|
79
|
+
"archived_pdf":{
|
80
|
+
"description": "Archived PDF version of the document. Is created when an document is printed and archived. A document can have multiple archived versions. This only returns the most recent one. ",
|
81
|
+
"optional":true,
|
82
|
+
"readonly":true,
|
83
|
+
"type":"object",
|
84
|
+
"properties":{"$ref":"./attachment.json#properties"}
|
85
|
+
},
|
79
86
|
"client_id":{
|
80
87
|
"description": "The clients uuid, must be set for a new document. New invoices take the clients address field, due days and cash discount if those fields are not set.",
|
81
88
|
"type":"string"
|
data/lib/sk_api_schema.rb
CHANGED
@@ -1 +1,65 @@
|
|
1
|
-
require 'activesupport'
|
1
|
+
require 'activesupport'
|
2
|
+
|
3
|
+
module SK
|
4
|
+
module Api
|
5
|
+
class Schema
|
6
|
+
|
7
|
+
# Read a schema with a given version and return it as hash
|
8
|
+
# See ../json folder for available schema's and versions
|
9
|
+
# === Parameter
|
10
|
+
# schema<String|Symbol>::name of the schema, available ones are in json directory
|
11
|
+
# version<String>:: version to read, this is the folder name where the schema is in.
|
12
|
+
def self.read(schema, version)
|
13
|
+
file_path = File.join(File.dirname(__FILE__), '../json', version, "#{schema}.json")
|
14
|
+
plain_data = File.open(file_path, 'r'){|f| f.read}
|
15
|
+
ActiveSupport::JSON.decode(plain_data)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Create a Hash with the available (api)object attributes defined in
|
19
|
+
# schema properties.
|
20
|
+
#
|
21
|
+
# === Example
|
22
|
+
# obj = Invoice.new(:title =>'hello world', :number=>'4711')
|
23
|
+
# obj_hash = Sk::Api::Schema.to_hash_from_schema(obj, 'v1.0')
|
24
|
+
#
|
25
|
+
# obj_hash => { invoice =>{'title'=>'hello world', 'number'=>'4711' } }
|
26
|
+
#
|
27
|
+
# === Parameter
|
28
|
+
# obj<Object>:. An ruby object which is returned as hash
|
29
|
+
# version<String>:. An ruby object which is returned as hash
|
30
|
+
# === Return
|
31
|
+
# <Hash{String=>{String=>Mixed}}>:: The object as hash:
|
32
|
+
# { invoice =>{'title'=>'hello world', 'number'=>''4711 } }
|
33
|
+
def self.to_hash_from_schema(obj, version)
|
34
|
+
# get objects class name without inheritance
|
35
|
+
obj_class_name = obj.class.name.split('::').last.underscore
|
36
|
+
# init data hash
|
37
|
+
data = {}
|
38
|
+
# get schema
|
39
|
+
schema = self.read(obj_class_name, version)
|
40
|
+
# iterate over the defined schema fields
|
41
|
+
schema['properties'].each do |field, prop|
|
42
|
+
if prop['type'] == 'array'
|
43
|
+
# always set an empty array
|
44
|
+
data[field] = []
|
45
|
+
if rel_objects = obj.send( field )
|
46
|
+
rel_objects.each do |rel_obj|
|
47
|
+
# call related objects to_hash_from_schema method ex: data[:client][:addresses] << SKApi::Models::Address.to_hash_from_schema(object)
|
48
|
+
data[field] << self.to_hash_from_schema(rel_obj, version)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
elsif prop['type'] == 'object' # a singular related object
|
52
|
+
data[field] = nil
|
53
|
+
if rel_obj = obj.send( field )
|
54
|
+
data[field] = self.to_hash_from_schema(rel_obj, version)
|
55
|
+
end
|
56
|
+
else # a simple field is only added if objects know its
|
57
|
+
data[field] = obj.send(field) if obj.respond_to?(field.to_sym)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
{ obj_class_name => data }
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/sk_api_schema.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{sk_api_schema}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Georg Leciejewski"]
|
12
|
-
s.date = %q{2010-11-
|
12
|
+
s.date = %q{2010-11-11}
|
13
13
|
s.description = %q{SalesKing API JSON schema and utility methods}
|
14
14
|
s.email = %q{gl@salesking.eu}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -21,15 +21,15 @@ Gem::Specification.new do |s|
|
|
21
21
|
"Rakefile",
|
22
22
|
"VERSION",
|
23
23
|
"json/v1.0/address.json",
|
24
|
+
"json/v1.0/attachment.json",
|
24
25
|
"json/v1.0/client.json",
|
25
26
|
"json/v1.0/credit_note.json",
|
26
27
|
"json/v1.0/invoice.json",
|
27
28
|
"json/v1.0/line_item.json",
|
28
29
|
"lib/sk_api_schema.rb",
|
29
|
-
"lib/utils/serializer.rb",
|
30
30
|
"sk_api_schema.gemspec",
|
31
|
-
"spec/
|
32
|
-
"spec/
|
31
|
+
"spec/sk_api_schema_spec.rb",
|
32
|
+
"spec/spec_helper.rb"
|
33
33
|
]
|
34
34
|
s.homepage = %q{http://github.com/salesking/sk_api_schema}
|
35
35
|
s.rdoc_options = ["--charset=UTF-8"]
|
@@ -38,7 +38,7 @@ Gem::Specification.new do |s|
|
|
38
38
|
s.summary = %q{SalesKing API JSON Schema}
|
39
39
|
s.test_files = [
|
40
40
|
"spec/spec_helper.rb",
|
41
|
-
"spec/
|
41
|
+
"spec/sk_api_schema_spec.rb"
|
42
42
|
]
|
43
43
|
|
44
44
|
if s.respond_to? :specification_version then
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe SK::Api::Schema do
|
4
|
+
|
5
|
+
it "should read json schema file" do
|
6
|
+
schema = SK::Api::Schema.read(:invoice, 'v1.0')
|
7
|
+
schema['title'].should == 'invoice'
|
8
|
+
schema['type'].should == 'object'
|
9
|
+
schema['properties'].should be_a Hash
|
10
|
+
schema['properties']['id']['identity'].should be_true
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should raise error if version folder does not exist" do
|
14
|
+
lambda{
|
15
|
+
SK::Api::Schema.read(:invoice, 'v3.0')
|
16
|
+
}.should raise_error
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should raise error if schema file does not exist" do
|
20
|
+
lambda{
|
21
|
+
SK::Api::Schema.read(:nope, 'v1.0')
|
22
|
+
}.should raise_error
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
describe SK::Api::Schema, 'object parsing' do
|
28
|
+
|
29
|
+
before :each do
|
30
|
+
@invoice = Invoice.new
|
31
|
+
@invoice.id = 'some-uuid'
|
32
|
+
@invoice.title = 'Your Invoice'
|
33
|
+
@invoice.number = '911'
|
34
|
+
|
35
|
+
@client = Client.new
|
36
|
+
@client.id = 'some-uuid'
|
37
|
+
@client.organisation = 'Dirty Food Inc.'
|
38
|
+
@client.number = '911'
|
39
|
+
|
40
|
+
@item = LineItem.new
|
41
|
+
@item.id = 'some-uuid'
|
42
|
+
@item.name = 'Pork Chops'
|
43
|
+
@item.description = 'Yummi Pork chopped by mexian emigrants'
|
44
|
+
@item.position = 1
|
45
|
+
@item.price_single = 0.99
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
it "should parse object without relations from schema" do
|
50
|
+
obj_hash = SK::Api::Schema.to_hash_from_schema(@invoice, 'v1.0')
|
51
|
+
obj_hash.should == {"invoice"=>{"number"=>"911", "line_items"=>[], "title"=>"Your Invoice", "id"=>"some-uuid", "date"=>nil, "client"=>nil, "due_date"=>nil}}
|
52
|
+
client_obj_hash = SK::Api::Schema.to_hash_from_schema(@client, 'v1.0')
|
53
|
+
client_obj_hash.should == {"client"=>{"number"=>"911", "addresses"=>[], "id"=>"some-uuid", "organisation"=>"Dirty Food Inc.", "last_name"=>nil}}
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should parse object with relations from schema" do
|
57
|
+
@invoice.line_items = [@item]
|
58
|
+
@invoice.client = @client
|
59
|
+
obj_hash = SK::Api::Schema.to_hash_from_schema(@invoice, 'v1.0')
|
60
|
+
obj_hash.should == {"invoice"=>{"number"=>"911", "line_items"=>[{"line_item"=>{"position"=>1, "name"=>"Pork Chops", "id"=>"some-uuid", "description"=>"Yummi Pork chopped by mexian emigrants", "price_single"=>0.99}}], "title"=>"Your Invoice", "id"=>"some-uuid", "date"=>nil, "client"=>{"client"=>{"number"=>"911", "addresses"=>[], "id"=>"some-uuid", "organisation"=>"Dirty Food Inc.", "last_name"=>nil}}, "due_date"=>nil}}
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
################################################################################
|
66
|
+
# virtual classes used in test
|
67
|
+
class Invoice
|
68
|
+
attr_accessor :id, :title, :description, :number, :date, :due_date, :line_items, :client
|
69
|
+
end
|
70
|
+
|
71
|
+
class LineItem
|
72
|
+
attr_accessor :id, :name, :description, :position, :price_single
|
73
|
+
end
|
74
|
+
class Client
|
75
|
+
attr_accessor :id, :organisation, :last_name, :number, :addresses
|
76
|
+
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sk_api_schema
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Georg Leciejewski
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-11-
|
18
|
+
date: 2010-11-11 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -60,15 +60,15 @@ files:
|
|
60
60
|
- Rakefile
|
61
61
|
- VERSION
|
62
62
|
- json/v1.0/address.json
|
63
|
+
- json/v1.0/attachment.json
|
63
64
|
- json/v1.0/client.json
|
64
65
|
- json/v1.0/credit_note.json
|
65
66
|
- json/v1.0/invoice.json
|
66
67
|
- json/v1.0/line_item.json
|
67
68
|
- lib/sk_api_schema.rb
|
68
|
-
- lib/utils/serializer.rb
|
69
69
|
- sk_api_schema.gemspec
|
70
|
+
- spec/sk_api_schema_spec.rb
|
70
71
|
- spec/spec_helper.rb
|
71
|
-
- spec/utils/field_map_spec.rb
|
72
72
|
has_rdoc: true
|
73
73
|
homepage: http://github.com/salesking/sk_api_schema
|
74
74
|
licenses: []
|
@@ -105,4 +105,4 @@ specification_version: 3
|
|
105
105
|
summary: SalesKing API JSON Schema
|
106
106
|
test_files:
|
107
107
|
- spec/spec_helper.rb
|
108
|
-
- spec/
|
108
|
+
- spec/sk_api_schema_spec.rb
|
data/lib/utils/serializer.rb
DELETED
@@ -1,66 +0,0 @@
|
|
1
|
-
module SKApi
|
2
|
-
module Utils
|
3
|
-
# Mixed into Resources::Base providing to_hash and to_json serialisation for
|
4
|
-
# SKApi Resources.
|
5
|
-
# Inside SalesKing this serialising is used to render the output.
|
6
|
-
# f.ex. in the clients api controller
|
7
|
-
# => SKApi::Resources::Client.to_json(a_client)
|
8
|
-
# This way you can keep your API client up to date by using the resources and
|
9
|
-
# relying on SKApi::Resources::Client.schema
|
10
|
-
module Serializer
|
11
|
-
def self.included(base)
|
12
|
-
base.extend ClassMethods
|
13
|
-
end
|
14
|
-
|
15
|
-
module ClassMethods
|
16
|
-
|
17
|
-
def schema_to_hash
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
# Create a Hash with the available (api)object attributes defined in api_fields.
|
22
|
-
#
|
23
|
-
# ==== Parameter
|
24
|
-
# obj<object>:. An ruby object which is returned as hash
|
25
|
-
def to_hash_from_schema(obj)
|
26
|
-
# first set the root node to the objects class name as symbol
|
27
|
-
obj_class_name = obj.class.name.split('::').last.underscore
|
28
|
-
# obj_class_name = obj.class.to_s.underscore.to_sym
|
29
|
-
data = { obj_class_name => {} }
|
30
|
-
# iterate over the defined api fields hash
|
31
|
-
self.schema_props.each do |field, props|
|
32
|
-
if props['type'] == 'array'
|
33
|
-
# always set the field, so the user can expect an empty array
|
34
|
-
data[obj_class_name][field] = []
|
35
|
-
if rel_objects = obj.send( field )
|
36
|
-
rel_objects.each do |rel_obj|
|
37
|
-
# setup scope for related class
|
38
|
-
klass = "SKApi::Resources::#{rel_obj.class}".constantize
|
39
|
-
# call related objects to_hash_from_schema method ex: data[:client][:addresses] << SKApi::Models::Address.to_hash_from_schema(object)
|
40
|
-
data[obj_class_name][field] << klass.to_hash_from_schema(rel_obj)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
elsif props['type'] == 'object' # a singular resource TODO should we add an empty object?
|
44
|
-
if rel_obj = obj.send( field )
|
45
|
-
klass = "SKApi::Resources::#{rel_obj.class}".constantize
|
46
|
-
# ex: data['invoice']['client'] = SKApi::Models::Client.to_hash_from_schema(client)
|
47
|
-
data[obj_class_name][field] = klass.to_hash_from_schema(rel_obj)
|
48
|
-
end
|
49
|
-
else # a simple field which can be directly called, only added of objects know its
|
50
|
-
data[obj_class_name][field] = obj.send(field) if obj.respond_to?(field.to_sym)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
data
|
54
|
-
end
|
55
|
-
|
56
|
-
def to_json(obj)
|
57
|
-
data = self.to_hash_from_schema(obj)
|
58
|
-
# data[:links] = self.api_links
|
59
|
-
ActiveSupport::JSON.encode(data)
|
60
|
-
end
|
61
|
-
|
62
|
-
end #ClassMethods
|
63
|
-
|
64
|
-
end #mixin
|
65
|
-
end #utils
|
66
|
-
end #SKApi
|
@@ -1,73 +0,0 @@
|
|
1
|
-
require 'spec/spec_helper'
|
2
|
-
|
3
|
-
describe SKApi::Utils::FieldMap do
|
4
|
-
|
5
|
-
before :each do
|
6
|
-
@loc_obj = LocalContact.new
|
7
|
-
@rem_obj = RemoteContact.new()
|
8
|
-
@map = SKApi::Utils::FieldMap.new(@loc_obj, @rem_obj, map_hash)
|
9
|
-
end
|
10
|
-
|
11
|
-
it "should create a mapping" do
|
12
|
-
@map.outdated?.should be_false # both objects are empty
|
13
|
-
end
|
14
|
-
|
15
|
-
it "should find outdated fields" do
|
16
|
-
@loc_obj.firstname = 'theo'
|
17
|
-
@map.outdated?.should be_true
|
18
|
-
@map.outdated.first[:loc_key].should == :firstname
|
19
|
-
end
|
20
|
-
|
21
|
-
it "should update outdated remote fields" do
|
22
|
-
@loc_obj.firstname = 'theo'
|
23
|
-
@map.update_remote_outdated
|
24
|
-
@rem_obj.first_name.should == @loc_obj.firstname
|
25
|
-
# test logging
|
26
|
-
@map.log.should_not be_empty
|
27
|
-
end
|
28
|
-
|
29
|
-
it "should update outdated local fields" do
|
30
|
-
@rem_obj.first_name = 'Heinz'
|
31
|
-
@map.update_local_outdated
|
32
|
-
@rem_obj.first_name.should == @loc_obj.firstname
|
33
|
-
@map.log.length.should == 1
|
34
|
-
end
|
35
|
-
# it "should update outdated local fields" do
|
36
|
-
# @rem_obj.first_name = 'Heinz'
|
37
|
-
# @map.outdated?
|
38
|
-
# @map.update_local_outdated
|
39
|
-
# @rem_obj.first_name.should == @loc_obj.firstname
|
40
|
-
# end
|
41
|
-
|
42
|
-
def map_hash
|
43
|
-
[
|
44
|
-
{:loc_key => :firstname, :rem_key => :first_name},
|
45
|
-
{:loc_key => :street, :rem_key => :address1},
|
46
|
-
{:loc_key => :postcode, :rem_key => :zip},
|
47
|
-
{:loc_key => :city, :rem_key => :city},
|
48
|
-
{:loc_key => :gender, :rem_key => :gender, :trans => { :obj=>'TransferFunctions',
|
49
|
-
:loc_trans => 'set_local_gender',
|
50
|
-
:rem_trans => 'set_remote_gender'}
|
51
|
-
}
|
52
|
-
]
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
56
|
-
|
57
|
-
class RemoteContact
|
58
|
-
attr_accessor :first_name, :address1, :zip, :city, :gender
|
59
|
-
end
|
60
|
-
class LocalContact
|
61
|
-
attr_accessor :firstname, :street, :postcode, :city, :gender
|
62
|
-
end
|
63
|
-
|
64
|
-
class TransferFunctions
|
65
|
-
def self.set_local_gender(remote_val)
|
66
|
-
return 'male' if remote_val == 'm'
|
67
|
-
return 'female' if remote_val == 'f'
|
68
|
-
end
|
69
|
-
def self.set_remote_gender(local_val)
|
70
|
-
return 'm' if local_val == 'male'
|
71
|
-
return 'f' if local_val == 'female'
|
72
|
-
end
|
73
|
-
end
|