acts_as_sdata 1.0.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/.gitignore +2 -0
- data/MIT-LICENSE +20 -0
- data/README.textile +200 -0
- data/Rakefile +20 -0
- data/VERSION +1 -0
- data/config/sdata.yml +13 -0
- data/config/sdata.yml.example +20 -0
- data/config/sdata.yml.tmpl.staging +14 -0
- data/generators/acts_as_sdata/acts_as_sdata_generator.rb +9 -0
- data/generators/acts_as_sdata/templates/migration.rb +69 -0
- data/init.rb +36 -0
- data/lib/s_data/active_record_extensions/base.rb +7 -0
- data/lib/s_data/active_record_extensions/mixin.rb +157 -0
- data/lib/s_data/active_record_extensions/sdata_uuid_mixin.rb +133 -0
- data/lib/s_data/atom_extensions/content_mixin.rb +14 -0
- data/lib/s_data/atom_extensions/entry_mixin.rb +41 -0
- data/lib/s_data/atom_extensions/nodes/digest.rb +48 -0
- data/lib/s_data/atom_extensions/nodes/payload.rb +34 -0
- data/lib/s_data/atom_extensions/nodes/sync_state.rb +14 -0
- data/lib/s_data/conditions_builder.rb +59 -0
- data/lib/s_data/controller_mixin.rb +11 -0
- data/lib/s_data/controller_mixin/actions.rb +87 -0
- data/lib/s_data/controller_mixin/collection_scope.rb +57 -0
- data/lib/s_data/controller_mixin/s_data_feed.rb +87 -0
- data/lib/s_data/controller_mixin/s_data_instance.rb +35 -0
- data/lib/s_data/diagnosis/application_controller_mixin.rb +16 -0
- data/lib/s_data/diagnosis/diagnosis.rb +130 -0
- data/lib/s_data/diagnosis/diagnosis_mapper.rb +39 -0
- data/lib/s_data/exceptions.rb +10 -0
- data/lib/s_data/formatting.rb +13 -0
- data/lib/s_data/namespace_definitions.rb +19 -0
- data/lib/s_data/payload.rb +158 -0
- data/lib/s_data/payload_map.rb +0 -0
- data/lib/s_data/payload_map/payload_map.rb +136 -0
- data/lib/s_data/payload_map/payload_map_hash.rb +39 -0
- data/lib/s_data/predicate.rb +31 -0
- data/lib/s_data/route_mapper.rb +143 -0
- data/lib/s_data/router_mixin.rb +10 -0
- data/lib/s_data/sync/controller_mixin.rb +122 -0
- data/lib/s_data/sync/sdata_syncing_mixin.rb +17 -0
- data/lib/s_data/virtual_base.rb +114 -0
- data/test/functional/Rakefile +0 -0
- data/test/unit/active_record_mixin/active_record_mixin_spec.rb +20 -0
- data/test/unit/active_record_mixin/acts_as_sdata_spec.rb +41 -0
- data/test/unit/active_record_mixin/find_by_sdata_instance_id_spec.rb +34 -0
- data/test/unit/active_record_mixin/payload_spec.rb +622 -0
- data/test/unit/active_record_mixin/to_atom_spec.rb +85 -0
- data/test/unit/atom_entry_mixin/atom_entry_mixin_spec.rb +11 -0
- data/test/unit/atom_entry_mixin/to_attributes_spec.rb +30 -0
- data/test/unit/class_stubs/address.rb +19 -0
- data/test/unit/class_stubs/contact.rb +25 -0
- data/test/unit/class_stubs/customer.rb +70 -0
- data/test/unit/class_stubs/model_base.rb +17 -0
- data/test/unit/class_stubs/payload.rb +15 -0
- data/test/unit/class_stubs/sd_uuid.rb +28 -0
- data/test/unit/class_stubs/user.rb +40 -0
- data/test/unit/conditions_builder_spec.rb +54 -0
- data/test/unit/controller_mixin/acts_as_sdata_spec.rb +29 -0
- data/test/unit/controller_mixin/build_sdata_feed_spec.rb +50 -0
- data/test/unit/controller_mixin/controller_mixin_spec.rb +22 -0
- data/test/unit/controller_mixin/diagnosis_spec.rb +232 -0
- data/test/unit/controller_mixin/sdata_collection_spec.rb +78 -0
- data/test/unit/controller_mixin/sdata_create_instance_spec.rb +173 -0
- data/test/unit/controller_mixin/sdata_opensearch_and_links_spec.rb +382 -0
- data/test/unit/controller_mixin/sdata_scope/linked_model_spec.rb +58 -0
- data/test/unit/controller_mixin/sdata_scope/non_linked_model_spec.rb +66 -0
- data/test/unit/controller_mixin/sdata_scope/scoping_in_config_spec.rb +64 -0
- data/test/unit/controller_mixin/sdata_show_instance_spec.rb +98 -0
- data/test/unit/controller_mixin/sdata_update_instance_spec.rb +65 -0
- data/test/unit/payload_map/payload_map_hash_spec.rb +84 -0
- data/test/unit/payload_map/payload_map_spec.rb +144 -0
- data/test/unit/predicate_spec.rb +59 -0
- data/test/unit/router_mixin/routes_spec.rb +138 -0
- data/test/unit/spec.opts +4 -0
- data/test/unit/spec_helper.rb +47 -0
- data/test/unit/spec_helpers/nokogiri_extensions.rb +16 -0
- data/test/unit/sync_controller_mixin/controller_mixin_spec.rb +22 -0
- data/test/unit/sync_controller_mixin/sdata_collection_sync_feed_spec.rb +69 -0
- metadata +175 -0
File without changes
|
@@ -0,0 +1,136 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module SData
|
4
|
+
module PayloadMap
|
5
|
+
def define_payload_map(map)
|
6
|
+
include InstanceMethods
|
7
|
+
cattr_accessor :payload_map
|
8
|
+
self.payload_map = PayloadMapHash.new(map)
|
9
|
+
self.payload_map.each do |name, opts|
|
10
|
+
has_sdata_attr(name, opts)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def has_sdata_attr(*args)
|
15
|
+
options = args.last.is_a?(Hash) ? args.pop : {:static_value => nil, :precedence => 50}
|
16
|
+
args.each do | name |
|
17
|
+
options[:method_name] ||= name
|
18
|
+
options[:method_name_with_deleted] = options[:method_name]
|
19
|
+
|
20
|
+
method_name = options[:method_name]
|
21
|
+
payload_map[name] ||= options
|
22
|
+
|
23
|
+
case field_type(options)
|
24
|
+
when :static_value
|
25
|
+
define_static_value_reader method_name, options[:static_value]
|
26
|
+
|
27
|
+
when :baze_field
|
28
|
+
define_baze_field_reference method_name, options[:baze_field]
|
29
|
+
|
30
|
+
when :method
|
31
|
+
|
32
|
+
when :proc
|
33
|
+
define_proc_caller method_name, options[:proc]
|
34
|
+
|
35
|
+
if options.has_key?(:proc_with_deleted)
|
36
|
+
method_name_with_deleted = options[:method_name_with_deleted] = "#{method_name.to_s}_with_deleted"
|
37
|
+
define_proc_with_deleted_caller method_name_with_deleted, options[:proc_with_deleted]
|
38
|
+
end
|
39
|
+
|
40
|
+
else
|
41
|
+
raise SData::Exceptions::VirtualBase::InvalidSDataAttribute.new(
|
42
|
+
"#{args.join(", ")}: must supply a static_value, baze_field, method or proc")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def has_sdata_association(*args)
|
48
|
+
options = args.last.is_a?(Hash) ? args.pop : {:precedence => 50, :type => :association}
|
49
|
+
options[:type] ||= :association
|
50
|
+
raise SData::Exceptions::VirtualBase::InvalidSDataAssociation.new(
|
51
|
+
"#{args.join(", ")}: must supply a proc or method") unless [:proc, :method].any?{|k|options.has_key?(k)}
|
52
|
+
raise SData::Exceptions::VirtualBase::InvalidSDataAssociation.new(
|
53
|
+
"#{args.join(", ")}: invalid association type '#{options[:type]}") unless [:association, :child].include?(options[:type])
|
54
|
+
args.push options
|
55
|
+
has_sdata_attr(*args)
|
56
|
+
end
|
57
|
+
|
58
|
+
module InstanceMethods
|
59
|
+
def payload
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
# Walks the payload, loading each association, descending into children, and yielding the tuple
|
65
|
+
# [payload_map_definition, node_object(s)] for each node. Can use without a block
|
66
|
+
# to fire all faults -- sync uses this when caching changed objects.
|
67
|
+
def associations_with_deleted(expand=:all_children)
|
68
|
+
return if expand == :none
|
69
|
+
payload_map.each_pair do |child_node_name, child_node_data|
|
70
|
+
if child_node_data[:type] == :association
|
71
|
+
expand = :none
|
72
|
+
elsif child_node_data[:type] == :child
|
73
|
+
expand = :all_children
|
74
|
+
else
|
75
|
+
next
|
76
|
+
end
|
77
|
+
child = __send__(child_node_data[:method_name_with_deleted])
|
78
|
+
yield child_node_data.merge(:name => child_node_name), child if block_given?
|
79
|
+
case child
|
80
|
+
when Array
|
81
|
+
child.each{ |grandchild| grandchild.associations_with_deleted(expand) if child.is_a?(SData::VirtualBase)}
|
82
|
+
when SData::VirtualBase
|
83
|
+
associations_with_deleted(expand)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
protected
|
90
|
+
|
91
|
+
def field_type(options)
|
92
|
+
[:static_value, :baze_field, :method, :proc].each do |type|
|
93
|
+
if options.has_key?(type)
|
94
|
+
return type
|
95
|
+
end
|
96
|
+
end
|
97
|
+
nil
|
98
|
+
end
|
99
|
+
|
100
|
+
def define_static_value_reader(method_name, value)
|
101
|
+
class_eval do
|
102
|
+
define_method method_name do
|
103
|
+
value
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def define_baze_field_reference(method_name, baze_field)
|
109
|
+
class_eval do
|
110
|
+
define_method method_name do
|
111
|
+
self.baze.__send__ baze_field
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def define_proc_caller(method_name, block)
|
117
|
+
class_eval do
|
118
|
+
define_method method_name, block
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def define_proc_with_deleted_caller(method_name, block)
|
123
|
+
cache_var = "@#{method_name.to_s}_cached"
|
124
|
+
class_eval do
|
125
|
+
define_method(method_name) do
|
126
|
+
unless instance_variable_get(cache_var)
|
127
|
+
instance_variable_set(cache_var, instance_eval(&block))
|
128
|
+
end
|
129
|
+
instance_variable_get(cache_var)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
SData::VirtualBase.extend SData::PayloadMap
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module SData
|
2
|
+
module PayloadMap
|
3
|
+
class PayloadMapHash < Hash
|
4
|
+
def initialize(hash)
|
5
|
+
merge!(hash)
|
6
|
+
end
|
7
|
+
|
8
|
+
def attrs
|
9
|
+
reject{|k,v| ! [:static_value, :baze_field].any?{|type| v.has_key?(type)} }
|
10
|
+
end
|
11
|
+
|
12
|
+
def static_values
|
13
|
+
subset :static_value
|
14
|
+
end
|
15
|
+
|
16
|
+
def baze_fields
|
17
|
+
subset :baze_field
|
18
|
+
end
|
19
|
+
|
20
|
+
def procs
|
21
|
+
subset :proc
|
22
|
+
end
|
23
|
+
|
24
|
+
def procs_with_deleted
|
25
|
+
subset :proc_with_deleted, :proc
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
def subset(*mapping_type)
|
31
|
+
mapping_type = [mapping_type].flatten
|
32
|
+
raw_subset = select { |key, value| mapping_type.any?{|type| value.has_key?(type) }}
|
33
|
+
hash = Hash[raw_subset]
|
34
|
+
hash.merge(hash){ |key, value| value[mapping_type.detect{|type| value.include?(type)}] }
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module SData
|
2
|
+
class Predicate < Struct.new(:field, :relation, :value)
|
3
|
+
def self.parse(fields_map, predicate_string)
|
4
|
+
# Gotcha on Rightscale that escaped + before it hits controller, but doesn't escape other special chars!
|
5
|
+
escaped_predicate_string = CGI::unescape(predicate_string.gsub('+', '%2B'))
|
6
|
+
match_data = escaped_predicate_string.match(/(\w+)\s(gt|lt|eq|ne|lteq|gteq)\s('?.+'?|'')/) || []
|
7
|
+
|
8
|
+
canonical_field_name = match_data[1].underscore.to_sym unless match_data[1].nil?
|
9
|
+
self.new fields_map[canonical_field_name], match_data[2], strip_quotes(match_data[3])
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.strip_quotes(value)
|
13
|
+
return value unless value.is_a?(String)
|
14
|
+
value = value.gsub("%27", "'")
|
15
|
+
return value unless value =~ /'.*?'/
|
16
|
+
return value[1,value.length-2]
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_conditions
|
20
|
+
if valid?
|
21
|
+
ConditionsBuilder.build_conditions field, relation.to_sym, value
|
22
|
+
else
|
23
|
+
raise Sage::BusinessLogic::Exception::IncompatibleDataException, "Invalid predicate string"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def valid?
|
28
|
+
field && relation && value
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module SData
|
2
|
+
class RouteMapper < Struct.new(:router, :resource_name, :options)
|
3
|
+
def map_sdata_routes!
|
4
|
+
#RADAR: the order of the below statements makes a difference
|
5
|
+
|
6
|
+
map_sdata_show_instance
|
7
|
+
map_sdata_show_instance_with_condition_and_predicate
|
8
|
+
map_sdata_show_instance_with_condition
|
9
|
+
map_sdata_show_instance_with_predicate
|
10
|
+
|
11
|
+
map_sdata_create_link
|
12
|
+
map_sdata_create_instance
|
13
|
+
map_sdata_update_instance
|
14
|
+
|
15
|
+
map_sdata_sync_source
|
16
|
+
map_sdata_sync_source_status
|
17
|
+
map_sdata_sync_source_delete
|
18
|
+
map_sdata_receive_sync_results
|
19
|
+
|
20
|
+
map_sdata_collection_with_condition
|
21
|
+
map_sdata_collection
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.urlize(string)
|
25
|
+
string.gsub("'", "(%27|')").gsub("\s", "(%20|\s)")
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
CONDITION = urlize("{:condition,([$](linked))}")
|
31
|
+
PREDICATE = urlize("{:predicate,[A-z]+\s[A-z]+\s'?[^']*'?}")
|
32
|
+
|
33
|
+
TRACKING_ID = urlize("{:trackingID,'[^']+'}")
|
34
|
+
|
35
|
+
# http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts
|
36
|
+
def map_sdata_collection
|
37
|
+
map_route "#{name_in_path}", 'sdata_collection', :get
|
38
|
+
end
|
39
|
+
|
40
|
+
# http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts/$syncSource('someid')
|
41
|
+
def map_sdata_sync_source_status
|
42
|
+
map_route "#{name_in_path}\/$syncSource\\(:trackingID\\)", 'sdata_collection_sync_feed_status', :get
|
43
|
+
end
|
44
|
+
|
45
|
+
# http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts/$syncSource
|
46
|
+
def map_sdata_sync_source_delete
|
47
|
+
map_route "#{name_in_path}\/$syncSource\\(:trackingID\\)", 'sdata_collection_sync_feed_delete', :delete
|
48
|
+
end
|
49
|
+
|
50
|
+
# http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts/$linked
|
51
|
+
def map_sdata_collection_with_condition
|
52
|
+
map_route "#{name_in_path}\/#{CONDITION}", 'sdata_collection', :get
|
53
|
+
end
|
54
|
+
|
55
|
+
# http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts('1')
|
56
|
+
def map_sdata_show_instance
|
57
|
+
map_route "#{name_in_path}\\(:instance_id\\)", 'sdata_show_instance', :get
|
58
|
+
end
|
59
|
+
|
60
|
+
# http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts/$linked('1')
|
61
|
+
def map_sdata_show_instance_with_condition
|
62
|
+
map_route "#{name_in_path}/#{CONDITION}\\(:instance_id\\)", 'sdata_show_instance', :get
|
63
|
+
end
|
64
|
+
|
65
|
+
# http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts(name eq 'asdf')
|
66
|
+
# http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts(name eq asdf)
|
67
|
+
# http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts(name eq '')
|
68
|
+
def map_sdata_show_instance_with_predicate
|
69
|
+
map_route "#{name_in_path}\\(#{PREDICATE}\\)", 'sdata_show_instance', :get
|
70
|
+
end
|
71
|
+
|
72
|
+
# /$linked(name eq 'Second')
|
73
|
+
def map_sdata_show_instance_with_condition_and_predicate
|
74
|
+
map_route "#{name_in_path}/#{CONDITION}\\(#{PREDICATE}\\)", 'sdata_show_instance', :get
|
75
|
+
end
|
76
|
+
|
77
|
+
# http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts
|
78
|
+
def map_sdata_create_instance
|
79
|
+
map_route "#{name_in_path}", 'sdata_create_instance', :post
|
80
|
+
end
|
81
|
+
|
82
|
+
# http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts/$linked
|
83
|
+
def map_sdata_create_link
|
84
|
+
map_route "#{name_in_path}/#{CONDITION}", 'sdata_create_link', :post
|
85
|
+
end
|
86
|
+
|
87
|
+
# http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts('1')
|
88
|
+
def map_sdata_update_instance
|
89
|
+
map_route "#{name_in_path}\\(:instance_id\\)", 'sdata_update_instance', :put
|
90
|
+
end
|
91
|
+
|
92
|
+
# http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts/$syncSource
|
93
|
+
def map_sdata_sync_source
|
94
|
+
map_route "#{name_in_path}/$syncSource", 'sdata_collection_sync_feed', :post
|
95
|
+
end
|
96
|
+
|
97
|
+
# http://localhost:3000/sdata/billingboss/crmErp/-/tradingAccounts/$syncResults
|
98
|
+
def map_sdata_receive_sync_results
|
99
|
+
map_route "#{name_in_path}/$syncResults\\(:trackingID\\)", 'sdata_collection_sync_results', :post
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
def map_route(path, action, method)
|
104
|
+
path = prefix.chomp('/') + '/' + path if prefix?
|
105
|
+
path = path + ".sdata" if formatted_paths?
|
106
|
+
|
107
|
+
router.connect path, :controller => controller_with_namespace, :action => action, :conditions => { :method => method }, :priority => 99
|
108
|
+
end
|
109
|
+
|
110
|
+
def controller_with_namespace
|
111
|
+
@controller_with_namespace ||= "#{namespace}#{controller}"
|
112
|
+
end
|
113
|
+
|
114
|
+
def namespace
|
115
|
+
@namespace ||= (options[:namespace] ? "#{options[:namespace]}/" : "")
|
116
|
+
end
|
117
|
+
|
118
|
+
def controller
|
119
|
+
@controller ||= resource_name.to_s.pluralize
|
120
|
+
end
|
121
|
+
|
122
|
+
def name_in_path
|
123
|
+
@name_in_path ||= resource_name.to_s.camelize(:lower).pluralize
|
124
|
+
end
|
125
|
+
|
126
|
+
def formatted_paths?
|
127
|
+
@formatted_paths ||= options[:formatted_paths]
|
128
|
+
end
|
129
|
+
|
130
|
+
def prefix
|
131
|
+
if options[:prefix]
|
132
|
+
@prefix = options[:prefix] + '/{:dataset,([^\/]+)}'
|
133
|
+
else
|
134
|
+
@prefix = '/'
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def prefix?
|
139
|
+
!! prefix
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module SData
|
2
|
+
module RouterMixin
|
3
|
+
def sdata_resource(name, options={})
|
4
|
+
route_creator = SData::RouteMapper.new(self, name, options)
|
5
|
+
route_creator.map_sdata_routes!
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
ActionController::Routing::RouteSet::Mapper.__send__ :include, SData::RouterMixin
|
@@ -0,0 +1,122 @@
|
|
1
|
+
module SData
|
2
|
+
module Sync
|
3
|
+
module ControllerMixin
|
4
|
+
def syncs_sdata(options={})
|
5
|
+
raise "cannot sync sdata unless controller first acts_as_sdata" if self.sdata_options.nil?
|
6
|
+
cattr_accessor :sdata_sync_options
|
7
|
+
self.sdata_sync_options = options
|
8
|
+
|
9
|
+
include InstanceMethods
|
10
|
+
end
|
11
|
+
|
12
|
+
module InstanceMethods
|
13
|
+
module Actions
|
14
|
+
# TODO: error handling
|
15
|
+
def sdata_collection_sync_feed
|
16
|
+
# get the target digest
|
17
|
+
payload = params[:entry].sdata_payload
|
18
|
+
|
19
|
+
raise "no payload!" if payload.blank?
|
20
|
+
|
21
|
+
sd_sync_run = SData::SdSyncRun.find_by_tracking_id(tracking_id)
|
22
|
+
raise Sage::BusinessLogic::Exception::AccessDeniedException, "Access denied" unless sd_sync_run.nil?
|
23
|
+
|
24
|
+
# prepare a sync run to hold our state
|
25
|
+
sd_sync_run = SData::SdSyncRun.new( :tracking_id => tracking_id,
|
26
|
+
:run_name => params[:runName],
|
27
|
+
# :created_at => params[:runStamp],
|
28
|
+
:sd_class => model_class.sdata_name,
|
29
|
+
:created_by => target_user)
|
30
|
+
sd_sync_run.target_digest = payload.sync_digest
|
31
|
+
|
32
|
+
sd_sync_run.start!
|
33
|
+
sd_sync_run.process!
|
34
|
+
xml = sd_sync_run.to_xml.to_s
|
35
|
+
render :xml => xml, :content_type => "application/xml", :location => sync_source_url(sd_sync_run.tracking_id), :status => 202
|
36
|
+
end
|
37
|
+
|
38
|
+
def sdata_collection_sync_feed_status
|
39
|
+
sd_sync_run = SData::SdSyncRun.find_by_tracking_id(tracking_id)
|
40
|
+
raise Sage::BusinessLogic::Exception::AccessDeniedException, "Access denied" if sd_sync_run.nil?
|
41
|
+
assert_access_to sd_sync_run
|
42
|
+
if sd_sync_run.finished?
|
43
|
+
@total_results = sd_sync_run.total_results
|
44
|
+
feed = build_sdata_feed(:feed => {:title => "#{model_class.sdata_name} synchronization feed #{params[:trackingID]}"})
|
45
|
+
feed[SData.config[:schemas]['sync'], 'syncMode'] << "catchUp"
|
46
|
+
|
47
|
+
feed.sync_digest = sd_sync_run.source_digest
|
48
|
+
|
49
|
+
atom_entries = []
|
50
|
+
errors = []
|
51
|
+
sd_sync_run.objects[zero_based_start_index,records_to_return].each do |obj|
|
52
|
+
begin
|
53
|
+
# RADAR: this (the (params) part) will allow user to insert a different dataset (and possibly
|
54
|
+
# other data) than that which was synchronized during the run. If this is somehow a security
|
55
|
+
# problem, need to freeze that data during synctime. an be also solved by freezing username
|
56
|
+
# in feed and matching dataset against it at accestime.
|
57
|
+
# RADAR: children (e.g. line items) will be embedded in parent (e.g. invoice) during this
|
58
|
+
# request, but from live data rather than syncronized one, is this a potential problem?
|
59
|
+
feed.entries << obj.to_atom(params.merge(:sync => true)){|entry| entry.sync_syncState = obj.sd_sync_state }
|
60
|
+
rescue Exception => e
|
61
|
+
errors << ApplicationDiagnosis.new(:exception => e).to_xml(:feed)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
#TODO: syntactic sugar if possible (such as diagnosing_errors(&block) which does the dirty work)
|
65
|
+
errors.each do |error|
|
66
|
+
feed[SData.config[:schemas]['sdata'], 'diagnosis'] << error
|
67
|
+
end
|
68
|
+
populate_open_search_for(feed)
|
69
|
+
build_feed_links_for(feed)
|
70
|
+
render :xml => feed, :content_type => "application/atom+xml; type=feed"
|
71
|
+
else
|
72
|
+
render :xml => sd_sync_run.to_xml.to_s,
|
73
|
+
:content_type => "application/atom+xml; type=feed",
|
74
|
+
:location => sync_source_url(sd_sync_run.tracking_id),
|
75
|
+
:status => 202
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def sdata_collection_sync_feed_delete
|
80
|
+
sd_sync_run = SData::SdSyncRun.find_by_tracking_id(tracking_id)
|
81
|
+
sd_sync_run.destroy
|
82
|
+
render :text => "OK"
|
83
|
+
end
|
84
|
+
|
85
|
+
def sdata_collection_sync_results
|
86
|
+
render :text => "Not implemented!"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
module AuxiliaryMethods
|
90
|
+
protected
|
91
|
+
|
92
|
+
# TODO: sort out profusion of urls endpoints and config classes!
|
93
|
+
def resource_url
|
94
|
+
case self.action_name
|
95
|
+
when 'sdata_collection_sync_feed_status',
|
96
|
+
'sdata_collection_sync_feed_status',
|
97
|
+
'sdata_collection_sync_feed_delete'
|
98
|
+
super + "/$syncSource('#{tracking_id}')"
|
99
|
+
else
|
100
|
+
super
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def sync_source_url(track)
|
105
|
+
endpoint = target_user.endpoint
|
106
|
+
"#{endpoint}/#{SData.sdata_collection_url_component(model_class)}/$syncSource('#{track}')"
|
107
|
+
end
|
108
|
+
|
109
|
+
def tracking_id
|
110
|
+
CGI::unescape(params[:trackingID]).gsub(/^'/,'').gsub(/'$/,'')
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
end
|
115
|
+
include Actions
|
116
|
+
include AuxiliaryMethods
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
ActionController::Base.extend SData::Sync::ControllerMixin
|
122
|
+
# Atom::Entry.elements "sync:digest", :class => SData::SdDigest::AtomWrapper
|