insightly 0.2.8 → 0.2.9
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +5 -0
- data/lib/insightly/base.rb +31 -7
- data/lib/insightly/comment.rb +2 -2
- data/lib/insightly/link.rb +1 -1
- data/lib/insightly/link_helper.rb +38 -11
- data/lib/insightly/opportunity.rb +0 -5
- data/lib/insightly/organisation.rb +1 -1
- data/lib/insightly/task.rb +0 -7
- data/lib/insightly/task_link.rb +2 -0
- data/lib/insightly/task_link_helper.rb +83 -10
- data/lib/insightly/version.rb +1 -1
- data/spec/spec_helper.rb +54 -0
- data/spec/unit/comment_spec.rb +47 -12
- data/spec/unit/configuration_spec.rb +4 -3
- data/spec/unit/contact_info_spec.rb +1 -1
- data/spec/unit/contact_spec.rb +61 -48
- data/spec/unit/custom_field_spec.rb +2 -1
- data/spec/unit/link_spec.rb +1 -1
- data/spec/unit/opportunity_category_spec.rb +1 -0
- data/spec/unit/opportunity_spec.rb +23 -2
- data/spec/unit/opportunity_state_reason_spec.rb +2 -1
- data/spec/unit/organisation_spec.rb +32 -3
- data/spec/unit/relationship_spec.rb +1 -0
- data/spec/unit/tag_spec.rb +5 -5
- data/spec/unit/task_category_spec.rb +2 -1
- data/spec/unit/task_link_spec.rb +1 -0
- data/spec/unit/task_spec.rb +668 -197
- data/spec/unit/team_member_spec.rb +1 -0
- data/spec/unit/user_spec.rb +3 -2
- metadata +141 -149
data/README.md
CHANGED
@@ -6,6 +6,11 @@ This is a rest client library to handle talking to http://Insight.ly
|
|
6
6
|
The official API for Insigh.ly was released on August 12, 2012. This library is in the very early stages of implementing access to everything expose in
|
7
7
|
that API. The focus is primarily on opportunities and tasks.
|
8
8
|
|
9
|
+
Freedom isn't Free - Neither is the API
|
10
|
+
===========
|
11
|
+
|
12
|
+
You have to be a paying customer of Insight.ly to use the API. If you are on a free plan, then it will give you 401 errors when you try to do anything with the API
|
13
|
+
|
9
14
|
Getting Started
|
10
15
|
=========
|
11
16
|
|
data/lib/insightly/base.rb
CHANGED
@@ -1,17 +1,20 @@
|
|
1
|
+
#METODO need to be able to delete records
|
2
|
+
#METODO create a script that can talk to the remote insightly install and confirm that everything still workd
|
3
|
+
#METODO re-write all the tests so that they store local data to work against
|
1
4
|
#METODO contacts allow you to set special dates to remember - can we access that via api?
|
2
|
-
#METODO It should have a method for converting date/time to the Insightly format
|
3
5
|
#METODO custom fields expect text,drop down, or date - add better handling (text should cast to_s)
|
4
6
|
#METODO contact infos should auto filter out duplicate entries
|
5
7
|
#METODO all the helpers should auto filter out duplicates (links,contact info,address etc)
|
6
8
|
#METODO only allow build to set fields that are part of the API fields
|
7
9
|
#METODO Fix all tests so they don't require the existence of certain object ids
|
8
|
-
|
10
|
+
#METODO add support for $top $skip and Brief=true for the things that suppor them
|
9
11
|
#METODO make a distinction between fields that you can set and save and ones you can only read - like DATE_UPDATED_UTC
|
12
|
+
|
10
13
|
module Insightly
|
11
14
|
class Base
|
12
15
|
|
13
16
|
class << self
|
14
|
-
attr_accessor :api_fields
|
17
|
+
attr_accessor :api_fields, :url_base, :remote_id_field
|
15
18
|
end
|
16
19
|
self.api_fields = []
|
17
20
|
|
@@ -46,6 +49,9 @@ module Insightly
|
|
46
49
|
end
|
47
50
|
end
|
48
51
|
|
52
|
+
def self.date_to_insightly(date = Date.today)
|
53
|
+
date.strftime("%Y-%m-%d %H:%M:%S")
|
54
|
+
end
|
49
55
|
def initialize(id = nil)
|
50
56
|
@data = {}
|
51
57
|
load(id) if id
|
@@ -55,8 +61,22 @@ module Insightly
|
|
55
61
|
def url_base
|
56
62
|
self.class.url_base
|
57
63
|
end
|
64
|
+
|
65
|
+
def remote_id_field
|
66
|
+
return self.class.remote_id_field if self.class.remote_id_field
|
67
|
+
self.class.to_s.downcase.gsub("insightly::", "") + "_id"
|
68
|
+
end
|
69
|
+
|
58
70
|
def remote_id
|
59
|
-
|
71
|
+
self.send(remote_id_field.to_sym)
|
72
|
+
end
|
73
|
+
|
74
|
+
def remote_id=(value)
|
75
|
+
self.send("#{remote_id_field}=", value)
|
76
|
+
end
|
77
|
+
|
78
|
+
def remote_id?
|
79
|
+
self.remote_id.nil? || self.remote_id.to_s.empty? ? false : true
|
60
80
|
end
|
61
81
|
|
62
82
|
def load(id)
|
@@ -67,9 +87,11 @@ module Insightly
|
|
67
87
|
def reload
|
68
88
|
load(remote_id)
|
69
89
|
end
|
90
|
+
|
70
91
|
def to_json
|
71
|
-
|
72
|
-
|
92
|
+
@data.to_json
|
93
|
+
end
|
94
|
+
|
73
95
|
def build(data)
|
74
96
|
@data = data
|
75
97
|
self
|
@@ -123,7 +145,9 @@ module Insightly
|
|
123
145
|
end
|
124
146
|
list
|
125
147
|
end
|
126
|
-
|
148
|
+
#def self.to_insightly_date(date)
|
149
|
+
# date.strftime("%Y-%m-%d 00:00:00")
|
150
|
+
#end
|
127
151
|
|
128
152
|
end
|
129
153
|
end
|
data/lib/insightly/comment.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
#METODO Add support for FileAttachment xml
|
2
|
+
#METODO the load via xml and load via json do not return the same format data
|
2
3
|
module Insightly
|
3
4
|
class Comment < ReadWrite
|
4
|
-
|
5
|
+
self.url_base = "Comments"
|
5
6
|
|
6
7
|
api_field "COMMENT_ID",
|
7
8
|
"BODY",
|
@@ -41,7 +42,6 @@ module Insightly
|
|
41
42
|
|
42
43
|
def load(id)
|
43
44
|
load_from_xml(get_collection("#{url_base}/#{id}", :xml_raw))
|
44
|
-
|
45
45
|
end
|
46
46
|
|
47
47
|
def save
|
data/lib/insightly/link.rb
CHANGED
@@ -1,16 +1,43 @@
|
|
1
|
+
#METODO be able to ask the object for a list of project_ids and projects
|
1
2
|
module Insightly
|
2
3
|
module LinkHelper
|
3
4
|
def links
|
4
5
|
@data["LINKS"] ||= []
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
6
|
+
@data["LINKS"].collect { |a| Insightly::Link.build(a) }
|
7
|
+
end
|
8
|
+
|
9
|
+
def links=(list)
|
10
|
+
@data["LINKS"] = list ? list.collect { |a| fix_for_link(a).remote_data } : []
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_link(link)
|
14
|
+
@data["LINKS"] ||= []
|
15
|
+
@data["LINKS"] << fix_for_link(link).remote_data
|
16
|
+
true
|
17
|
+
end
|
18
|
+
def contact_ids
|
19
|
+
self.links.collect { |link| link.contact_id}.compact
|
20
|
+
end
|
21
|
+
def opportunity_ids
|
22
|
+
self.links.collect { |link| link.opportunity_id}.compact
|
23
|
+
end
|
24
|
+
def organisation_ids
|
25
|
+
self.links.collect { |link| link.organisation_id}.compact
|
26
|
+
end
|
27
|
+
def contacts
|
28
|
+
self.contact_ids.collect { |id| Insightly::Contact.new(id)}
|
29
|
+
end
|
30
|
+
def opportunities
|
31
|
+
self.opportunity_ids.collect { |id| Insightly::Opportunity.new(id)}
|
32
|
+
end
|
33
|
+
def organisations
|
34
|
+
self.organisation_ids.collect { |id| Insightly::Organisation.new(id)}
|
35
|
+
end
|
36
|
+
#def project_ids
|
37
|
+
# self.links.collect { |link| link.project_id}.compact
|
38
|
+
#end
|
39
|
+
#def projects
|
40
|
+
# self.project_ids.collect { |id| Insightly::Project.new(id)}
|
41
|
+
#end
|
15
42
|
end
|
16
|
-
end
|
43
|
+
end
|
data/lib/insightly/task.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
#METODO make it so you can just say task.add_contact(contact/contact_id) (for opportunity and organisation as well)
|
2
|
-
#METODO warn them about how you have to save a task before you can link it up
|
3
1
|
module Insightly
|
4
2
|
class Task < ReadWrite
|
5
3
|
include Insightly::TaskLinkHelper
|
@@ -61,12 +59,7 @@ module Insightly
|
|
61
59
|
end
|
62
60
|
|
63
61
|
|
64
|
-
def remote_id
|
65
|
-
task_id
|
66
|
-
end
|
67
|
-
|
68
62
|
def fix_for_link(link)
|
69
|
-
#This needs to auto set the org id on the item
|
70
63
|
link.task_id = self.remote_id
|
71
64
|
link
|
72
65
|
end
|
data/lib/insightly/task_link.rb
CHANGED
@@ -1,16 +1,89 @@
|
|
1
|
+
#METODO add support for project
|
1
2
|
module Insightly
|
2
3
|
module TaskLinkHelper
|
3
4
|
def task_links
|
4
5
|
@data["TASKLINKS"] ||= []
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
6
|
+
@data["TASKLINKS"].collect { |a| Insightly::TaskLink.build(a) }
|
7
|
+
end
|
8
|
+
|
9
|
+
def task_links=(list)
|
10
|
+
@data["TASKLINKS"] = list ? list.collect { |a| fix_for_link(a).remote_data } : []
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_task_link(link)
|
14
|
+
raise(ScriptError, "You must save the #{self.class} before adding a link.") if !remote_id
|
15
|
+
@data["TASKLINKS"] ||= []
|
16
|
+
@data["TASKLINKS"] << fix_for_link(link).remote_data
|
17
|
+
true
|
18
|
+
end
|
19
|
+
def contact_ids
|
20
|
+
list_ids_by_type("contact")
|
21
|
+
end
|
22
|
+
|
23
|
+
def contacts
|
24
|
+
list_objs_by_type("contact", Insightly::Contact)
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_contact_id(contact_id)
|
28
|
+
add_by_id("contact", contact_id)
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_contact(contact)
|
32
|
+
add_by_obj("contact", contact)
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
def opportunity_ids
|
38
|
+
list_ids_by_type("opportunity")
|
39
|
+
end
|
40
|
+
|
41
|
+
def opportunities
|
42
|
+
list_objs_by_type("opportunity", Insightly::Opportunity)
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_opportunity_id(opportunity_id)
|
46
|
+
add_by_id("opportunity", opportunity_id)
|
47
|
+
end
|
48
|
+
|
49
|
+
def add_opportunity(opportunity)
|
50
|
+
add_by_obj("opportunity", opportunity)
|
51
|
+
end
|
52
|
+
def organisation_ids
|
53
|
+
list_ids_by_type("organisation")
|
54
|
+
end
|
55
|
+
|
56
|
+
def organisations
|
57
|
+
list_objs_by_type("organisation", Insightly::Organisation)
|
58
|
+
end
|
59
|
+
|
60
|
+
def add_organisation_id(organisation_id)
|
61
|
+
add_by_id("organisation", organisation_id)
|
62
|
+
end
|
63
|
+
|
64
|
+
def add_organisation(organisation)
|
65
|
+
add_by_obj("organisation", organisation)
|
66
|
+
end
|
67
|
+
|
68
|
+
def list_ids_by_type(type)
|
69
|
+
self.task_links.collect { |task_link| task_link.send("#{type}_id".to_sym) }.compact
|
70
|
+
end
|
71
|
+
|
72
|
+
def list_objs_by_type(type,klass)
|
73
|
+
self.send("#{type}_ids".to_sym).collect { |id| klass.new(id) }
|
74
|
+
end
|
75
|
+
|
76
|
+
def add_by_id(type, id)
|
77
|
+
return false if !id
|
78
|
+
self.save if !remote_id?
|
79
|
+
add_task_link(Insightly::TaskLink.send("add_#{type}".to_sym,id))
|
80
|
+
self.save
|
81
|
+
end
|
82
|
+
|
83
|
+
def add_by_obj(type, obj)
|
84
|
+
obj.save if !obj.remote_id?
|
85
|
+
self.send("add_#{type}_id".to_sym, obj.remote_id)
|
86
|
+
end
|
87
|
+
protected :list_ids_by_type, :list_objs_by_type, :add_by_id, :add_by_obj
|
15
88
|
end
|
16
89
|
end
|
data/lib/insightly/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -7,12 +7,30 @@
|
|
7
7
|
require "rubygems"
|
8
8
|
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __FILE__)
|
9
9
|
|
10
|
+
|
11
|
+
|
10
12
|
require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
|
11
13
|
Bundler.require(:default, :testing) if defined?(Bundler)
|
12
14
|
|
15
|
+
|
16
|
+
require 'vcr'
|
17
|
+
|
18
|
+
VCR.configure do |c|
|
19
|
+
c.cassette_library_dir = 'cassettes'
|
20
|
+
c.hook_into :webmock
|
21
|
+
c.default_cassette_options = {:record => :new_episodes} # :new_episodes, :none, :all
|
22
|
+
c.ignore_localhost = true
|
23
|
+
# c.allow_http_connections_when_no_cassette = true
|
24
|
+
c.filter_sensitive_data('<API_KEY>') { INSIGHTLY_API_KEY }
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
|
13
29
|
require "insightly"
|
14
30
|
require File.expand_path(File.dirname(__FILE__) + "/../api_key")
|
15
31
|
RSpec.configure do |config|
|
32
|
+
config.extend VCR::RSpec::Macros
|
33
|
+
|
16
34
|
config.treat_symbols_as_metadata_keys_with_true_values = true
|
17
35
|
config.run_all_when_everything_filtered = true
|
18
36
|
config.filter_run :focus
|
@@ -23,3 +41,39 @@ RSpec.configure do |config|
|
|
23
41
|
# --seed 1234
|
24
42
|
config.order = 'random'
|
25
43
|
end
|
44
|
+
|
45
|
+
def simple_insightly_user
|
46
|
+
|
47
|
+
VCR.use_cassette('all insightly users', :allow_playback_repeats => true) do
|
48
|
+
return Insightly::User.all.first
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
def simple_insightly_task(title = nil)
|
54
|
+
VCR.use_cassette('simple task', :allow_playback_repeats => true) do
|
55
|
+
task = Insightly::Task.new.build({"STATUS" => "Completed",
|
56
|
+
"RESPONSIBLE_USER_ID" => simple_insightly_user.user_id,
|
57
|
+
"OWNER_USER_ID" => simple_insightly_user.user_id,
|
58
|
+
"TITLE" => title ? title : "000 Test Task #{Date.today}"
|
59
|
+
})
|
60
|
+
task.save
|
61
|
+
return task
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
def simple_insightly_organisation(title = nil)
|
66
|
+
VCR.use_cassette('simple contact') do
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
def simple_insightly_opportunity(title = nil)
|
71
|
+
VCR.use_cassette('simple contact') do
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
def simple_insightly_contact(first_name = nil, last_name = nil)
|
76
|
+
VCR.use_cassette('simple contact') do
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
data/spec/unit/comment_spec.rb
CHANGED
@@ -39,9 +39,25 @@ describe Insightly::Comment do
|
|
39
39
|
@comment.remote_id.should == @comment.comment_id
|
40
40
|
end
|
41
41
|
it "should allow you to load based on an id" do
|
42
|
-
|
43
|
-
|
44
|
-
|
42
|
+
VCR.use_cassette('create and load comment') do
|
43
|
+
@user = Insightly::User.all.first
|
44
|
+
|
45
|
+
@task = Insightly::Task.new
|
46
|
+
@task.title = "000 Test Task"
|
47
|
+
@task.status = "Completed"
|
48
|
+
@task.owner_user_id = @user.user_id
|
49
|
+
@task.responsible_user_id = @user.user_id
|
50
|
+
@task.save
|
51
|
+
@task.comment_on("Sample Comment")
|
52
|
+
@saved_comment = @task.comments.first
|
53
|
+
|
54
|
+
|
55
|
+
@comment = Insightly::Comment.new(@saved_comment.comment_id)
|
56
|
+
@comment.comment_id.should == @saved_comment.comment_id
|
57
|
+
@comment.body.should == @saved_comment.body
|
58
|
+
|
59
|
+
|
60
|
+
end
|
45
61
|
end
|
46
62
|
it "should allow you to build an object from a hash" do
|
47
63
|
comment = Insightly::Comment.new.build({"BODY" => "Other"})
|
@@ -77,15 +93,34 @@ describe Insightly::Comment do
|
|
77
93
|
end
|
78
94
|
|
79
95
|
it "should allow you to modify a comment" do
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
96
|
+
VCR.use_cassette('first insightly user') do
|
97
|
+
@user = Insightly::User.all.first
|
98
|
+
end
|
99
|
+
VCR.use_cassette('create and modify comment') do
|
100
|
+
|
101
|
+
|
102
|
+
@task = Insightly::Task.new
|
103
|
+
@task.title = "000 Test Task"
|
104
|
+
@task.status = "Completed"
|
105
|
+
@task.owner_user_id = @user.user_id
|
106
|
+
@task.responsible_user_id = @user.user_id
|
107
|
+
@task.save
|
108
|
+
@task.comment_on("Sample Comment")
|
109
|
+
@saved_comment = @task.comments.first
|
110
|
+
|
111
|
+
@comment = Insightly::Comment.new(@saved_comment.comment_id)
|
112
|
+
@comment.body.should == "Sample Comment"
|
113
|
+
|
114
|
+
value = "Test Comment Edit Now"
|
115
|
+
@comment.body = value
|
116
|
+
@comment.save
|
117
|
+
@comment.body.should == value
|
118
|
+
@comment.reload
|
119
|
+
@comment.body.should == value
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
|
89
124
|
end
|
90
125
|
|
91
126
|
|