sugarcrm 0.5.3 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +15 -10
- data/Rakefile +4 -1
- data/VERSION +1 -1
- data/lib/sugarcrm.rb +107 -119
- data/lib/sugarcrm/api/get_available_modules.rb +17 -0
- data/lib/sugarcrm/api/get_document_revision.rb +14 -0
- data/lib/sugarcrm/{get_entries.rb → api/get_entries.rb} +2 -2
- data/lib/sugarcrm/api/get_entries_count.rb +20 -0
- data/lib/sugarcrm/{get_entry.rb → api/get_entry.rb} +5 -8
- data/lib/sugarcrm/{get_entry_list.rb → api/get_entry_list.rb} +2 -2
- data/lib/sugarcrm/{get_module_fields.rb → api/get_module_fields.rb} +6 -3
- data/lib/sugarcrm/api/get_note_attachment.rb +15 -0
- data/lib/sugarcrm/{get_relationships.rb → api/get_relationship.rb} +9 -4
- data/lib/sugarcrm/api/get_report_entries.rb +19 -0
- data/lib/sugarcrm/api/get_server_info.rb +7 -0
- data/lib/sugarcrm/api/get_user_id.rb +13 -0
- data/lib/sugarcrm/api/get_user_team_id.rb +14 -0
- data/lib/sugarcrm/api/login.rb +18 -0
- data/lib/sugarcrm/api/logout.rb +15 -0
- data/lib/sugarcrm/api/seamless_login.rb +13 -0
- data/lib/sugarcrm/api/search_by_module.rb +24 -0
- data/lib/sugarcrm/api/set_campaign_merge.rb +15 -0
- data/lib/sugarcrm/api/set_document_revision.rb +15 -0
- data/lib/sugarcrm/api/set_entries.rb +15 -0
- data/lib/sugarcrm/api/set_entry.rb +15 -0
- data/lib/sugarcrm/api/set_note_attachment.rb +3 -0
- data/lib/sugarcrm/api/set_relationship.rb +18 -0
- data/lib/sugarcrm/api/set_relationships.rb +22 -0
- data/lib/sugarcrm/connection.rb +112 -0
- data/lib/sugarcrm/exceptions.rb +16 -0
- data/lib/sugarcrm/module.rb +11 -0
- data/lib/sugarcrm/request.rb +28 -0
- data/lib/sugarcrm/response.rb +29 -0
- data/test/helper.rb +5 -0
- data/test/test_connection.rb +60 -0
- data/test/test_response.rb +36 -0
- data/test/test_sugarcrm.rb +31 -45
- metadata +56 -17
- data/lib/net/http_digest_auth.rb +0 -44
- data/lib/stdlib/array.rb +0 -14
- data/lib/stdlib/hash.rb +0 -17
- data/lib/stdlib/object.rb +0 -5
- data/test/test_json_to_obj.rb +0 -48
@@ -0,0 +1,15 @@
|
|
1
|
+
module SugarCRM; class Connection
|
2
|
+
# Retrieves an attachment from a note.
|
3
|
+
def get_note_attachment(id)
|
4
|
+
login! unless logged_in?
|
5
|
+
|
6
|
+
json = <<-EOF
|
7
|
+
{
|
8
|
+
\"session\": \"#{@session}\"\,
|
9
|
+
\"id\": #{id}\
|
10
|
+
}
|
11
|
+
EOF
|
12
|
+
json.gsub!(/^\s{6}/,'')
|
13
|
+
get(:get_note_attachment, json)
|
14
|
+
end
|
15
|
+
end; end
|
@@ -1,6 +1,8 @@
|
|
1
|
-
module SugarCRM; class
|
2
|
-
#
|
3
|
-
|
1
|
+
module SugarCRM; class Connection
|
2
|
+
# Retrieves a collection of beans that are related
|
3
|
+
# to the specified bean and, optionally, returns
|
4
|
+
# relationship data
|
5
|
+
def get_relationship(module_name, id, related_to, options={})
|
4
6
|
login! unless logged_in?
|
5
7
|
json = <<-EOF
|
6
8
|
{
|
@@ -15,6 +17,9 @@ def get_relationships(module_name, id, related_to, options={})
|
|
15
17
|
}
|
16
18
|
EOF
|
17
19
|
json.gsub!(/^\s{6}/,'')
|
18
|
-
get(:
|
20
|
+
get(:get_relationship, json)
|
19
21
|
end
|
22
|
+
|
23
|
+
alias :get_relationships :get_relationship
|
24
|
+
|
20
25
|
end; end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module SugarCRM; class Connection
|
2
|
+
# Retrieves a list of report entries based on specified report IDs.
|
3
|
+
def get_report_entries(ids, options={})
|
4
|
+
login! unless logged_in?
|
5
|
+
{
|
6
|
+
:select_fields => '',
|
7
|
+
}.merge! options
|
8
|
+
|
9
|
+
json = <<-EOF
|
10
|
+
{
|
11
|
+
\"session\": \"#{@session}\"\,
|
12
|
+
\"ids\": #{ids.to_json}\,
|
13
|
+
\"select_fields\": \"#{select_fields}\"
|
14
|
+
}
|
15
|
+
EOF
|
16
|
+
json.gsub!(/^\s{6}/,'')
|
17
|
+
get(:get_report_entries, json)
|
18
|
+
end
|
19
|
+
end; end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module SugarCRM; class Connection
|
2
|
+
# Returns the ID of the user who is logged into the current session.
|
3
|
+
def get_user_id
|
4
|
+
login! unless logged_in?
|
5
|
+
json = <<-EOF
|
6
|
+
{
|
7
|
+
\"session\": \"#{@session}\"
|
8
|
+
}
|
9
|
+
EOF
|
10
|
+
json.gsub!(/^\s{8}/,'')
|
11
|
+
response = get(:get_user_id, json)
|
12
|
+
end
|
13
|
+
end; end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module SugarCRM; class Connection
|
2
|
+
# Retrieves the ID of the default team of the user
|
3
|
+
# who is logged into the current session.
|
4
|
+
def get_user_team_id
|
5
|
+
login! unless logged_in?
|
6
|
+
json = <<-EOF
|
7
|
+
{
|
8
|
+
\"session\": \"#{@session}\"
|
9
|
+
}
|
10
|
+
EOF
|
11
|
+
json.gsub!(/^\s{8}/,'')
|
12
|
+
response = get(:get_user_team_id, json)
|
13
|
+
end
|
14
|
+
end; end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module SugarCRM; class Connection
|
2
|
+
# Logs the user into the Sugar application.
|
3
|
+
def login
|
4
|
+
connect! unless connected?
|
5
|
+
json = <<-EOF
|
6
|
+
{
|
7
|
+
\"user_auth\": {
|
8
|
+
\"user_name\": \"#{@user}\"\,
|
9
|
+
\"password\": \"#{OpenSSL::Digest::MD5.new(@pass)}\"\,
|
10
|
+
\"version\": \"2\"\,
|
11
|
+
},
|
12
|
+
\"application\": \"\"
|
13
|
+
}
|
14
|
+
EOF
|
15
|
+
json.gsub!(/^\s{8}/,'')
|
16
|
+
response = get(:login, json)
|
17
|
+
end
|
18
|
+
end; end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module SugarCRM; class Connection
|
2
|
+
# Logs out of the Sugar user session.
|
3
|
+
def logout
|
4
|
+
login! unless logged_in?
|
5
|
+
json = <<-EOF
|
6
|
+
{
|
7
|
+
\"user_auth\": {
|
8
|
+
\"session\": \"#{@session}\"
|
9
|
+
}
|
10
|
+
}
|
11
|
+
EOF
|
12
|
+
json.gsub!(/^\s{8}/,'')
|
13
|
+
response = get(:logout, json)
|
14
|
+
end
|
15
|
+
end; end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module SugarCRM; class Connection
|
2
|
+
# Performs a seamless login during synchronization.
|
3
|
+
def seamless_login
|
4
|
+
login! unless logged_in?
|
5
|
+
json = <<-EOF
|
6
|
+
{
|
7
|
+
\"session\": \"#{@session}\"
|
8
|
+
}
|
9
|
+
EOF
|
10
|
+
json.gsub!(/^\s{8}/,'')
|
11
|
+
response = get(:seamless_login, json)
|
12
|
+
end
|
13
|
+
end; end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module SugarCRM; class Connection
|
2
|
+
# Returns the ID, module name and fields for specified modules.
|
3
|
+
# Supported modules are Accounts, Bugs, Calls, Cases, Contacts,
|
4
|
+
# Leads, Opportunities, Projects, Project Tasks, and Quotes.
|
5
|
+
def search_by_module(search_string, modules, options={})
|
6
|
+
login! unless logged_in?
|
7
|
+
|
8
|
+
{ :offset => nil,
|
9
|
+
:max_results => nil,
|
10
|
+
}.merge! options
|
11
|
+
|
12
|
+
json = <<-EOF
|
13
|
+
{
|
14
|
+
\"session\": \"#{@session}\"\,
|
15
|
+
\"search_string\": \"#{search_string}\"\,
|
16
|
+
\"modules\": \"#{modules}\"\,
|
17
|
+
\"offset\": #{options[:offset]}\,
|
18
|
+
\"max_results\": #{options[:max_results]}
|
19
|
+
}
|
20
|
+
EOF
|
21
|
+
json.gsub!(/^\s{6}/,'')
|
22
|
+
get(:search_by_module, json)
|
23
|
+
end
|
24
|
+
end; end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module SugarCRM; class Connection
|
2
|
+
# Performs a mail merge for the specified campaign.
|
3
|
+
def set_campaign_merge(targets, campaign_id)
|
4
|
+
login! unless logged_in?
|
5
|
+
json = <<-EOF
|
6
|
+
{
|
7
|
+
\"session\": \"#{@session}\"\,
|
8
|
+
\"targets\": #{targets.to_json}\,
|
9
|
+
\"campaign-id\": \"#{campaign_id}\"
|
10
|
+
}
|
11
|
+
EOF
|
12
|
+
json.gsub!(/^\s{6}/,'')
|
13
|
+
get(:set_campaign_merge, json)
|
14
|
+
end
|
15
|
+
end; end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module SugarCRM; class Connection
|
2
|
+
# Sets a new revision for a document.
|
3
|
+
def set_document_revision(id, revision)
|
4
|
+
login! unless logged_in?
|
5
|
+
json = <<-EOF
|
6
|
+
{
|
7
|
+
\"session\": \"#{@session}\"\,
|
8
|
+
\"document_revision\": \"#{revision}\"\,
|
9
|
+
\"id\": #{id}
|
10
|
+
}
|
11
|
+
EOF
|
12
|
+
json.gsub!(/^\s{6}/,'')
|
13
|
+
get(:set_document_revision, json)
|
14
|
+
end
|
15
|
+
end; end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module SugarCRM; class Connection
|
2
|
+
# Creates or updates a list of SugarBeans.
|
3
|
+
def set_entries(module_name, name_value_lists)
|
4
|
+
login! unless logged_in?
|
5
|
+
json = <<-EOF
|
6
|
+
{
|
7
|
+
\"session\": \"#{@session}\"\,
|
8
|
+
\"module_name\": \"#{module_name}\"\,
|
9
|
+
\"name_value_list\": #{name_value_lists.to_json}
|
10
|
+
}
|
11
|
+
EOF
|
12
|
+
json.gsub!(/^\s{6}/,'')
|
13
|
+
get(:set_entries, json)
|
14
|
+
end
|
15
|
+
end; end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module SugarCRM; class Connection
|
2
|
+
# Creates or updates a single SugarBean.
|
3
|
+
def set_entry(module_name, name_value_list)
|
4
|
+
login! unless logged_in?
|
5
|
+
json = <<-EOF
|
6
|
+
{
|
7
|
+
\"session\": \"#{@session}\"\,
|
8
|
+
\"module_name\": \"#{module_name}\"\,
|
9
|
+
\"name_value_list\": #{name_value_list.to_json}
|
10
|
+
}
|
11
|
+
EOF
|
12
|
+
json.gsub!(/^\s{6}/,'')
|
13
|
+
get(:set_entry, json)
|
14
|
+
end
|
15
|
+
end; end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module SugarCRM; class Connection
|
2
|
+
# Sets a single relationship between two SugarBeans.
|
3
|
+
def set_relationship(module_name, module_id, link_field_name, related_ids)
|
4
|
+
login! unless logged_in?
|
5
|
+
raise ArgumentError, "related_ids must be an Array" unless related_ids.class == Array
|
6
|
+
json = <<-EOF
|
7
|
+
{
|
8
|
+
\"session\": \"#{@session}\"\,
|
9
|
+
\"module_name\": \"#{module_name}\"\,
|
10
|
+
\"module_id\": #{module_id}\,
|
11
|
+
\"link_field_name\": #{link_field_name}\,
|
12
|
+
\"related_ids\": #{link_field_name.to_json}
|
13
|
+
}
|
14
|
+
EOF
|
15
|
+
json.gsub!(/^\s{6}/,'')
|
16
|
+
get(:set_relationship, json)
|
17
|
+
end
|
18
|
+
end; end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module SugarCRM; class Connection
|
2
|
+
# Sets multiple relationships between two SugarBeans.
|
3
|
+
def set_relationships(module_names, module_ids, link_field_names, related_ids)
|
4
|
+
login! unless logged_in?
|
5
|
+
|
6
|
+
[module_names, module_ids, link_field_names, related_ids].each do |arg|
|
7
|
+
raise ArgumentError, "argument must be an Array" unless arg.class == Array
|
8
|
+
end
|
9
|
+
|
10
|
+
json = <<-EOF
|
11
|
+
{
|
12
|
+
\"session\": \"#{@session}\"\,
|
13
|
+
\"module_names\": \"#{module_names.to_json}\"\,
|
14
|
+
\"module_ids\": #{module_ids.to_json}\,
|
15
|
+
\"link_field_names\": #{link_field_names.to_json}\,
|
16
|
+
\"related_ids\": #{link_field_name.to_json}
|
17
|
+
}
|
18
|
+
EOF
|
19
|
+
json.gsub!(/^\s{6}/,'')
|
20
|
+
get(:set_relationships, json)
|
21
|
+
end
|
22
|
+
end; end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module SugarCRM
|
2
|
+
class Connection
|
3
|
+
|
4
|
+
URL = "/service/v2/rest.php"
|
5
|
+
|
6
|
+
attr :url, true
|
7
|
+
attr :user, false
|
8
|
+
attr :pass, false
|
9
|
+
attr :ssl, false
|
10
|
+
attr :session, true
|
11
|
+
attr :connection, true
|
12
|
+
attr :modules, false
|
13
|
+
attr :debug, true
|
14
|
+
|
15
|
+
# This is the singleton connection class.
|
16
|
+
def initialize(url, user, pass, debug=false)
|
17
|
+
@url = URI.parse(url)
|
18
|
+
@user = user
|
19
|
+
@pass = pass
|
20
|
+
@debug = debug
|
21
|
+
# Handles http/https in url string
|
22
|
+
@ssl = false
|
23
|
+
@ssl = true if @url.scheme == "https"
|
24
|
+
# Appends the rest.php path onto the end of the URL if it's not included
|
25
|
+
if @url.path !~ /rest.php$/
|
26
|
+
@url.path += URL
|
27
|
+
end
|
28
|
+
login!
|
29
|
+
raise SugarCRM::LoginError, "Invalid Login" unless logged_in?
|
30
|
+
@modules = get_modules
|
31
|
+
@modules.each do |m|
|
32
|
+
begin
|
33
|
+
register_module(m)
|
34
|
+
rescue SugarCRM::InvalidRequest
|
35
|
+
next
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Check to see if we are logged in
|
41
|
+
def logged_in?
|
42
|
+
@session ? true : false
|
43
|
+
end
|
44
|
+
|
45
|
+
# Login
|
46
|
+
def login!
|
47
|
+
response = login
|
48
|
+
@session = response["id"]
|
49
|
+
end
|
50
|
+
|
51
|
+
# Check to see if we are connected
|
52
|
+
def connected?
|
53
|
+
return false unless @connection
|
54
|
+
return false unless @connection.started?
|
55
|
+
true
|
56
|
+
end
|
57
|
+
|
58
|
+
# Connect
|
59
|
+
def connect!
|
60
|
+
@connection = Net::HTTP.new(@url.host, @url.port)
|
61
|
+
if @ssl
|
62
|
+
@connection.use_ssl = true
|
63
|
+
@connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
64
|
+
end
|
65
|
+
@connection.start
|
66
|
+
end
|
67
|
+
|
68
|
+
# Send a GET request to the Sugar Instance
|
69
|
+
def get(method, json)
|
70
|
+
request = SugarCRM::Request.new(@url, method, json, @debug)
|
71
|
+
response = connection.get(request.to_s)
|
72
|
+
|
73
|
+
case response
|
74
|
+
when Net::HTTPOK
|
75
|
+
raise SugarCRM::EmptyResponse unless response.body
|
76
|
+
response_json = JSON.parse response.body
|
77
|
+
return false if response_json["result_count"] == 0
|
78
|
+
if @debug
|
79
|
+
puts "#{method}: JSON Response:"
|
80
|
+
pp response_json
|
81
|
+
puts "\n"
|
82
|
+
end
|
83
|
+
return response_json
|
84
|
+
when Net::HTTPNotFound
|
85
|
+
raise SugarCRM::InvalidSugarCRMUrl, "#{@url} is invalid"
|
86
|
+
when Net::HTTPInternalServerError
|
87
|
+
raise SugarCRM::InvalidRequest, "#{request} is invalid"
|
88
|
+
else
|
89
|
+
if @debug
|
90
|
+
puts "#{method}: Raw Response:"
|
91
|
+
puts response.body
|
92
|
+
puts "\n"
|
93
|
+
end
|
94
|
+
raise SugarCRM::UnhandledResponse, "Can't handle response #{response}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Dynamically register objects based on Module name
|
99
|
+
# I.e. a SugarCRM Module named Users will generate
|
100
|
+
# a SugarCRM::User class.
|
101
|
+
def register_module(module_name, mod=SugarCRM)
|
102
|
+
klass_name = module_name.singularize
|
103
|
+
return if mod.const_defined? klass_name
|
104
|
+
klass = Class.new(SugarCRM::Base) do
|
105
|
+
self.module_name = module_name
|
106
|
+
end
|
107
|
+
mod.const_set klass_name, klass
|
108
|
+
klass
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module SugarCRM
|
2
|
+
class LoginError < RuntimeError
|
3
|
+
end
|
4
|
+
|
5
|
+
class EmptyResponse < RuntimeError
|
6
|
+
end
|
7
|
+
|
8
|
+
class UnhandledResponse < RuntimeError
|
9
|
+
end
|
10
|
+
|
11
|
+
class InvalidSugarCRMUrl < RuntimeError
|
12
|
+
end
|
13
|
+
|
14
|
+
class InvalidRequest < RuntimeError
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module SugarCRM
|
2
|
+
|
3
|
+
class Request
|
4
|
+
|
5
|
+
attr :request, true
|
6
|
+
attr :url, true
|
7
|
+
attr :method, true
|
8
|
+
attr :json, true
|
9
|
+
|
10
|
+
def initialize(url, method, json, debug=false)
|
11
|
+
@request = url.path.dup
|
12
|
+
@request << '?method=' << method.to_s
|
13
|
+
@request << '&input_type=JSON'
|
14
|
+
@request << '&response_type=JSON'
|
15
|
+
@request << '&rest_data=' << json
|
16
|
+
|
17
|
+
if debug
|
18
|
+
puts "#{method}: Request:\n#{@request}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
URI.escape(@request)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|