sugarcrm 0.5.3 → 0.6.0
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.
- 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
|