sugarcrm 0.9.9 → 0.9.10
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 +9 -14
- data/Rakefile +2 -10
- data/VERSION +1 -1
- data/lib/sugarcrm.rb +1 -0
- data/lib/sugarcrm/associations/association.rb +91 -29
- data/lib/sugarcrm/associations/association_methods.rb +1 -2
- data/lib/sugarcrm/associations/associations.rb +10 -16
- data/lib/sugarcrm/attributes/attribute_typecast.rb +7 -0
- data/lib/sugarcrm/connection/api/get_available_modules.rb +1 -1
- data/lib/sugarcrm/connection/api/get_document_revision.rb +2 -2
- data/lib/sugarcrm/connection/api/get_entries.rb +5 -5
- data/lib/sugarcrm/connection/api/get_entries_count.rb +4 -4
- data/lib/sugarcrm/connection/api/get_entry.rb +5 -5
- data/lib/sugarcrm/connection/api/get_entry_list.rb +9 -9
- data/lib/sugarcrm/connection/api/get_module_fields.rb +2 -2
- data/lib/sugarcrm/connection/api/get_note_attachment.rb +3 -3
- data/lib/sugarcrm/connection/api/get_relationships.rb +8 -8
- data/lib/sugarcrm/connection/api/get_report_entries.rb +3 -3
- data/lib/sugarcrm/connection/api/get_user_id.rb +1 -1
- data/lib/sugarcrm/connection/api/get_user_team_id.rb +1 -1
- data/lib/sugarcrm/connection/api/logout.rb +2 -2
- data/lib/sugarcrm/connection/api/seamless_login.rb +1 -1
- data/lib/sugarcrm/connection/api/search_by_module.rb +5 -5
- data/lib/sugarcrm/connection/api/set_campaign_merge.rb +3 -3
- data/lib/sugarcrm/connection/api/set_document_revision.rb +3 -3
- data/lib/sugarcrm/connection/api/set_entries.rb +3 -3
- data/lib/sugarcrm/connection/api/set_entry.rb +3 -3
- data/lib/sugarcrm/connection/api/set_note_attachment.rb +24 -2
- data/lib/sugarcrm/connection/api/set_relationship.rb +7 -7
- data/lib/sugarcrm/connection/api/set_relationships.rb +5 -5
- data/lib/sugarcrm/connection/connection.rb +3 -1
- data/lib/sugarcrm/environment.rb +16 -1
- data/test/connection/test_get_entry_list.rb +1 -1
- data/test/connection/test_set_note_attachment.rb +17 -0
- data/test/helper.rb +1 -1
- data/test/test_associations.rb +98 -0
- data/test/test_environment.rb +7 -0
- data/test/test_sugarcrm.rb +0 -52
- metadata +29 -36
- data/test/test_association.rb +0 -18
data/README.rdoc
CHANGED
|
@@ -6,13 +6,7 @@ REST Bindings for SugarCRM!
|
|
|
6
6
|
|
|
7
7
|
== SUMMARY:
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
== Description:
|
|
12
|
-
|
|
13
|
-
A less clunky way to interact with SugarCRM via REST.
|
|
14
|
-
|
|
15
|
-
Instead of SugarCRM.connection.get_entry("Users", "1") you could use SugarCRM::User.find(1). There is support for collections à la SugarCRM::User.find(1).email_addresses, or SugarCRM::Contact.first.meetings << new_meeting. ActiveRecord style finders are in place, with limited support for conditions and joins.
|
|
9
|
+
A less clunky way to interact with SugarCRM via REST.
|
|
16
10
|
|
|
17
11
|
== FEATURES/PROBLEMS:
|
|
18
12
|
|
|
@@ -145,12 +139,13 @@ Instead of SugarCRM.connection.get_entry("Users", "1") you could use SugarCRM::U
|
|
|
145
139
|
|
|
146
140
|
== USING A CONFIGURATION FILE
|
|
147
141
|
|
|
148
|
-
If you want to use a configuration file instead of always specifying the url, username, and password to connect to SugarCRM, you can
|
|
142
|
+
If you want to use a configuration file instead of always specifying the url, username, and password to connect to SugarCRM, you can add your credentials to one (or more) of
|
|
149
143
|
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
144
|
+
* `/etc/sugarcrm.yaml`
|
|
145
|
+
* `~/.sugarcrm.yaml` (i.e. your home directory on Linux and Mac OSX)
|
|
146
|
+
* a `sugarcrm.yaml` file at the root of you Windows home directory (execute `ENV['USERPROFILE']` in Ruby to see which directory should contain the file)
|
|
147
|
+
* `config/sugarcrm.yaml` (will need to be copied each time you upgrade or reinstall the gem)
|
|
148
|
+
* a YAML file and call `SugarCRM::Environment.load_config` followed by the absolute path to your configuration file
|
|
154
149
|
|
|
155
150
|
If there are several configuration files, they are loaded sequentially in the order above and will overwrite previous values (if present). This allows you to (e.g.) have a config file in `/etc/sugarcrm.yaml` with system-wide configuration information (such as the url where SugarCRM is located) and/or defaults. Each developer/user can then have his personal configuration file in `~/.sugarcrm.yaml` with his own username and password. A developer could also specify a different location for the SugarCRM instance (e.g. a local testing instance) in his configuration file, which will take precedence over the value in `/etc/sugarcrm.yaml`.
|
|
156
151
|
|
|
@@ -175,9 +170,9 @@ An example, accompanied by instructions, can be found in the `config/sugarcrm.ya
|
|
|
175
170
|
|
|
176
171
|
4. You now have full access to the gem's functionality, e.g. `puts SugarCRM::Account.first.name`
|
|
177
172
|
|
|
178
|
-
==
|
|
173
|
+
== EXTENDING THE GEM
|
|
179
174
|
|
|
180
|
-
If you want to
|
|
175
|
+
If you want to extend the gem's capabilities (e.g. to add methods specific to your environment), you can either
|
|
181
176
|
|
|
182
177
|
* drop your `*.rb` files in `lib/sugarcrm/extensions/` (see the README in that folder)
|
|
183
178
|
|
data/Rakefile
CHANGED
|
@@ -13,11 +13,10 @@ require 'jeweler'
|
|
|
13
13
|
Jeweler::Tasks.new do |gem|
|
|
14
14
|
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
|
15
15
|
gem.name = "sugarcrm"
|
|
16
|
-
gem.summary = %Q{
|
|
17
|
-
gem.description = %Q{A less clunky way to interact with SugarCRM via REST. Instead of SugarCRM.connection.get_entry("Users", "1") you could use SugarCRM::User.find(1). There is support for collections a la SugarCRM::User.find(1).email_addresses, or SugarCRM::Contact.first.meetings << new_meeting. ActiveRecord style finders are in place, with limited support for conditions and joins.}
|
|
16
|
+
gem.summary = %Q{A less clunky way to interact with SugarCRM via REST.}
|
|
18
17
|
gem.email = "carl.hicks@gmail.com"
|
|
19
18
|
gem.homepage = "http://github.com/chicks/sugarcrm"
|
|
20
|
-
gem.authors = ["Carl Hicks"]
|
|
19
|
+
gem.authors = ["Carl Hicks", "David Sulc"]
|
|
21
20
|
end
|
|
22
21
|
Jeweler::RubygemsDotOrgTasks.new
|
|
23
22
|
|
|
@@ -28,13 +27,6 @@ Rake::TestTask.new(:test) do |test|
|
|
|
28
27
|
test.verbose = true
|
|
29
28
|
end
|
|
30
29
|
|
|
31
|
-
#require 'rcov/rcovtask'
|
|
32
|
-
#Rcov::RcovTask.new do |test|
|
|
33
|
-
# test.libs << 'test'
|
|
34
|
-
# test.pattern = 'test/**/test_*.rb'
|
|
35
|
-
# test.verbose = true
|
|
36
|
-
#end
|
|
37
|
-
|
|
38
30
|
task :default => :test
|
|
39
31
|
|
|
40
32
|
require 'rake/rdoctask'
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.9.
|
|
1
|
+
0.9.10
|
data/lib/sugarcrm.rb
CHANGED
|
@@ -1,21 +1,30 @@
|
|
|
1
1
|
module SugarCRM
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
# Associations are middlemen between the object that holds the association, known as the @owner,
|
|
4
|
+
# and the actual associated object, known as the @target. Methods are added to the @owner that
|
|
5
|
+
# allow access to the association collection, and are held in @proxy_methods. The cardinality
|
|
6
|
+
# of the association is available in @cardinality, and the actual relationship details are held
|
|
7
|
+
# in @relationship.
|
|
3
8
|
class Association
|
|
4
9
|
attr :owner, true
|
|
5
10
|
attr :target, true
|
|
6
11
|
attr :link_field, true
|
|
12
|
+
attr :relationship, true
|
|
7
13
|
attr :attributes, true
|
|
8
|
-
attr :
|
|
14
|
+
attr :proxy_methods, true
|
|
15
|
+
attr :cardinality, true
|
|
9
16
|
|
|
10
|
-
#
|
|
17
|
+
# Creates a new instance of an Association
|
|
11
18
|
def initialize(owner,link_field,opts={})
|
|
12
19
|
@options = { :define_methods? => true }.merge! opts
|
|
13
20
|
@owner = owner
|
|
14
21
|
check_valid_owner
|
|
15
22
|
@link_field = link_field
|
|
16
23
|
@attributes = owner.link_fields[link_field]
|
|
24
|
+
@relationship = relationship_for(@attributes["relationship"])
|
|
17
25
|
@target = resolve_target
|
|
18
|
-
@
|
|
26
|
+
@proxy_methods = define_methods if @options[:define_methods?]
|
|
27
|
+
@cardinality = resolve_cardinality
|
|
19
28
|
self
|
|
20
29
|
end
|
|
21
30
|
|
|
@@ -28,6 +37,27 @@ module SugarCRM
|
|
|
28
37
|
false
|
|
29
38
|
end
|
|
30
39
|
|
|
40
|
+
def ==(comparison_object)
|
|
41
|
+
comparison_object.instance_of?(self.class) &&
|
|
42
|
+
@target.class == comparison_object.class &&
|
|
43
|
+
@link_field == comparison_object.link_field
|
|
44
|
+
end
|
|
45
|
+
alias :eql? :==
|
|
46
|
+
|
|
47
|
+
def hash
|
|
48
|
+
"#{@target.class}##{@link_field}".hash
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def inspect
|
|
52
|
+
self
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def to_s
|
|
56
|
+
"#<SugarCRM::Association @proxy_methods=[#{@proxy_methods.join(", ")}], " +
|
|
57
|
+
"@link_field=\"#{@link_field}\", @target=#{@target}, @owner=#{@owner.class}, " +
|
|
58
|
+
"@cardinality=#{@cardinality}>"
|
|
59
|
+
end
|
|
60
|
+
|
|
31
61
|
protected
|
|
32
62
|
|
|
33
63
|
def check_valid_owner
|
|
@@ -36,7 +66,6 @@ module SugarCRM
|
|
|
36
66
|
end
|
|
37
67
|
|
|
38
68
|
# Attempts to determine the class of the target in the association
|
|
39
|
-
# TODO: Write tests for this.
|
|
40
69
|
def resolve_target
|
|
41
70
|
# Use the link_field name first
|
|
42
71
|
klass = @link_field.singularize.camelize
|
|
@@ -46,47 +75,80 @@ module SugarCRM
|
|
|
46
75
|
module_name = SugarCRM::Module.find(@attributes["module"])
|
|
47
76
|
return "SugarCRM::#{module_name.klass}".constantize if SugarCRM.const_defined? module_name.klass
|
|
48
77
|
end
|
|
49
|
-
# Use the
|
|
78
|
+
# Use the "relationship" target
|
|
50
79
|
if @attributes["relationship"].length > 0
|
|
51
|
-
klass =
|
|
80
|
+
klass = @relationship[:target][:name].singularize.camelize
|
|
52
81
|
return "SugarCRM::#{klass}".constantize if SugarCRM.const_defined? klass
|
|
53
82
|
end
|
|
54
83
|
false
|
|
55
84
|
end
|
|
56
85
|
|
|
86
|
+
# Defines methods for accessing the association target on the owner class.
|
|
87
|
+
# If the link_field name includes the owner class name, it is stripped before
|
|
88
|
+
# creating the method. If this occurs, we also create an alias to the stripped
|
|
89
|
+
# method using the full link_field name.
|
|
90
|
+
def define_methods
|
|
91
|
+
methods = []
|
|
92
|
+
pretty_name = @relationship[:target][:name]
|
|
93
|
+
methods << define_method(@link_field)
|
|
94
|
+
methods << define_alias(pretty_name, @link_field) if pretty_name != @link_field
|
|
95
|
+
methods
|
|
96
|
+
end
|
|
97
|
+
|
|
57
98
|
# Generates the association proxy method for related module
|
|
58
99
|
def define_method(link_field)
|
|
100
|
+
raise ArgumentException, "argument cannot be nil" if link_field.nil?
|
|
101
|
+
if (@owner.respond_to? link_field.to_sym) && @owner.debug
|
|
102
|
+
warn "Warning: Overriding method: #{@owner.class}##{link_field}"
|
|
103
|
+
end
|
|
59
104
|
@owner.class.module_eval %Q?
|
|
60
105
|
def #{link_field}
|
|
61
106
|
query_association :#{link_field}
|
|
62
107
|
end
|
|
63
108
|
?
|
|
109
|
+
link_field
|
|
64
110
|
end
|
|
65
111
|
|
|
66
|
-
# Defines
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
112
|
+
# Defines a method alias. Checks to see if a method is already defined.
|
|
113
|
+
def define_alias(alias_name, method_name)
|
|
114
|
+
@owner.class.module_eval %Q?
|
|
115
|
+
alias :#{alias_name} :#{method_name}
|
|
116
|
+
?
|
|
117
|
+
alias_name
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# This method breaks the relationship into parts and returns them
|
|
121
|
+
def relationship_for(relationship)
|
|
122
|
+
# We need to run both regexes, because the plurality of the @owner module name is
|
|
123
|
+
# important
|
|
124
|
+
plural_regex = /((.*)_)?(#{Regexp.quote(@owner.class._module.name.downcase)})(_(.*))?/
|
|
125
|
+
singular_regex = /((.*)_)?(#{Regexp.quote(@owner.class._module.name.downcase.singularize)})(_(.*))?/
|
|
126
|
+
# Break the loop if we match
|
|
127
|
+
[plural_regex, singular_regex].each {|r| break if relationship.match(r)}
|
|
128
|
+
# Assign sane values to things if we didnt match
|
|
129
|
+
o = $3
|
|
130
|
+
o = @owner.class._module.name.downcase if o.nil? || o.empty?
|
|
131
|
+
t = [$2, $5].compact.join('_')
|
|
132
|
+
t = @link_field if t.nil? || t.empty?
|
|
133
|
+
# Look up the cardinality
|
|
134
|
+
o_c, t_c = cardinality_for(o,t)
|
|
135
|
+
{:owner => {:name => o, :cardinality => o_c},
|
|
136
|
+
:target => {:name => t, :cardinality => t_c}}
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Determines if the provided string is plural or singular
|
|
140
|
+
# Plurality == Cardinality
|
|
141
|
+
def cardinality_for(*args)
|
|
142
|
+
args.inject([]) {|results,arg|
|
|
143
|
+
result = :many
|
|
144
|
+
result = :one if arg.singularize == arg
|
|
145
|
+
results << result
|
|
146
|
+
}
|
|
81
147
|
end
|
|
82
148
|
|
|
83
|
-
#
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def humanized_link_name(link_field)
|
|
87
|
-
# the module name is used to function properly with modules containing '_' (e.g. a custom module abc_sale : custom modules need a prefix (abc here) so they will always have a '_' in their table name)
|
|
88
|
-
return link_field unless link_field.to_s =~ /((.*)_)?#{Regexp.quote(@owner.class._module.name.downcase)}(_(.*))?/
|
|
89
|
-
[$2, $4].compact.join('_')
|
|
149
|
+
# TODO: Add Tests for This
|
|
150
|
+
def resolve_cardinality
|
|
151
|
+
"#{@relationship[:owner][:cardinality]}_to_#{@relationship[:target][:cardinality]}".to_sym
|
|
90
152
|
end
|
|
91
153
|
|
|
92
154
|
end
|
|
@@ -38,7 +38,7 @@ module SugarCRM; module AssociationMethods
|
|
|
38
38
|
"Couldn't associate #{self.class._module.name}: #{self.id} -> #{t}: #{t.id}!"
|
|
39
39
|
end
|
|
40
40
|
# We need to update the association cache for any changes we make.
|
|
41
|
-
if opts[:delete]
|
|
41
|
+
if opts[:delete] == 1
|
|
42
42
|
update_association_cache_for(association.link_field, t, :delete)
|
|
43
43
|
t.update_association_cache_for(association.link_field, self, :delete)
|
|
44
44
|
else
|
|
@@ -51,7 +51,6 @@ module SugarCRM; module AssociationMethods
|
|
|
51
51
|
alias :relate! :associate!
|
|
52
52
|
|
|
53
53
|
# Removes a relationship between the current object and the target object
|
|
54
|
-
# TODO: Write a test for this.
|
|
55
54
|
def disassociate!(target)
|
|
56
55
|
associate!(target,{:delete => 1})
|
|
57
56
|
end
|
|
@@ -19,6 +19,13 @@ module SugarCRM
|
|
|
19
19
|
self
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
+
# Returns the proxy methods of all the associations in the collection
|
|
23
|
+
def proxy_methods
|
|
24
|
+
@associations.inject([]) { |pm,a|
|
|
25
|
+
pm = pm | a.proxy_methods
|
|
26
|
+
}
|
|
27
|
+
end
|
|
28
|
+
|
|
22
29
|
# Looks up an association by object, link_field, or method.
|
|
23
30
|
# Raises an exception if not found
|
|
24
31
|
def find!(target)
|
|
@@ -32,26 +39,13 @@ module SugarCRM
|
|
|
32
39
|
# Returns false if not found
|
|
33
40
|
def find(association)
|
|
34
41
|
begin
|
|
35
|
-
find!
|
|
42
|
+
find!(association)
|
|
36
43
|
rescue InvalidAssociation
|
|
37
44
|
false
|
|
38
45
|
end
|
|
39
46
|
end
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
self
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def to_s
|
|
46
|
-
methods = []
|
|
47
|
-
@associations.each do |a|
|
|
48
|
-
a.methods.each do |m|
|
|
49
|
-
methods << m
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
"[#{methods.join(', ')}]"
|
|
53
|
-
end
|
|
54
|
-
|
|
47
|
+
alias :include? :find
|
|
48
|
+
|
|
55
49
|
# delegate undefined methods to the @collection array
|
|
56
50
|
# E.g. contact.cases should behave like an array and allow `length`, `size`, `each`, etc.
|
|
57
51
|
def method_missing(method_name, *args, &block)
|
|
@@ -18,6 +18,13 @@ module SugarCRM; module AttributeTypeCast
|
|
|
18
18
|
# skip primary key columns
|
|
19
19
|
next if name == "id"
|
|
20
20
|
attr_type = attr_type_for(name)
|
|
21
|
+
|
|
22
|
+
# empty attributes should stay empty (e.g. an empty int field shouldn't be typecast as 0)
|
|
23
|
+
if [:datetime, :datetimecombo, :int].include? attr_type && (value.nil? || value == '')
|
|
24
|
+
@attributes[name] = nil
|
|
25
|
+
next
|
|
26
|
+
end
|
|
27
|
+
|
|
21
28
|
case attr_type
|
|
22
29
|
when :bool
|
|
23
30
|
@attributes[name] = (value == "1")
|
|
@@ -10,11 +10,11 @@ module SugarCRM; class Connection
|
|
|
10
10
|
|
|
11
11
|
json = <<-EOF
|
|
12
12
|
{
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
"session": "#{@session}",
|
|
14
|
+
"module_name": "#{module_name}",
|
|
15
|
+
"ids": #{ids.to_json},
|
|
16
|
+
"select_fields": #{resolve_fields(module_name, options[:fields])},
|
|
17
|
+
"link_name_to_fields_array": #{options[:link_fields].to_json}
|
|
18
18
|
}
|
|
19
19
|
EOF
|
|
20
20
|
json.gsub!(/^\s{6}/,'')
|
|
@@ -8,10 +8,10 @@ module SugarCRM; class Connection
|
|
|
8
8
|
|
|
9
9
|
json = <<-EOF
|
|
10
10
|
{
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
"session": "#{@session}",
|
|
12
|
+
"module_name": "#{module_name}",
|
|
13
|
+
"query": "#{query}",
|
|
14
|
+
"deleted": #{options[:deleted]}
|
|
15
15
|
}
|
|
16
16
|
EOF
|
|
17
17
|
json.gsub!(/^\s{6}/,'')
|
|
@@ -9,11 +9,11 @@ module SugarCRM; class Connection
|
|
|
9
9
|
|
|
10
10
|
json = <<-EOF
|
|
11
11
|
{
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
"session": "#{@session}",
|
|
13
|
+
"module_name": "#{module_name}",
|
|
14
|
+
"id": "#{id}",
|
|
15
|
+
"select_fields": #{resolve_fields(module_name, options[:fields])},
|
|
16
|
+
"link_name_to_fields_array": #{options[:link_fields]}
|
|
17
17
|
}
|
|
18
18
|
EOF
|
|
19
19
|
|
|
@@ -14,15 +14,15 @@ module SugarCRM; class Connection
|
|
|
14
14
|
|
|
15
15
|
json = <<-EOF
|
|
16
16
|
{
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
17
|
+
"session": "#{@session}",
|
|
18
|
+
"module_name": "#{module_name}",
|
|
19
|
+
"query": "#{query}",
|
|
20
|
+
"order_by": "#{options[:order_by]}",
|
|
21
|
+
"offset": "#{options[:offset]}",
|
|
22
|
+
"select_fields": #{resolve_fields(module_name, options[:fields])},
|
|
23
|
+
"link_name_to_fields_array": #{options[:link_fields].to_json},
|
|
24
|
+
"max_results": "#{options[:limit]}",
|
|
25
|
+
"deleted": #{options[:deleted]}
|
|
26
26
|
}
|
|
27
27
|
EOF
|
|
28
28
|
json.gsub!(/^\s{6}/,'')
|
|
@@ -4,11 +4,11 @@ module SugarCRM; class Connection
|
|
|
4
4
|
login! unless logged_in?
|
|
5
5
|
json = <<-EOF
|
|
6
6
|
{
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
"session": "#{@session}",
|
|
8
|
+
"id": "#{id}"
|
|
9
9
|
}
|
|
10
10
|
EOF
|
|
11
11
|
json.gsub!(/^\s{6}/,'')
|
|
12
|
-
send!(:get_note_attachment, json)
|
|
12
|
+
send!(:get_note_attachment, json)["note_attachment"]
|
|
13
13
|
end
|
|
14
14
|
end; end
|
|
@@ -13,14 +13,14 @@ module SugarCRM; class Connection
|
|
|
13
13
|
|
|
14
14
|
json = <<-EOF
|
|
15
15
|
{
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
"session": "#{@session}",
|
|
17
|
+
"module_name": "#{module_name}",
|
|
18
|
+
"module_id": "#{id}",
|
|
19
|
+
"link_field_name": "#{related_to.downcase}",
|
|
20
|
+
"related_module_query": "#{options[:query]}",
|
|
21
|
+
"related_fields": #{resolve_related_fields(module_name, related_to)},
|
|
22
|
+
"related_module_link_name_to_fields_array": #{options[:link_fields].to_json},
|
|
23
|
+
"deleted": #{options[:deleted]}
|
|
24
24
|
}
|
|
25
25
|
EOF
|
|
26
26
|
json.gsub!(/^\s{6}/,'')
|
|
@@ -6,9 +6,9 @@ module SugarCRM; class Connection
|
|
|
6
6
|
|
|
7
7
|
json = <<-EOF
|
|
8
8
|
{
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
"session": "#{@session}",
|
|
10
|
+
"ids": #{ids.to_json},
|
|
11
|
+
"select_fields": "#{options[:select_fields].to_json}"
|
|
12
12
|
}
|
|
13
13
|
EOF
|
|
14
14
|
json.gsub!(/^\s{6}/,'')
|
|
@@ -12,11 +12,11 @@ module SugarCRM; class Connection
|
|
|
12
12
|
|
|
13
13
|
json = <<-EOF
|
|
14
14
|
{
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
"session": "#{@session}",
|
|
16
|
+
"search_string": "#{search_string}",
|
|
17
|
+
"modules": "#{modules}",
|
|
18
|
+
"offset": #{options[:offset]},
|
|
19
|
+
"max_results": #{options[:limit]}
|
|
20
20
|
}
|
|
21
21
|
EOF
|
|
22
22
|
json.gsub!(/^\s{6}/,'')
|
|
@@ -4,9 +4,9 @@ module SugarCRM; class Connection
|
|
|
4
4
|
login! unless logged_in?
|
|
5
5
|
json = <<-EOF
|
|
6
6
|
{
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
"session": "#{@session}",
|
|
8
|
+
"targets": #{targets.to_json},
|
|
9
|
+
"campaign-id": "#{campaign_id}"
|
|
10
10
|
}
|
|
11
11
|
EOF
|
|
12
12
|
json.gsub!(/^\s{6}/,'')
|
|
@@ -4,9 +4,9 @@ module SugarCRM; class Connection
|
|
|
4
4
|
login! unless logged_in?
|
|
5
5
|
json = <<-EOF
|
|
6
6
|
{
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
"session": "#{@session}",
|
|
8
|
+
"document_revision": "#{revision}",
|
|
9
|
+
"id": #{id}
|
|
10
10
|
}
|
|
11
11
|
EOF
|
|
12
12
|
json.gsub!(/^\s{6}/,'')
|
|
@@ -4,9 +4,9 @@ module SugarCRM; class Connection
|
|
|
4
4
|
login! unless logged_in?
|
|
5
5
|
json = <<-EOF
|
|
6
6
|
{
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
"session": "#{@session}",
|
|
8
|
+
"module_name": "#{module_name}",
|
|
9
|
+
"name_value_list": #{name_value_lists.to_json}
|
|
10
10
|
}
|
|
11
11
|
EOF
|
|
12
12
|
json.gsub!(/^\s{6}/,'')
|
|
@@ -4,9 +4,9 @@ module SugarCRM; class Connection
|
|
|
4
4
|
login! unless logged_in?
|
|
5
5
|
json = <<-EOF
|
|
6
6
|
{
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
"session": "#{@session}",
|
|
8
|
+
"module_name": "#{module_name}",
|
|
9
|
+
"name_value_list": #{name_value_list.to_json}
|
|
10
10
|
}
|
|
11
11
|
EOF
|
|
12
12
|
json.gsub!(/^\s{6}/,'')
|
|
@@ -1,3 +1,25 @@
|
|
|
1
1
|
module SugarCRM; class Connection
|
|
2
|
-
#
|
|
3
|
-
|
|
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": "#{@session}",
|
|
13
|
+
"note": {
|
|
14
|
+
"id": "#{id}",
|
|
15
|
+
"filename": "#{filename}",
|
|
16
|
+
"file": "#{Base64.encode64(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
|
|
@@ -9,13 +9,13 @@ module SugarCRM; class Connection
|
|
|
9
9
|
raise ArgumentError, "related_ids must be an Array" unless related_ids.class == Array
|
|
10
10
|
json = <<-EOF
|
|
11
11
|
{
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
"session": "#{@session}",
|
|
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
19
|
}
|
|
20
20
|
EOF
|
|
21
21
|
json.gsub!(/^\s{6}/,'')
|
|
@@ -9,11 +9,11 @@ module SugarCRM; class Connection
|
|
|
9
9
|
|
|
10
10
|
json = <<-EOF
|
|
11
11
|
{
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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": #{related_ids.to_json}
|
|
17
17
|
}
|
|
18
18
|
EOF
|
|
19
19
|
json.gsub!(/^\s{6}/,'')
|
|
@@ -29,7 +29,9 @@ module SugarCRM; class Connection
|
|
|
29
29
|
resolve_url
|
|
30
30
|
login!
|
|
31
31
|
# make sure the environment singleton gets loaded
|
|
32
|
-
|
|
32
|
+
if @options[:load_environment] # prevent loops when Environment tries to log in automatically
|
|
33
|
+
SugarCRM::Environment.update_config({:base_url => url, :username => user, :password => pass})
|
|
34
|
+
end
|
|
33
35
|
self
|
|
34
36
|
end
|
|
35
37
|
|
data/lib/sugarcrm/environment.rb
CHANGED
|
@@ -9,7 +9,7 @@ module SugarCRM; class Environment
|
|
|
9
9
|
@config = {}
|
|
10
10
|
|
|
11
11
|
# see README for reasoning behind the priorization
|
|
12
|
-
|
|
12
|
+
config_file_paths.each{|path|
|
|
13
13
|
load_config path if File.exists? path
|
|
14
14
|
}
|
|
15
15
|
extensions_folder = File.join(File.dirname(__FILE__), 'extensions')
|
|
@@ -28,6 +28,14 @@ module SugarCRM; class Environment
|
|
|
28
28
|
@config[k.to_sym] = v
|
|
29
29
|
}
|
|
30
30
|
end
|
|
31
|
+
@config
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def update_config(params)
|
|
35
|
+
params.each{|k,v|
|
|
36
|
+
@config[k.to_sym] = v
|
|
37
|
+
}
|
|
38
|
+
@config
|
|
31
39
|
end
|
|
32
40
|
|
|
33
41
|
# load all the monkey patch extension files in the provided folder
|
|
@@ -42,6 +50,13 @@ module SugarCRM; class Environment
|
|
|
42
50
|
end
|
|
43
51
|
|
|
44
52
|
private
|
|
53
|
+
def config_file_paths
|
|
54
|
+
# see README for reasoning behind the priorization
|
|
55
|
+
paths = ['/etc/sugarcrm.yaml', File.expand_path('~/.sugarcrm.yaml'), File.join(File.dirname(__FILE__), 'config', 'sugarcrm.yaml')]
|
|
56
|
+
paths.insert(1, File.join(ENV['USERPROFILE'], 'sugarcrm.yaml')) if ENV['USERPROFILE']
|
|
57
|
+
paths
|
|
58
|
+
end
|
|
59
|
+
|
|
45
60
|
def validate_path(path)
|
|
46
61
|
raise "Invalid path: #{path}" unless File.exists? path
|
|
47
62
|
end
|
|
@@ -18,7 +18,7 @@ class TestGetEntryList < Test::Unit::TestCase
|
|
|
18
18
|
"Users",
|
|
19
19
|
"users.deleted = 0"
|
|
20
20
|
)
|
|
21
|
-
assert_equal "
|
|
21
|
+
assert_equal "admin", users.first.user_name
|
|
22
22
|
end
|
|
23
23
|
should "return an object when #get_entry_list" do
|
|
24
24
|
assert_instance_of Array, @response
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'helper'
|
|
2
|
+
|
|
3
|
+
class TestSetNoteAttachment < Test::Unit::TestCase
|
|
4
|
+
context "A SugarCRM.connection" do
|
|
5
|
+
should "Add an attachment to a Note" do
|
|
6
|
+
SugarCRM.connect(URL, USER, PASS, {:debug => false})
|
|
7
|
+
n = SugarCRM::Note.new
|
|
8
|
+
n.name = "A Test Note"
|
|
9
|
+
assert n.save
|
|
10
|
+
file = File.read("test/config_test.yaml")
|
|
11
|
+
assert SugarCRM.connection.set_note_attachment(n.id, "config_test.yaml", file)
|
|
12
|
+
attachment = SugarCRM.connection.get_note_attachment(n.id)
|
|
13
|
+
assert Base64.decode64(attachment["file"]) == file
|
|
14
|
+
assert n.delete
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
data/test/helper.rb
CHANGED
data/test/test_associations.rb
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
require 'helper'
|
|
2
2
|
|
|
3
3
|
class TestAssociations < Test::Unit::TestCase
|
|
4
|
+
context "A SugarCRM::Associations class" do
|
|
5
|
+
should "Return an array of Association objects when self#register(SugarCRM::User.new)" do
|
|
6
|
+
associations = SugarCRM::Associations.register(SugarCRM::User.new)
|
|
7
|
+
assert associations.include? "email_addresses"
|
|
8
|
+
assert associations.proxy_methods.include? "email_addresses"
|
|
9
|
+
end
|
|
10
|
+
end
|
|
4
11
|
context "A SugarCRM::Base instance" do
|
|
5
12
|
should "return an email address when sent #email_addresses" do
|
|
6
13
|
u = SugarCRM::User.find("seed_sarah_id")
|
|
@@ -37,5 +44,96 @@ class TestAssociations < Test::Unit::TestCase
|
|
|
37
44
|
a = SugarCRM::Account.first
|
|
38
45
|
assert_instance_of SugarCRM::User, a.created_by_link.first
|
|
39
46
|
end
|
|
47
|
+
|
|
48
|
+
should "create relationships with associate!" do
|
|
49
|
+
a = SugarCRM::Account.first
|
|
50
|
+
c = SugarCRM::Contact.create(:last_name => 'Doe')
|
|
51
|
+
|
|
52
|
+
nb_contacts = a.contacts.size
|
|
53
|
+
a.associate!(c)
|
|
54
|
+
assert_equal nb_contacts + 1, a.contacts.size # test association_cache is updated
|
|
55
|
+
|
|
56
|
+
assert_equal nb_contacts + 1, SugarCRM::Account.first.contacts.size # test relationship is created in Sugar
|
|
57
|
+
|
|
58
|
+
assert c.delete
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
should "destroy relationships with disassociate!" do
|
|
62
|
+
a = SugarCRM::Account.first
|
|
63
|
+
c = SugarCRM::Contact.create(:last_name => 'Doe')
|
|
64
|
+
|
|
65
|
+
a.associate!(c)
|
|
66
|
+
nb_contacts = a.contacts.size
|
|
67
|
+
a.disassociate!(c)
|
|
68
|
+
assert_equal nb_contacts - 1, a.contacts.size # test association_cache is updated
|
|
69
|
+
|
|
70
|
+
assert_equal nb_contacts - 1, SugarCRM::Account.first.contacts.size # test relationship is destroyed in Sugar
|
|
71
|
+
|
|
72
|
+
assert c.delete
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
should "not destroy a relationship if associate! is called with {:delete => 0}" do
|
|
76
|
+
a = SugarCRM::Account.first
|
|
77
|
+
c = SugarCRM::Contact.create(:last_name => 'Doe')
|
|
78
|
+
|
|
79
|
+
a.associate!(c)
|
|
80
|
+
nb_contacts = a.contacts.size
|
|
81
|
+
a.associate!(c, {:delete => 0})
|
|
82
|
+
assert_equal nb_contacts, a.contacts.size
|
|
83
|
+
|
|
84
|
+
assert c.delete
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
should "update association cache on associate! only if association changes" do
|
|
88
|
+
a = SugarCRM::Account.first
|
|
89
|
+
c = SugarCRM::Contact.create(:last_name => 'Doe')
|
|
90
|
+
|
|
91
|
+
nb_contacts = a.contacts.size
|
|
92
|
+
a.associate!(c)
|
|
93
|
+
assert_equal nb_contacts + 1, a.contacts.size
|
|
94
|
+
a.associate!(c)
|
|
95
|
+
assert_equal nb_contacts + 1, a.contacts.size # should not change: already associated
|
|
96
|
+
|
|
97
|
+
assert c.delete
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
should "update association cache on << only if association changes" do
|
|
101
|
+
a = SugarCRM::Account.first
|
|
102
|
+
c = SugarCRM::Contact.create(:last_name => 'Doe')
|
|
103
|
+
|
|
104
|
+
nb_contacts = a.contacts.size
|
|
105
|
+
a.contacts << c
|
|
106
|
+
assert_equal nb_contacts + 1, a.contacts.size
|
|
107
|
+
a.contacts << c
|
|
108
|
+
assert_equal nb_contacts + 1, a.contacts.size # should not change: already associated
|
|
109
|
+
|
|
110
|
+
assert c.delete
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
should "update association cache for both sides of the relationship when calling associate!" do
|
|
114
|
+
a = SugarCRM::Account.first
|
|
115
|
+
c = SugarCRM::Contact.create(:last_name => 'Doe')
|
|
116
|
+
|
|
117
|
+
nb_contacts = a.contacts.size
|
|
118
|
+
nb_accounts = c.accounts.size
|
|
119
|
+
a.associate!(c)
|
|
120
|
+
assert_equal nb_contacts + 1, a.contacts.size
|
|
121
|
+
assert_equal nb_accounts + 1, c.accounts.size
|
|
122
|
+
|
|
123
|
+
assert c.delete
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
should "update association cache for both sides of the relationship when calling <<" do
|
|
127
|
+
a = SugarCRM::Account.first
|
|
128
|
+
c = SugarCRM::Contact.create(:last_name => 'Doe')
|
|
129
|
+
|
|
130
|
+
nb_contacts = a.contacts.size
|
|
131
|
+
nb_accounts = c.accounts.size
|
|
132
|
+
a.contacts << c
|
|
133
|
+
assert_equal nb_contacts + 1, a.contacts.size
|
|
134
|
+
assert_equal nb_accounts + 1, c.accounts.size
|
|
135
|
+
|
|
136
|
+
assert c.delete
|
|
137
|
+
end
|
|
40
138
|
end
|
|
41
139
|
end
|
data/test/test_environment.rb
CHANGED
|
@@ -33,6 +33,13 @@ class TestEnvironment < Test::Unit::TestCase
|
|
|
33
33
|
SugarCRM::Environment.load_config File.join(File.dirname(__FILE__), 'config_test.yaml')
|
|
34
34
|
assert SugarCRM.connection.logged_in?
|
|
35
35
|
end
|
|
36
|
+
|
|
37
|
+
should "update the login credentials on connection" do
|
|
38
|
+
SugarCRM.connect!(URL, USER, PASS)
|
|
39
|
+
{:base_url => URL, :username => USER, :password => PASS}.each{|k,v|
|
|
40
|
+
assert_equal v, SugarCRM::Environment.config[k]
|
|
41
|
+
}
|
|
42
|
+
end
|
|
36
43
|
end
|
|
37
44
|
|
|
38
45
|
end
|
data/test/test_sugarcrm.rb
CHANGED
|
@@ -182,58 +182,6 @@ class TestSugarCRM < Test::Unit::TestCase
|
|
|
182
182
|
assert a.delete
|
|
183
183
|
end
|
|
184
184
|
|
|
185
|
-
should "update association cache on associate! only if association changes" do
|
|
186
|
-
a = SugarCRM::Account.first
|
|
187
|
-
c = SugarCRM::Contact.create(:last_name => 'Doe')
|
|
188
|
-
|
|
189
|
-
nb_contacts = a.contacts.size
|
|
190
|
-
a.associate!(c)
|
|
191
|
-
assert_equal nb_contacts + 1, a.contacts.size
|
|
192
|
-
a.associate!(c)
|
|
193
|
-
assert_equal nb_contacts + 1, a.contacts.size # should not change: already associated
|
|
194
|
-
|
|
195
|
-
c.delete
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
should "update association cache on << only if association changes" do
|
|
199
|
-
a = SugarCRM::Account.first
|
|
200
|
-
c = SugarCRM::Contact.create(:last_name => 'Doe')
|
|
201
|
-
|
|
202
|
-
nb_contacts = a.contacts.size
|
|
203
|
-
a.contacts << c
|
|
204
|
-
assert_equal nb_contacts + 1, a.contacts.size
|
|
205
|
-
a.contacts << c
|
|
206
|
-
assert_equal nb_contacts + 1, a.contacts.size # should not change: already associated
|
|
207
|
-
|
|
208
|
-
c.delete
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
should "update association cache for both sides of the relationship when calling associate!" do
|
|
212
|
-
a = SugarCRM::Account.first
|
|
213
|
-
c = SugarCRM::Contact.create(:last_name => 'Doe')
|
|
214
|
-
|
|
215
|
-
nb_contacts = a.contacts.size
|
|
216
|
-
nb_accounts = c.accounts.size
|
|
217
|
-
a.associate!(c)
|
|
218
|
-
assert_equal nb_contacts + 1, a.contacts.size
|
|
219
|
-
assert_equal nb_accounts + 1, c.accounts.size
|
|
220
|
-
|
|
221
|
-
c.delete
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
should "update association cache for both sides of the relationship when calling <<" do
|
|
225
|
-
a = SugarCRM::Account.first
|
|
226
|
-
c = SugarCRM::Contact.create(:last_name => 'Doe')
|
|
227
|
-
|
|
228
|
-
nb_contacts = a.contacts.size
|
|
229
|
-
nb_accounts = c.accounts.size
|
|
230
|
-
a.contacts << c
|
|
231
|
-
assert_equal nb_contacts + 1, a.contacts.size
|
|
232
|
-
assert_equal nb_accounts + 1, c.accounts.size
|
|
233
|
-
|
|
234
|
-
c.delete
|
|
235
|
-
end
|
|
236
|
-
|
|
237
185
|
should "support saving of records with special characters in them" do
|
|
238
186
|
a = SugarCRM::Account.new
|
|
239
187
|
a.name = "COHEN, WEISS & SIMON LLP"
|
metadata
CHANGED
|
@@ -1,114 +1,108 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sugarcrm
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
hash: 41
|
|
5
4
|
prerelease: false
|
|
6
5
|
segments:
|
|
7
6
|
- 0
|
|
8
7
|
- 9
|
|
9
|
-
-
|
|
10
|
-
version: 0.9.
|
|
8
|
+
- 10
|
|
9
|
+
version: 0.9.10
|
|
11
10
|
platform: ruby
|
|
12
11
|
authors:
|
|
13
12
|
- Carl Hicks
|
|
13
|
+
- David Sulc
|
|
14
14
|
autorequire:
|
|
15
15
|
bindir: bin
|
|
16
16
|
cert_chain: []
|
|
17
17
|
|
|
18
|
-
date: 2011-
|
|
18
|
+
date: 2011-02-06 00:00:00 -08:00
|
|
19
19
|
default_executable:
|
|
20
20
|
dependencies:
|
|
21
21
|
- !ruby/object:Gem::Dependency
|
|
22
|
-
type: :runtime
|
|
23
|
-
prerelease: false
|
|
24
22
|
name: activesupport
|
|
25
|
-
|
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
|
26
24
|
none: false
|
|
27
25
|
requirements:
|
|
28
26
|
- - ">="
|
|
29
27
|
- !ruby/object:Gem::Version
|
|
30
|
-
hash: 7
|
|
31
28
|
segments:
|
|
32
29
|
- 3
|
|
33
30
|
- 0
|
|
34
31
|
- 0
|
|
35
32
|
version: 3.0.0
|
|
36
|
-
requirement: *id001
|
|
37
|
-
- !ruby/object:Gem::Dependency
|
|
38
33
|
type: :runtime
|
|
39
34
|
prerelease: false
|
|
35
|
+
version_requirements: *id001
|
|
36
|
+
- !ruby/object:Gem::Dependency
|
|
40
37
|
name: i18n
|
|
41
|
-
|
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
|
42
39
|
none: false
|
|
43
40
|
requirements:
|
|
44
41
|
- - ">="
|
|
45
42
|
- !ruby/object:Gem::Version
|
|
46
|
-
hash: 3
|
|
47
43
|
segments:
|
|
48
44
|
- 0
|
|
49
45
|
version: "0"
|
|
50
|
-
requirement: *id002
|
|
51
|
-
- !ruby/object:Gem::Dependency
|
|
52
46
|
type: :runtime
|
|
53
47
|
prerelease: false
|
|
48
|
+
version_requirements: *id002
|
|
49
|
+
- !ruby/object:Gem::Dependency
|
|
54
50
|
name: json
|
|
55
|
-
|
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
|
56
52
|
none: false
|
|
57
53
|
requirements:
|
|
58
54
|
- - ">="
|
|
59
55
|
- !ruby/object:Gem::Version
|
|
60
|
-
hash: 3
|
|
61
56
|
segments:
|
|
62
57
|
- 0
|
|
63
58
|
version: "0"
|
|
64
|
-
|
|
65
|
-
- !ruby/object:Gem::Dependency
|
|
66
|
-
type: :development
|
|
59
|
+
type: :runtime
|
|
67
60
|
prerelease: false
|
|
61
|
+
version_requirements: *id003
|
|
62
|
+
- !ruby/object:Gem::Dependency
|
|
68
63
|
name: shoulda
|
|
69
|
-
|
|
64
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
|
70
65
|
none: false
|
|
71
66
|
requirements:
|
|
72
67
|
- - ">="
|
|
73
68
|
- !ruby/object:Gem::Version
|
|
74
|
-
hash: 3
|
|
75
69
|
segments:
|
|
76
70
|
- 0
|
|
77
71
|
version: "0"
|
|
78
|
-
requirement: *id004
|
|
79
|
-
- !ruby/object:Gem::Dependency
|
|
80
72
|
type: :development
|
|
81
73
|
prerelease: false
|
|
74
|
+
version_requirements: *id004
|
|
75
|
+
- !ruby/object:Gem::Dependency
|
|
82
76
|
name: bundler
|
|
83
|
-
|
|
77
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
|
84
78
|
none: false
|
|
85
79
|
requirements:
|
|
86
80
|
- - ~>
|
|
87
81
|
- !ruby/object:Gem::Version
|
|
88
|
-
hash: 23
|
|
89
82
|
segments:
|
|
90
83
|
- 1
|
|
91
84
|
- 0
|
|
92
85
|
- 0
|
|
93
86
|
version: 1.0.0
|
|
94
|
-
requirement: *id005
|
|
95
|
-
- !ruby/object:Gem::Dependency
|
|
96
87
|
type: :development
|
|
97
88
|
prerelease: false
|
|
89
|
+
version_requirements: *id005
|
|
90
|
+
- !ruby/object:Gem::Dependency
|
|
98
91
|
name: jeweler
|
|
99
|
-
|
|
92
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
|
100
93
|
none: false
|
|
101
94
|
requirements:
|
|
102
95
|
- - ~>
|
|
103
96
|
- !ruby/object:Gem::Version
|
|
104
|
-
hash: 7
|
|
105
97
|
segments:
|
|
106
98
|
- 1
|
|
107
99
|
- 5
|
|
108
100
|
- 2
|
|
109
101
|
version: 1.5.2
|
|
110
|
-
|
|
111
|
-
|
|
102
|
+
type: :development
|
|
103
|
+
prerelease: false
|
|
104
|
+
version_requirements: *id006
|
|
105
|
+
description:
|
|
112
106
|
email: carl.hicks@gmail.com
|
|
113
107
|
executables: []
|
|
114
108
|
|
|
@@ -185,10 +179,10 @@ files:
|
|
|
185
179
|
- test/connection/test_get_user_team_id.rb
|
|
186
180
|
- test/connection/test_login.rb
|
|
187
181
|
- test/connection/test_logout.rb
|
|
182
|
+
- test/connection/test_set_note_attachment.rb
|
|
188
183
|
- test/connection/test_set_relationship.rb
|
|
189
184
|
- test/extensions_test/patch.rb
|
|
190
185
|
- test/helper.rb
|
|
191
|
-
- test/test_association.rb
|
|
192
186
|
- test/test_association_collection.rb
|
|
193
187
|
- test/test_associations.rb
|
|
194
188
|
- test/test_connection.rb
|
|
@@ -210,7 +204,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
210
204
|
requirements:
|
|
211
205
|
- - ">="
|
|
212
206
|
- !ruby/object:Gem::Version
|
|
213
|
-
hash:
|
|
207
|
+
hash: 957398452548061165
|
|
214
208
|
segments:
|
|
215
209
|
- 0
|
|
216
210
|
version: "0"
|
|
@@ -219,7 +213,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
219
213
|
requirements:
|
|
220
214
|
- - ">="
|
|
221
215
|
- !ruby/object:Gem::Version
|
|
222
|
-
hash: 3
|
|
223
216
|
segments:
|
|
224
217
|
- 0
|
|
225
218
|
version: "0"
|
|
@@ -229,7 +222,7 @@ rubyforge_project:
|
|
|
229
222
|
rubygems_version: 1.3.7
|
|
230
223
|
signing_key:
|
|
231
224
|
specification_version: 3
|
|
232
|
-
summary:
|
|
225
|
+
summary: A less clunky way to interact with SugarCRM via REST.
|
|
233
226
|
test_files:
|
|
234
227
|
- test/connection/test_get_available_modules.rb
|
|
235
228
|
- test/connection/test_get_entries.rb
|
|
@@ -242,10 +235,10 @@ test_files:
|
|
|
242
235
|
- test/connection/test_get_user_team_id.rb
|
|
243
236
|
- test/connection/test_login.rb
|
|
244
237
|
- test/connection/test_logout.rb
|
|
238
|
+
- test/connection/test_set_note_attachment.rb
|
|
245
239
|
- test/connection/test_set_relationship.rb
|
|
246
240
|
- test/extensions_test/patch.rb
|
|
247
241
|
- test/helper.rb
|
|
248
|
-
- test/test_association.rb
|
|
249
242
|
- test/test_association_collection.rb
|
|
250
243
|
- test/test_associations.rb
|
|
251
244
|
- test/test_connection.rb
|
data/test/test_association.rb
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
#TODO: Figure out how to test this.
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
# That code works, but what didn't work:
|
|
5
|
-
# document.tasks.size
|
|
6
|
-
# document.associate!(task)
|
|
7
|
-
# document.tasks.size
|
|
8
|
-
# This seems to be fixed in HEAD in my repo. I haven't pushed the changes to your repo, because I don't really see why commit https://github.com/davidsulc/sugarcrm/commit/228375348c9113324370afa0aca4120eb117d3e1 fixes the issue...
|
|
9
|
-
# Also, I fixed this case
|
|
10
|
-
# document.tasks.size
|
|
11
|
-
# document.associate!(task)
|
|
12
|
-
# document.tasks.size # => 1 (correct)
|
|
13
|
-
# document.associate!(task)
|
|
14
|
-
# document.tasks.size # => 2 (incorrect: should remain 1)
|
|
15
|
-
# One thing we should look into is
|
|
16
|
-
# document.associate!(task)
|
|
17
|
-
# document.tasks.size # => 1
|
|
18
|
-
# task.documents.size # => 0 (should be 1)
|