sugarcrm 0.5.3 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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