solve360 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -41,17 +41,17 @@ And if you're using environments like Rails:
41
41
 
42
42
  Base attributes are set up for you. Creating is simple:
43
43
 
44
- Solve360::Contact.create("First Name" => "Stephen", "Last Name" => "Bartholomew")
44
+ Solve360::Contact.create(:fields => "First Name" => "Stephen", "Last Name" => "Bartholomew")
45
45
 
46
46
  Custom attributes can be added:
47
47
 
48
- Solve360::Contact.fields do
48
+ Solve360::Contact.map_fields do
49
49
  {"Description" => "custom20394", "Location" => "custom392434"}
50
50
  end
51
51
 
52
52
  and then used:
53
53
 
54
- contact = Solve360::Contact.create("First Name" => "Steve", "Description" => "Web Developer", "Location" => "England")
54
+ contact = Solve360::Contact.create(:fields => "First Name" => "Steve", "Description" => "Web Developer", "Location" => "England")
55
55
  contact.id
56
56
  => The ID of the record created on the CRM
57
57
 
@@ -65,11 +65,23 @@ You can find by the ID of a record on the CRM:
65
65
 
66
66
  Once you have set the attributes on a model you can simply save:
67
67
 
68
- contact.attributes["First Name"] = "Steve"
68
+ contact.fields["First Name"] = "Steve"
69
69
  contact.save
70
70
 
71
71
  If the record does not have an ID it'll be created, otherwise the details will be saved.
72
72
 
73
+ ### Related Items
74
+
75
+ Related items can be access via:
76
+
77
+ contact.related_items
78
+ => {"name" => "Curve21", "id" => "12345"}
79
+
80
+ And added:
81
+
82
+ contact.add_related_item({"name" => "ACME Ltd", "id" => "91284"})
83
+ contact.save
84
+
73
85
  ## Support/Bugs
74
86
 
