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.
Files changed (43) hide show
  1. data/README.rdoc +15 -10
  2. data/Rakefile +4 -1
  3. data/VERSION +1 -1
  4. data/lib/sugarcrm.rb +107 -119
  5. data/lib/sugarcrm/api/get_available_modules.rb +17 -0
  6. data/lib/sugarcrm/api/get_document_revision.rb +14 -0
  7. data/lib/sugarcrm/{get_entries.rb → api/get_entries.rb} +2 -2
  8. data/lib/sugarcrm/api/get_entries_count.rb +20 -0
  9. data/lib/sugarcrm/{get_entry.rb → api/get_entry.rb} +5 -8
  10. data/lib/sugarcrm/{get_entry_list.rb → api/get_entry_list.rb} +2 -2
  11. data/lib/sugarcrm/{get_module_fields.rb → api/get_module_fields.rb} +6 -3
  12. data/lib/sugarcrm/api/get_note_attachment.rb +15 -0
  13. data/lib/sugarcrm/{get_relationships.rb → api/get_relationship.rb} +9 -4
  14. data/lib/sugarcrm/api/get_report_entries.rb +19 -0
  15. data/lib/sugarcrm/api/get_server_info.rb +7 -0
  16. data/lib/sugarcrm/api/get_user_id.rb +13 -0
  17. data/lib/sugarcrm/api/get_user_team_id.rb +14 -0
  18. data/lib/sugarcrm/api/login.rb +18 -0
  19. data/lib/sugarcrm/api/logout.rb +15 -0
  20. data/lib/sugarcrm/api/seamless_login.rb +13 -0
  21. data/lib/sugarcrm/api/search_by_module.rb +24 -0
  22. data/lib/sugarcrm/api/set_campaign_merge.rb +15 -0
  23. data/lib/sugarcrm/api/set_document_revision.rb +15 -0
  24. data/lib/sugarcrm/api/set_entries.rb +15 -0
  25. data/lib/sugarcrm/api/set_entry.rb +15 -0
  26. data/lib/sugarcrm/api/set_note_attachment.rb +3 -0
  27. data/lib/sugarcrm/api/set_relationship.rb +18 -0
  28. data/lib/sugarcrm/api/set_relationships.rb +22 -0
  29. data/lib/sugarcrm/connection.rb +112 -0
  30. data/lib/sugarcrm/exceptions.rb +16 -0
  31. data/lib/sugarcrm/module.rb +11 -0
  32. data/lib/sugarcrm/request.rb +28 -0
  33. data/lib/sugarcrm/response.rb +29 -0
  34. data/test/helper.rb +5 -0
  35. data/test/test_connection.rb +60 -0
  36. data/test/test_response.rb +36 -0
  37. data/test/test_sugarcrm.rb +31 -45
  38. metadata +56 -17
  39. data/lib/net/http_digest_auth.rb +0 -44
  40. data/lib/stdlib/array.rb +0 -14
  41. data/lib/stdlib/hash.rb +0 -17
  42. data/lib/stdlib/object.rb +0 -5
  43. 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 Base
2
- # A standard REST call to get a list of relationships
3
- def get_relationships(module_name, id, related_to, options={})
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(:get_relationships, json)
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,7 @@
1
+ module SugarCRM; class Connection
2
+ # Returns server information such as version, flavor, and gmt_time.
3
+ def get_server_info
4
+ login! unless logged_in?
5
+ connection.get(:get_server_info, "")
6
+ end
7
+ 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,3 @@
1
+ module SugarCRM; class Connection
2
+ # to be implemented
3
+ 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,11 @@
1
+ module SugarCRM
2
+ class Base
3
+
4
+ # Runs a find against the remote service
5
+ def self.find(id)
6
+ response = connection.get_entry(self.module_name, id,{:fields => self.module_fields.keys})
7
+ response.object
8
+ end
9
+
10
+ end
11
+ 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