sugarcrm_emp 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. data/.document +5 -0
  2. data/.gitignore +29 -0
  3. data/Gemfile +14 -0
  4. data/LICENSE +20 -0
  5. data/README.rdoc +275 -0
  6. data/Rakefile +44 -0
  7. data/VERSION +1 -0
  8. data/WATCHLIST.rdoc +7 -0
  9. data/bin/sugarcrm +26 -0
  10. data/lib/rails/generators/sugarcrm/config/config_generator.rb +22 -0
  11. data/lib/rails/generators/sugarcrm/config/templates/initializer.rb +4 -0
  12. data/lib/rails/generators/sugarcrm/config/templates/sugarcrm.yml +19 -0
  13. data/lib/sugarcrm/associations/association.rb +170 -0
  14. data/lib/sugarcrm/associations/association_cache.rb +36 -0
  15. data/lib/sugarcrm/associations/association_collection.rb +141 -0
  16. data/lib/sugarcrm/associations/association_methods.rb +91 -0
  17. data/lib/sugarcrm/associations/associations.rb +61 -0
  18. data/lib/sugarcrm/associations.rb +5 -0
  19. data/lib/sugarcrm/attributes/attribute_methods.rb +203 -0
  20. data/lib/sugarcrm/attributes/attribute_serializers.rb +55 -0
  21. data/lib/sugarcrm/attributes/attribute_typecast.rb +44 -0
  22. data/lib/sugarcrm/attributes/attribute_validations.rb +62 -0
  23. data/lib/sugarcrm/attributes.rb +4 -0
  24. data/lib/sugarcrm/base.rb +355 -0
  25. data/lib/sugarcrm/config/sugarcrm.yaml +10 -0
  26. data/lib/sugarcrm/connection/api/get_available_modules.rb +22 -0
  27. data/lib/sugarcrm/connection/api/get_document_revision.rb +14 -0
  28. data/lib/sugarcrm/connection/api/get_entries.rb +23 -0
  29. data/lib/sugarcrm/connection/api/get_entries_count.rb +20 -0
  30. data/lib/sugarcrm/connection/api/get_entry.rb +23 -0
  31. data/lib/sugarcrm/connection/api/get_entry_list.rb +31 -0
  32. data/lib/sugarcrm/connection/api/get_module_fields.rb +15 -0
  33. data/lib/sugarcrm/connection/api/get_note_attachment.rb +14 -0
  34. data/lib/sugarcrm/connection/api/get_relationships.rb +30 -0
  35. data/lib/sugarcrm/connection/api/get_report_entries.rb +17 -0
  36. data/lib/sugarcrm/connection/api/get_server_info.rb +7 -0
  37. data/lib/sugarcrm/connection/api/get_user_id.rb +13 -0
  38. data/lib/sugarcrm/connection/api/get_user_team_id.rb +14 -0
  39. data/lib/sugarcrm/connection/api/login.rb +18 -0
  40. data/lib/sugarcrm/connection/api/logout.rb +15 -0
  41. data/lib/sugarcrm/connection/api/seamless_login.rb +13 -0
  42. data/lib/sugarcrm/connection/api/search_by_module.rb +25 -0
  43. data/lib/sugarcrm/connection/api/set_campaign_merge.rb +15 -0
  44. data/lib/sugarcrm/connection/api/set_document_revision.rb +35 -0
  45. data/lib/sugarcrm/connection/api/set_entries.rb +15 -0
  46. data/lib/sugarcrm/connection/api/set_entry.rb +15 -0
  47. data/lib/sugarcrm/connection/api/set_note_attachment.rb +25 -0
  48. data/lib/sugarcrm/connection/api/set_relationship.rb +27 -0
  49. data/lib/sugarcrm/connection/api/set_relationships.rb +22 -0
  50. data/lib/sugarcrm/connection/connection.rb +201 -0
  51. data/lib/sugarcrm/connection/helper.rb +50 -0
  52. data/lib/sugarcrm/connection/request.rb +61 -0
  53. data/lib/sugarcrm/connection/response.rb +91 -0
  54. data/lib/sugarcrm/connection.rb +5 -0
  55. data/lib/sugarcrm/connection_pool.rb +163 -0
  56. data/lib/sugarcrm/exceptions.rb +23 -0
  57. data/lib/sugarcrm/extensions/README.txt +23 -0
  58. data/lib/sugarcrm/finders/dynamic_finder_match.rb +41 -0
  59. data/lib/sugarcrm/finders/finder_methods.rb +243 -0
  60. data/lib/sugarcrm/finders.rb +2 -0
  61. data/lib/sugarcrm/module.rb +174 -0
  62. data/lib/sugarcrm/module_methods.rb +91 -0
  63. data/lib/sugarcrm/session.rb +218 -0
  64. data/lib/sugarcrm.rb +22 -0
  65. data/sugarcrm.gemspec +178 -0
  66. data/test/config_test.yaml +15 -0
  67. data/test/connection/test_get_available_modules.rb +9 -0
  68. data/test/connection/test_get_entries.rb +15 -0
  69. data/test/connection/test_get_entry.rb +22 -0
  70. data/test/connection/test_get_entry_list.rb +23 -0
  71. data/test/connection/test_get_module_fields.rb +11 -0
  72. data/test/connection/test_get_relationships.rb +12 -0
  73. data/test/connection/test_get_server_info.rb +9 -0
  74. data/test/connection/test_get_user_id.rb +9 -0
  75. data/test/connection/test_get_user_team_id.rb +9 -0
  76. data/test/connection/test_login.rb +9 -0
  77. data/test/connection/test_logout.rb +9 -0
  78. data/test/connection/test_set_document_revision.rb +28 -0
  79. data/test/connection/test_set_entry.rb +15 -0
  80. data/test/connection/test_set_note_attachment.rb +16 -0
  81. data/test/connection/test_set_relationship.rb +18 -0
  82. data/test/extensions_test/patch.rb +9 -0
  83. data/test/helper.rb +17 -0
  84. data/test/test_association_collection.rb +11 -0
  85. data/test/test_associations.rb +156 -0
  86. data/test/test_connection.rb +13 -0
  87. data/test/test_connection_pool.rb +40 -0
  88. data/test/test_finders.rb +201 -0
  89. data/test/test_module.rb +51 -0
  90. data/test/test_request.rb +35 -0
  91. data/test/test_response.rb +26 -0
  92. data/test/test_session.rb +136 -0
  93. data/test/test_sugarcrm.rb +213 -0
  94. metadata +266 -0