75
87
  [Lighthouse](http://c21.lighthouseapp.com/projects/38966-solve360/overview)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.3
1
+ 0.0.4
data/lib/solve360.rb CHANGED
@@ -4,6 +4,6 @@ require "active_support/inflector"
4
4
  require "active_support/core_ext/hash"
5
5
 
6
6
 
7
- ["model", "config", "contact", "company"].each do |lib|
7
+ ["item", "config", "contact", "company"].each do |lib|
8
8
  require File.join(File.dirname(__FILE__), "solve360", lib)
9
9
  end
@@ -1,8 +1,8 @@
1
1
  module Solve360
2
2
  class Company
3
- include Solve360::Model
3
+ include Solve360::Item
4
4
 
5
- fields do
5
+ map_fields do
6
6
  {"Billing Address" => "billingaddress",
7
7
  "Company Address" => "mainaddress",
8
8
  "Company Fax" => "fax",
@@ -1,8 +1,8 @@
1
1
  module Solve360
2
2
  class Contact
3
- include Solve360::Model
3
+ include Solve360::Item
4
4
 
5
- fields do
5
+ map_fields do
6
6
  {"Business Address" => "businessaddress",
7
7
  "Business Direct" => "businessphonedirect",
8
8
  "Business Email" => "businessemail",
@@ -0,0 +1,189 @@
1
+ module Solve360
2
+ module Item
3
+
4
+ def self.included(model)
5
+ model.extend ClassMethods
6
+ model.send(:include, HTTParty)
7
+ model.instance_variable_set(:@field_mapping, {})
8
+ end
9
+
10
+ # Base Item fields
11
+ attr_accessor :id, :name, :typeid, :created, :updated, :viewed, :ownership, :flagged
12
+
13
+ # Base item collections
14
+ attr_accessor :fields, :related_items, :related_items_to_add
15
+
16
+ def initialize(attributes = {})
17
+ attributes.symbolize_keys!
18
+
19
+ self.fields = {}
20
+ self.related_items = []
21
+ self.related_items_to_add = []
22
+
23
+ [:fields, :related_items].each do |collection|
24
+ self.send("#{collection}=", attributes[collection]) if attributes[collection]
25
+ attributes.delete collection
26
+ end
27
+
28
+ attributes.each do |key, value|
29
+ self.send("#{key}=", value)
30
+ end
31
+ end
32
+
33
+ # @see Base::map_human_attributes
34
+ def map_human_fields
35
+ self.class.map_human_fields(self.fields)
36
+ end
37
+
38
+ # Save the attributes for the current record to the CRM
39
+ #
40
+ # If the record is new it will be created on the CRM
41
+ #
42
+ # @return [Hash] response values from API
43
+ def save
44
+ response = []
45
+ if new_record?
46
+ response = self.class.request(:post, "/#{self.class.resource_name}", to_request)
47
+ self.id = response["response"]["item"]["id"]
48
+ else
49
+ response = self.class.request(:put, "/#{self.class.resource_name}/#{id}", to_request)
50
+ end
51
+
52
+ related_items.concat(related_items_to_add)
53
+
54
+ response
55
+ end
56
+
57
+ def new_record?
58
+ self.id == nil
59
+ end
60
+
61
+ def to_request
62
+ xml = "<request>"
63
+
64
+ xml << map_human_fields.collect {|key, value| "<#{key}>#{value}</#{key}>"}.join("")
65
+
66
+ if related_items_to_add.size > 0
67
+ xml << "<relateditems>"
68
+
69
+ related_items_to_add.each do |related_item|
70
+ xml << %Q{<add><relatedto><id>#{related_item["id"]}</id></relatedto></add>}
71
+ end
72
+
73
+ xml << "</relateditems>"
74
+ end
75
+ xml << "</request>"
76
+
77
+ xml
78
+ end
79
+
80
+ def add_related_item(item)
81
+ related_items_to_add << item
82
+ end
83
+
84
+ module ClassMethods
85
+
86
+ # Map human map_human_fields to API fields
87
+ #
88
+ # @param [Hash] human mapped fields
89
+ # @example
90
+ # map_attributes("First Name" => "Steve", "Description" => "Web Developer")
91
+ # => {:firstname => "Steve", :custom12345 => "Web Developer"}
92
+ #
93
+ # @return [Hash] API mapped attributes
94
+ #
95
+ def map_human_fields(fields)
96
+ mapped_fields = {}
97
+
98
+ field_mapping.each do |human, api|
99
+ mapped_fields[api] = fields[human] if !fields[human].blank?
100
+ end
101
+
102
+ mapped_fields
103
+ end
104
+
105
+ # As ::map_api_fields but API -> human
106
+ #
107
+ # @param [Hash] API mapped attributes
108
+ # @example
109
+ # map_attributes(:firstname => "Steve", :custom12345 => "Web Developer")
110
+ # => {"First Name" => "Steve", "Description" => "Web Developer"}
111
+ #
112
+ # @return [Hash] human mapped attributes
113
+ def map_api_fields(fields)
114
+ fields.stringify_keys!
115
+
116
+ mapped_fields = {}
117
+
118
+ field_mapping.each do |human, api|
119
+ mapped_fields[human] = fields[api] if !fields[api].blank?
120
+ end
121
+
122
+ mapped_fields
123
+ end
124
+
125
+ # Create a record in the API
126
+ #
127
+ # @param [Hash] field => value as configured in Item::fields
128
+ def create(fields, options = {})
129
+ new_record = self.new(fields)
130
+ new_record.save
131
+ new_record
132
+ end
133
+
134
+ # Find a record
135
+ #
136
+ # @param [Integer] id of the record on the CRM
137
+ def find(id)
138
+ response = request(:get, "/#{resource_name}/#{id}")
139
+
140
+ construct_record_from_response(response)
141
+ end
142
+
143
+ # Send an HTTP request
144
+ #
145
+ # @param [Symbol, String] :get, :post, :put or :delete
146
+ # @param [String] url of the resource
147
+ # @param [String, nil] optional string to send in request body
148
+ def request(verb, uri, body = "")
149
+ send(verb, HTTParty.normalize_base_uri(Solve360::Config.config.url) + uri,
150
+ :headers => {"Content-Type" => "application/xml", "Accepts" => "application/json"},
151
+ :body => body,
152
+ :basic_auth => {:username => Solve360::Config.config.username, :password => Solve360::Config.config.token})
153
+ end
154
+
155
+ def construct_record_from_response(response)
156
+ item = response["response"]["item"]
157
+ item.symbolize_keys!
158
+
159
+ item[:fields] = map_api_fields(item[:fields])
160
+
161
+ record = new(item)
162
+
163
+ if response["response"]["relateditems"]
164
+ related_items = response["response"]["relateditems"]["relatedto"]
165
+
166
+ if related_items.kind_of?(Array)
167
+ record.related_items.concat(related_items)
168
+ else
169
+ record.related_items = [related_items]
170
+ end
171
+ end
172
+
173
+ record
174
+ end
175
+
176
+ def resource_name
177
+ self.name.to_s.demodulize.underscore.pluralize
178
+ end
179
+
180
+ def map_fields(&block)
181
+ @field_mapping.merge! yield
182
+ end
183
+
184
+ def field_mapping
185
+ @field_mapping
186
+ end
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,161 @@
1
+ require File.join(File.dirname(__FILE__), "..", "spec_helper")
2
+
3
+ class Person
4
+ include Solve360::Item
5
+
6
+ map_fields do
7
+ { "Job Title" => "job_title", "Name" => "name" }
8
+ end
9
+ end
10
+
11
+ describe "A Solve360 model" do
12
+ it "should determine model name" do
13
+ Person.resource_name.should == "people"
14
+ end
15
+
16
+ context "more than one model" do
17
+ it "should not pollute map" do
18
+ class Car
19
+ include Solve360::Item
20
+ map_fields do
21
+ { "Doors" => "doors" }
22
+ end
23
+ end
24
+
25
+ Car.field_mapping.keys.include?("Job Title").should be_false
26
+ Person.field_mapping.keys.include?("Doors").should be_false
27
+ end
28
+ end
29
+
30
+ context "XML respresentation" do
31
+ before do
32
+ @person = Person.new(:fields => {"Name" => "Stephen"})
33
+ @person.add_related_item({"name" => "Curve21", "id" => "12345"})
34
+
35
+ @xml = Crack::XML.parse(@person.to_request)
36
+ end
37
+
38
+ it "should contain related items to add" do
39
+ @xml["request"]["relateditems"]["add"]["relatedto"]["id"].should == "12345"
40
+ end
41
+
42
+ it "should contain item fields" do
43
+ @xml["request"]["name"].should == "Stephen"
44
+ end
45
+ end
46
+ end
47
+
48
+ describe "Field mapping" do
49
+ before do
50
+ Person.map_fields do
51
+ {"Interests" => "custom_interests",
52
+ "Department Website" => "custom_deptwebsite",
53
+ "Description" => "custom_description"}
54
+ end
55
+
56
+ @person = Person.new
57
+ end
58
+
59
+ it "should set base map" do
60
+ Person.field_mapping["Job Title"].should == "job_title"
61
+ end
62
+
63
+ it "should set custom map" do
64
+ Person.field_mapping["Interests"].should == "custom_interests"
65
+ end
66
+
67
+ it "should allow setting of values on an instance via field maps" do
68
+ @person.fields["Interests"] = "Coding"
69
+ @person.fields["Interests"].should == "Coding"
70
+ end
71
+
72
+ it "should map human fields to API fields" do
73
+ fields = {"Description" => "A description"}
74
+
75
+ Person.map_human_fields(fields)["custom_description"].should == "A description"
76
+ end
77
+
78
+ it "should map API fields to human fields" do
79
+ fields = {:custom_description => "A description"}
80
+
81
+ Person.map_api_fields(fields)["Description"].should == "A description"
82
+ end
83
+ end
84
+
85
+ describe "Creating a record" do
86
+ context "directly from create" do
87
+ before do
88
+ stub_http_response_with("contacts/create-success.json")
89
+ @contact = Solve360::Contact.create(:fields => {"First Name" => "Catherine"})
90
+ end
91
+
92
+ it "should be valid" do
93
+ @contact.fields["First Name"].should == "Catherine"
94
+ @contact.id.should == "12345"
95
+ end
96
+ end
97
+
98
+ context "creating a new object then saving" do
99
+ before do
100
+ stub_http_response_with("contacts/create-success.json")
101
+ @contact = Solve360::Contact.new(:fields => {"First Name" => "Catherine"})
102
+ @contact.save
103
+ end
104
+
105
+ it "should be valid" do
106
+ @contact.id.should == "12345"
107
+ end
108
+ end
109
+ end
110
+
111
+ describe "Finding a record" do
112
+ context "Successfully" do
113
+ before do
114
+ stub_http_response_with("contacts/find-success.json")
115
+ @contact = Solve360::Contact.find(12345)
116
+ end
117
+
118
+ it "should find existing user" do
119
+ @contact.fields["First Name"].should == "Henry"
120
+ @contact.id.should == "12345"
121
+ end
122
+
123
+ it "should have relations" do
124
+ @contact.related_items.first["name"].should == "Curve21"
125
+ end
126
+ end
127
+ end
128
+
129
+ describe "Updating a record" do
130
+ before do
131
+ @contact = Solve360::Contact.new(:fields => {"First Name" => "Steve"})
132
+
133
+ @contact.id = "12345"
134
+
135
+ stub_http_response_with("contacts/update-success.json")
136
+
137
+ @contact.fields["First Name"] = "Steve"
138
+
139
+ @response = @contact.save
140
+ end
141
+
142
+ it "should be valid" do
143
+ @response["response"]["status"].should == "success"
144
+ end
145
+ end
146
+
147
+ describe "Adding a releated item" do
148
+ before do
149
+ @contact = Solve360::Contact.new(:fields => {"First Name" => "Steve"})
150
+ @contact.id = "12345"
151
+
152
+ stub_http_response_with("contacts/update-success.json")
153
+
154
+ @contact.add_related_item({"name" => "A New Company", "id" => "932334"})
155
+ @contact.save
156
+ end
157
+
158
+ it "should become set after save" do
159
+ @contact.related_items.first["name"].should == "A New Company"
160
+ end
161
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solve360
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Bartholomew
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-16 00:00:00 +01:00
12
+ date: 2009-10-22 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -59,7 +59,7 @@ files:
59
59
  - lib/solve360/company.rb
60
60
  - lib/solve360/config.rb
61
61
  - lib/solve360/contact.rb
62
- - lib/solve360/model.rb
62
+ - lib/solve360/item.rb
63
63
  - spec/api_settings.yml
64
64
  - spec/api_settings.yml.sample
65
65
  - spec/fixtures/contacts/create-success.json
@@ -69,7 +69,7 @@ files:
69
69
  - spec/fixtures/contacts/show-success.json
70
70
  - spec/fixtures/contacts/update-failed.json
71
71
  - spec/fixtures/contacts/update-success.json
72
- - spec/solve360/model_spec.rb
72
+ - spec/solve360/item_spec.rb
73
73
  - spec/spec.opts
74
74
  - spec/spec_helper.rb
75
75
  has_rdoc: true
@@ -101,5 +101,5 @@ signing_key:
101
101
  specification_version: 3
102
102
  summary: Libary for working with the Solve360 CRM API
103
103
  test_files:
104
- - spec/solve360/model_spec.rb
104
+ - spec/solve360/item_spec.rb
105
105
  - spec/spec_helper.rb
@@ -1,141 +0,0 @@
1
- module Solve360
2
- module Model
3
-
4
- def self.included(model)
5
- model.extend ClassMethods
6
- model.send(:include, HTTParty)
7
- model.instance_variable_set(:@fields, {})
8
- end
9
-
10
- attr_accessor :attributes, :id, :relations
11
-
12
- def initialize(attributes = {})
13
- self.attributes = attributes
14
- self.relations = []
15
- self.id = nil
16
- end
17
-
18
- # @see Base::map_human_attributes
19
- def map_human_attributes
20
- self.class.map_human_attributes(self.attributes)
21
- end
22
-
23
- # Save the attributes for the current record to the CRM
24
- #
25
- # If the record is new it will be created on the CRM
26
- #
27
- # @return [Hash] response values from API
28
- def save
29
- if new_record?
30
- new_record = self.class.create(attributes)
31
- self.id = new_record.id
32
- else
33
- self.class.request(:put, "/#{self.class.resource_name}/#{id}", map_human_attributes.to_xml(:root => "request"))
34
- end
35
- end
36
-
37
- def new_record?
38
- self.id == nil
39
- end
40
-
41
- module ClassMethods
42
-
43
- # Map human attributes to API attributes
44
- #
45
- # @param [Hash] human mapped attributes
46
- # @example
47
- # map_attributes("First Name" => "Steve", "Description" => "Web Developer")
48
- # => {:firstname => "Steve", :custom12345 => "Web Developer"}
49
- #
50
- # @return [Hash] API mapped attributes
51
- #
52
- def map_human_attributes(attributes)
53
- mapped_attributes = {}
54
-
55
- fields.each do |human, api|
56
- mapped_attributes[api] = attributes[human] if !attributes[human].blank?
57
- end
58
-
59
- mapped_attributes
60
- end
61
-
62
- # As ::map_human_attributes but API -> human
63
- #
64
- # @param [Hash] API mapped attributes
65
- # @example
66
- # map_attributes(:firstname => "Steve", :custom12345 => "Web Developer")
67
- # => {"First Name" => "Steve", "Description" => "Web Developer"}
68
- #
69
- # @return [Hash] human mapped attributes
70
- def map_api_attributes(attributes)
71
- attributes.stringify_keys!
72
-
73
- mapped_attributes = {}
74
-
75
- fields.each do |human, api|
76
- mapped_attributes[human] = attributes[api] if !attributes[api].blank?
77
- end
78
-
79
- mapped_attributes
80
- end
81
-
82
- # Create a record in the API
83
- #
84
- # @param [Hash] field => value as configured in Model::fields
85
- def create(attributes, options = {})
86
- response = request(:post, "/#{resource_name}", map_human_attributes(attributes).to_xml(:root => "request"))
87
-
88
- construct_record_from_response(response)
89
- end
90
-
91
- # Find a record
92
- #
93
- # @param [Integer] id of the record on the CRM
94
- def find(id)
95
- response = request(:get, "/#{resource_name}/#{id}")
96
-
97
- construct_record_from_response(response)
98
- end
99
-
100
- # Send an HTTP request
101
- #
102
- # @param [Symbol, String] :get, :post, :put or :delete
103
- # @param [String] url of the resource
104
- # @param [String, nil] optional string to send in request body
105
- def request(verb, uri, body = "")
106
- send(verb, HTTParty.normalize_base_uri(Solve360::Config.config.url) + uri,
107
- :headers => {"Content-Type" => "application/xml", "Accepts" => "application/json"},
108
- :body => body,
109
- :basic_auth => {:username => Solve360::Config.config.username, :password => Solve360::Config.config.token})
110
- end
111
-
112
- def construct_record_from_response(response)
113
- attributes = map_api_attributes(response["response"]["item"]["fields"])
114
- record = new(attributes)
115
-
116
- related_to = response["response"]["relateditems"]["relatedto"]
117
-
118
- if related_to.kind_of?(Array)
119
- record.relations.concat(related_to)
120
- else
121
- record.relations << related_to
122
- end
123
-
124
- record.id = response["response"]["item"]["id"].to_i
125
- record
126
- end
127
-
128
- def resource_name
129
- self.name.to_s.demodulize.underscore.pluralize
130
- end
131
-
132
- def fields(&block)
133
- if block_given?
134
- @fields.merge! yield
135
- else
136
- @fields
137
- end
138
- end
139
- end
140
- end
141
- end
@@ -1,128 +0,0 @@
1
- require File.join(File.dirname(__FILE__), "..", "spec_helper")
2
-
3
- class Person
4
- include Solve360::Model
5
-
6
- fields do
7
- { "Job Title" => "job_title" }
8
- end
9
- end
10
-
11
- describe "A Solve360 model" do
12
- it "should determine model name" do
13
- Person.resource_name.should == "people"
14
- end
15
-
16
- context "more than one model" do
17
- it "should not pollute map" do
18
- class Car
19
- include Solve360::Model
20
- fields do
21
- { "Doors" => "doors" }
22
- end
23
- end
24
-
25
- Car.fields.keys.include?("Job Title").should be_false
26
- Person.fields.keys.include?("Doors").should be_false
27
- end
28
- end
29
- end
30
-
31
- describe "Field mapping" do
32
- before do
33
- Person.fields do
34
- {"Interests" => "custom_interests",
35
- "Department Website" => "custom_deptwebsite",
36
- "Description" => "custom_description"}
37
- end
38
-
39
- @person = Person.new
40
- end
41
-
42
- it "should set base map" do
43
- Person.fields["Job Title"].should == "job_title"
44
- end
45
-
46
- it "should set custom map" do
47
- Person.fields["Interests"].should == "custom_interests"
48
- end
49
-
50
- it "should allow setting of values on an instance via field maps" do
51
- @person.attributes["Interests"] = "Coding"
52
- @person.attributes["Interests"].should == "Coding"
53
- end
54
-
55
- it "should map human map to API map" do
56
- attributes = {"Description" => "A description"}
57
-
58
- Person.map_human_attributes(attributes)["custom_description"].should == "A description"
59
- end
60
-
61
- it "should map API map to human map" do
62
- attributes = {:custom_description => "A description"}
63
-
64
- Person.map_api_attributes(attributes)["Description"].should == "A description"
65
- end
66
- end
67
-
68
- describe "Creating a record" do
69
- context "directly from create" do
70
- before do
71
- stub_http_response_with("contacts/create-success.json")
72
- @contact = Solve360::Contact.create("First Name" => "Catherine")
73
- end
74
-
75
- it "should be valid" do
76
- @contact.attributes["First Name"].should == "Catherine"
77
- @contact.id.should == 12345
78
- end
79
- end
80
-
81
- context "creating a new object then saving" do
82
- before do
83
- stub_http_response_with("contacts/create-success.json")
84
- @contact = Solve360::Contact.new("First Name" => "Catherine")
85
- @contact.save
86
- end
87
-
88
- it "should be valid" do
89
- @contact.id.should == 12345
90
- end
91
- end
92
- end
93
-
94
- describe "Finding a record" do
95
- context "Successfully" do
96
- before do
97
- stub_http_response_with("contacts/find-success.json")
98
- @contact = Solve360::Contact.find(12345)
99
- end
100
-
101
- it "should find existing user" do
102
- @contact.attributes["First Name"].should == "Henry"
103
- @contact.id.should == 12345
104
- end
105
-
106
- it "should have relations" do
107
- @contact.relations.first["name"].should == "Curve21"
108
- end
109
- end
110
- end
111
-
112
- describe "Updating a record" do
113
- before do
114
- @contact = Solve360::Contact.new("First Name" => "Steve")
115
-
116
- @contact.id = 12345
117
-
118
- stub_http_response_with("contacts/update-success.json")
119
-
120
- @contact.attributes["First Name"] = "Steve"
121
-
122
- @response = @contact.save
123
- end
124
-
125
- it "should be valid" do
126
- @response["response"]["status"].should == "success"
127
- end
128
- end