@@ -0,0 +1,25 @@
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, opts={})
6
+ login! unless logged_in?
7
+
8
+ options = {
9
+ :offset => nil,
10
+ :limit => nil,
11
+ }.merge! opts
12
+
13
+ json = <<-EOF
14
+ {
15
+ "session": "#{@sugar_session_id}",
16
+ "search_string": "#{search_string}",
17
+ "modules": "#{modules}",
18
+ "offset": #{options[:offset]},
19
+ "max_results": #{options[:limit]}
20
+ }
21
+ EOF
22
+ json.gsub!(/^\s{6}/,'')
23
+ send!(:search_by_module, json)
24
+ end
25
+ 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": "#{@sugar_session_id}",
8
+ "targets": #{targets.to_json},
9
+ "campaign-id": "#{campaign_id}"
10
+ }
11
+ EOF
12
+ json.gsub!(/^\s{6}/,'')
13
+ send!(:set_campaign_merge, json)
14
+ end
15
+ end; end
@@ -0,0 +1,35 @@
1
+ module SugarCRM; class Connection
2
+ # Sets a new revision for a document.
3
+ def set_document_revision(document_id, revision_number, opts={})
4
+ options = {
5
+ :file => '',
6
+ :file_name => '',
7
+ :document_name => nil
8
+ }.merge! opts
9
+
10
+ # Raise an exception of we try to pass :file, but not :file_name
11
+ if (!options[:file].empty? && options[:file_name].empty?)
12
+ raise ArgumentException, ":file_name must be specified if :file is specified"
13
+ end
14
+
15
+ # If no document_name is given, use the file_name
16
+ options[:document_name] ||= options[:file_name]
17
+
18
+ login! unless logged_in?
19
+
20
+ json = <<-EOF
21
+ {
22
+ "session": "#{@sugar_session_id}",
23
+ "document_revision": {
24
+ "id": "#{document_id}",
25
+ "document_name": "#{options[:document_name]}",
26
+ "revision": "#{revision_number}",
27
+ "filename": "#{options[:file_name]}",
28
+ "file": "#{b64_encode(options[:file])}"
29
+ }
30
+ }
31
+ EOF
32
+ json.gsub!(/^\s{6}/,'')
33
+ send!(:set_document_revision, json)
34
+ end
35
+ 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": "#{@sugar_session_id}",
8
+ "module_name": "#{module_name}",
9
+ "name_value_list": #{name_value_lists.to_json}
10
+ }
11
+ EOF
12
+ json.gsub!(/^\s{6}/,'')
13
+ send!(: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": "#{@sugar_session_id}",
8
+ "module_name": "#{module_name}",
9
+ "name_value_list": #{name_value_list.to_json}
10
+ }
11
+ EOF
12
+ json.gsub!(/^\s{6}/,'')
13
+ send!(:set_entry, json)
14
+ end
15
+ end; end
@@ -0,0 +1,25 @@
1
+ module SugarCRM; class Connection
2
+ # Creates or updates an attachment on a note
3
+ def set_note_attachment(id, filename, file, opts={})
4
+ options = {
5
+ :module_id => '',
6
+ :module_name => ''
7
+ }.merge! opts
8
+
9
+ login! unless logged_in?
10
+ json = <<-EOF
11
+ {
12
+ "session": "#{@sugar_session_id}",
13
+ "note": {
14
+ "id": "#{id}",
15
+ "filename": "#{filename}",
16
+ "file": "#{b64_encode(file)}",
17
+ "related_module_id": "#{options[:module_id]}",
18
+ "related_module_name": "#{options[:module_name]}"
19
+ }
20
+ }
21
+ EOF
22
+ json.gsub!(/^\s{6}/,'')
23
+ send!(:set_note_attachment, json)
24
+ end
25
+ end; end
@@ -0,0 +1,27 @@
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, opts={})
4
+ login! unless logged_in?
5
+ options = {
6
+ :name_value_list => [],
7
+ :delete => 0,
8
+ }.merge! opts
9
+ raise ArgumentError, "related_ids must be an Array" unless related_ids.class == Array
10
+ json = <<-EOF
11
+ {
12
+ "session": "#{@sugar_session_id}",
13
+ "module_name": "#{module_name}",
14
+ "module_id": "#{module_id}",
15
+ "link_field_name": "#{link_field_name}",
16
+ "related_ids": #{related_ids.to_json},
17
+ "name_value_list": #{options[:name_value_list].to_json},
18
+ "delete": #{options[:delete]}
19
+ }
20
+ EOF
21
+ json.gsub!(/^\s{6}/,'')
22
+ # TODO: Add a handler for the response. By default it returns a hash like:
23
+ # {failed => 0, deleted => 0, created => 1}. We should add this to the
24
+ # Response.handle method and return true/false depending on the outcome.
25
+ send!(:set_relationship, json)
26
+ end
27
+ 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": "#{@sugar_session_id}",
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": #{related_ids.to_json}
17
+ }
18
+ EOF
19
+ json.gsub!(/^\s{6}/,'')
20
+ send!(:set_relationships, json)
21
+ end
22
+ end; end
@@ -0,0 +1,201 @@
1
+ module SugarCRM; class Connection
2
+
3
+ URL = "/service/v2/rest.php"
4
+ # Set this to filter out debug output on a certain method (i.e. get_modules, or get_fields)
5
+ DONT_SHOW_DEBUG_FOR = []
6
+ RESPONSE_IS_NOT_JSON = [:get_user_id, :get_user_team_id]
7
+
8
+ attr :url, true
9
+ attr :user, false
10
+ attr :pass, false
11
+ attr :session, true
12
+ attr :sugar_session_id, true
13
+ attr :connection, true
14
+ attr :options, true
15
+ attr :request, true
16
+ attr :response, true
17
+ attr :errors, true
18
+
19
+ # This is the singleton connection class.
20
+ def initialize(url, user, pass, options={})
21
+ @options = {
22
+ :debug => false,
23
+ :register_modules => true,
24
+ :load_environment => true
25
+ }.merge(options)
26
+ @errors = []
27
+ @url = URI.parse(url)
28
+ @user = user
29
+ @pass = pass
30
+ @request = ""
31
+ @response = ""
32
+ resolve_url
33
+ login!
34
+ self
35
+ end
36
+
37
+ # Check to see if we are logged in
38
+ def logged_in?
39
+ connect! unless connected?
40
+ @sugar_session_id ? true : false
41
+ end
42
+
43
+ # Login
44
+ def login!
45
+ @sugar_session_id = login["id"]
46
+ raise SugarCRM::LoginError, "Invalid Login" unless logged_in?
47
+ end
48
+
49
+ def logout
50
+ logout
51
+ @sugar_session_id = nil
52
+ end
53
+
54
+ # Check to see if we are connected
55
+ def connected?
56
+ return false unless @connection
57
+ true
58
+ end
59
+
60
+ # Connect
61
+ def connect!
62
+ @connection = HTTPClient.new
63
+ end
64
+ alias :reconnect! :connect!
65
+
66
+ # Send a request to the Sugar Instance
67
+ def send!(method, json, max_retry=3)
68
+ if max_retry == 0
69
+ raise SugarCRM::RetryLimitExceeded, "SugarCRM::Connection Errors: \n#{@errors.reverse.join "\n\s\s"}"
70
+ end
71
+ @request = SugarCRM::Request.new(@url, method, json, @options[:debug])
72
+ # Send Ze Reques
73
+ begin
74
+ if @request.length > 3900
75
+ @response = @connection.post(@url, @request)
76
+ else
77
+ @response = @connection.get(@url, @request)
78
+ end
79
+ return handle_response
80
+ # Timeouts are usually a server side issue
81
+ rescue Timeout::Error => error
82
+ @errors << error
83
+ send!(method, json, max_retry.pred)
84
+ # Lower level errors requiring a reconnect
85
+ rescue Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPIPE, EOFError => error
86
+ @errors << error
87
+ reconnect!
88
+ send!(method, json, max_retry.pred)
89
+ # Handle invalid sessions
90
+ rescue SugarCRM::InvalidSession => error
91
+ @errors << error
92
+ old_session = @sugar_session_id.dup
93
+ login!
94
+ # Update the session id in the request that we want to retry.
95
+ json.gsub!(old_session, @sugar_session_id)
96
+ send!(method, json, max_retry.pred)
97
+ end
98
+ end
99
+ alias :retry! :send!
100
+
101
+ def debug=(debug)
102
+ options[:debug] = debug
103
+ end
104
+
105
+ def debug?
106
+ options[:debug]
107
+ end
108
+
109
+ private
110
+
111
+ def handle_response
112
+ case @response.status
113
+ when 200
114
+ return process_response
115
+ when 404
116
+ raise SugarCRM::InvalidSugarCRMUrl, "#{@url} is invalid"
117
+ when 500
118
+ raise SugarCRM::InvalidRequest, "#{@request} is invalid"
119
+ else
120
+ if @options[:debug]
121
+ puts "#{@request.method}: Raw Response:"
122
+ puts @response.body
123
+ puts "\n"
124
+ end
125
+ raise SugarCRM::UnhandledResponse, "Can't handle response #{@response}"
126
+ end
127
+ end
128
+
129
+ def process_response
130
+ empty_body?
131
+ if response_contains_json?
132
+ return parse_response
133
+ else
134
+ return @response.body
135
+ end
136
+ end
137
+
138
+ def resolve_url
139
+ # Appends the rest.php path onto the end of the URL if it's not included
140
+ if @url.path !~ /rest.php$/
141
+ @url.path += URL
142
+ end
143
+ end
144
+
145
+ # Complain if our body is empty.
146
+ def empty_body?
147
+ raise SugarCRM::EmptyResponse unless @response.body
148
+ end
149
+
150
+ # Some methods are dumb and don't return a JSON Response
151
+ def response_contains_json?
152
+ if RESPONSE_IS_NOT_JSON.include? @request.method
153
+ return false
154
+ end
155
+ true
156
+ end
157
+
158
+ def parse_response
159
+ begin
160
+ # Push it through the old meat grinder.
161
+ json = JSON.parse(@response.body)
162
+ rescue StandardError => e
163
+ # Complain if we can't parse
164
+ raise UnhandledResponse, @response.body
165
+ end
166
+ # Do ze debugs!
167
+ nice_debugging_for json
168
+ # Check for an invalid session
169
+ invalid_session? json
170
+ # Check for an empty result set
171
+ if zero_results? json
172
+ return nil
173
+ end
174
+ json
175
+ end
176
+
177
+ # Check if we got an invalid session error back
178
+ # something like:
179
+ # {"name"=>"Invalid Session ID",
180
+ # "number"=>11,
181
+ # "description"=>"The session ID is invalid"}
182
+ def invalid_session?(json)
183
+ return false unless json["name"]
184
+ return false if @request.method == :logout
185
+ raise SugarCRM::InvalidSession if json["name"] == "Invalid Session ID"
186
+ end
187
+
188
+ def zero_results?(json)
189
+ json["result_count"] == 0
190
+ end
191
+
192
+ # Filter debugging on REALLY BIG responses
193
+ def nice_debugging_for(json)
194
+ if @options[:debug] && !(DONT_SHOW_DEBUG_FOR.include? @request.method)
195
+ puts "#{@request.method}: JSON Response:"
196
+ pp json
197
+ puts "\n"
198
+ end
199
+ end
200
+
201
+ end; end
@@ -0,0 +1,50 @@
1
+ module SugarCRM; class Connection
2
+ # Attempts to return a list of fields for the target of the association.
3
+ # i.e. if we are associating Contact -> Account, using the "contacts" link
4
+ # field name - this will lookup the contacts association and try to determine
5
+ # the target object type (Contact). It will then pull the fields for that object
6
+ # and shove them in the related_fields portion of the get_relationship request.
7
+ def resolve_related_fields(module_name, link_field)
8
+ a = Association.new(class_for(module_name), link_field)
9
+ if a.target
10
+ fields = a.target.new.attributes.keys
11
+ else
12
+ fields = ["id"]
13
+ end
14
+ fields.to_json
15
+ end
16
+
17
+ def resolve_fields(module_name, fields)
18
+ # FIXME: This is to work around a bug in SugarCRM 6.0
19
+ # where no fields are returned if no fields are specified
20
+ if fields.length == 0
21
+ mod = Module.find(module_name.classify, @session)
22
+ if mod
23
+ fields = mod.fields.keys
24
+ else
25
+ fields = ["id"]
26
+ end
27
+ end
28
+ return fields.to_json
29
+ end
30
+
31
+ # Returns an instance of class for the provided module name
32
+ def class_for(module_name)
33
+ begin
34
+ class_const = @session.namespace_const.const_get(module_name.classify)
35
+ klass = class_const.new
36
+ rescue NameError
37
+ raise InvalidModule, "Module: #{module_name} is not registered"
38
+ end
39
+ end
40
+
41
+ # We need to strip newlines from Base64 encoding for JSON validation purposes.
42
+ def b64_encode(file)
43
+ Base64.encode64(file).gsub(/\n/, '')
44
+ end
45
+
46
+ def b64_decode(file)
47
+ Base64.decode64(file)
48
+ end
49
+
50
+ end; end
@@ -0,0 +1,61 @@
1
+ module SugarCRM; class Request
2
+ attr :request, true
3
+ attr :url, true
4
+ attr :method, true
5
+ attr :json, true
6
+ attr :http_method
7
+
8
+ def initialize(url, method, json, debug=false)
9
+ @url = url
10
+ @method = method
11
+ @json = escape(json)
12
+ @request = 'method=' << @method.to_s
13
+ @request << '&input_type=JSON'
14
+ @request << '&response_type=JSON'
15
+ @request << '&rest_data=' << @json
16
+ if debug
17
+ puts "#{method}: Request:"
18
+ puts json
19
+ puts "\n"
20
+ end
21
+ self
22
+ end
23
+
24
+ def escape(json)
25
+ # BUG: SugarCRM doesn't properly handle '&quot;' inside of JSON for some reason. Let's unescape any html elements.
26
+ j = convert_reserved_characters(json)
27
+ # Now we escape the resulting string.
28
+ j = CGI.escape(j)
29
+ j
30
+ end
31
+
32
+ # TODO: Fix this so that it JSON.parse will consume it.
33
+ def unescape
34
+ j = CGI.unescape(@json)
35
+ j.gsub!(/\n/, '')
36
+ end
37
+
38
+ def bytesize
39
+ self.to_s.bytesize
40
+ end
41
+
42
+ def length
43
+ self.to_s.length
44
+ end
45
+
46
+ def to_s
47
+ @request
48
+ end
49
+ alias :to_str :to_s
50
+
51
+ # A tiny helper for converting reserved characters for html encoding
52
+ def convert_reserved_characters(string)
53
+ string.gsub!(/&quot;/, '\"')
54
+ string.gsub!(/&apos;/, '\'')
55
+ string.gsub!(/&amp;/, '\&')
56
+ string.gsub!(/&lt;/, '\<')
57
+ string.gsub!(/&lt;/, '\>')
58
+ string
59
+ end
60
+
61
+ end; end
@@ -0,0 +1,91 @@
1
+ module SugarCRM; class Response
2
+ class << self
3
+ # This class handles the response from the server.
4
+ # It tries to convert the response into an object such as User
5
+ # or an object collection. If it fails, it just returns the response hash
6
+ def handle(json, session)
7
+ r = new(json, session)
8
+ begin
9
+ return r.to_obj
10
+ rescue UninitializedModule => e
11
+ raise e
12
+ rescue InvalidAttribute => e
13
+ raise e
14
+ rescue InvalidAttributeType => e
15
+ raise e
16
+ rescue => e
17
+ if session.connection.debug?
18
+ puts "Failed to process JSON:"
19
+ pp json
20
+ end
21
+ raise e
22
+ end
23
+ end
24
+ end
25
+
26
+ attr :response, false
27
+
28
+ def initialize(json, session, opts={})
29
+ @options = { :always_return_array => false }.merge! opts
30
+ @response = json
31
+ @response = json.with_indifferent_access if json.is_a? Hash
32
+ @session = session
33
+ end
34
+
35
+ # Tries to instantiate and return an object with the values
36
+ # populated from the response
37
+ def to_obj
38
+ # If this is not a "entry_list" response, just return
39
+ return @response unless @response && @response["entry_list"]
40
+
41
+ objects = []
42
+ @response["entry_list"].each do |object|
43
+ attributes = []
44
+ _module = resolve_module(object)
45
+ attributes = flatten_name_value_list(object)
46
+ namespace = @session.namespace_const
47
+ if namespace.const_get(_module)
48
+ if attributes.length == 0
49
+ raise AttributeParsingError, "response contains objects without attributes!"
50
+ end
51
+ objects << namespace.const_get(_module).new(attributes)
52
+ else
53
+ raise InvalidModule, "#{_module} does not exist, or is not accessible"
54
+ end
55
+ end
56
+ # If we only have one result, just return the object
57
+ if objects.length == 1 && !@options[:always_return_array]
58
+ return objects[0]
59
+ else
60
+ return objects
61
+ end
62
+ end
63
+
64
+ def to_json
65
+ @response.to_json
66
+ end
67
+
68
+ def resolve_module(list)
69
+ list["module_name"].classify
70
+ end
71
+
72
+ def flatten_name_value_list(list)
73
+ if list["name_value_list"]
74
+ return flatten(list["name_value_list"])
75
+ else
76
+ return false
77
+ end
78
+ end
79
+
80
+ # Takes a hash like { "first_name" => {"name" => "first_name", "value" => "John"}}
81
+ # And flattens it into {"first_name" => "John"}
82
+ def flatten(list)
83
+ raise ArgumentError, list[0]['value'] if list[0] && list[0]['name'] == 'warning'
84
+ raise ArgumentError, 'method parameter must respond to #each_pair' unless list.respond_to? :each_pair
85
+ flat_list = {}
86
+ list.each_pair do |k,v|
87
+ flat_list[k.to_sym] = v["value"]
88
+ end
89
+ flat_list
90
+ end
91
+ end; end
@@ -0,0 +1,5 @@
1
+ require 'sugarcrm/connection/helper'
2
+ require 'sugarcrm/connection/connection'
3
+ require 'sugarcrm/connection/request'
4
+ require 'sugarcrm/connection/response'
5
+ Dir["#{File.dirname(__FILE__)}/connection/api/*.rb"].each { |f| load(f) }