infopark_reactor 1.10.0.beta → 1.11.0.beta2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/app/models/rails_connector/abstract_model.rb +7 -0
  3. data/app/models/rails_connector/abstract_obj.rb +31 -0
  4. data/app/models/rails_connector/attribute.rb +94 -0
  5. data/app/models/rails_connector/blob_mapping.rb +12 -0
  6. data/app/models/rails_connector/channel.rb +41 -0
  7. data/app/models/rails_connector/content.rb +12 -0
  8. data/app/models/rails_connector/meta/eager_loader.rb +41 -0
  9. data/app/models/rails_connector/obj_class.rb +143 -0
  10. data/app/models/rails_connector/object_with_meta_data.rb +18 -0
  11. data/infopark_reactor.gemspec +4 -4
  12. data/lib/generators/cm/migration/USAGE +8 -0
  13. data/lib/generators/cm/migration/migration_generator.rb +16 -0
  14. data/lib/generators/cm/migration/templates/template.rb +8 -0
  15. data/lib/infopark_reactor.rb +35 -1
  16. data/lib/reactor/attributes.rb +2 -4
  17. data/lib/reactor/cm/attribute.rb +91 -0
  18. data/lib/reactor/cm/bridge.rb +50 -0
  19. data/lib/reactor/cm/channel.rb +18 -0
  20. data/lib/reactor/cm/editorial_group.rb +23 -0
  21. data/lib/reactor/cm/group.rb +241 -0
  22. data/lib/reactor/cm/language.rb +57 -0
  23. data/lib/reactor/cm/link.rb +136 -0
  24. data/lib/reactor/cm/live_group.rb +23 -0
  25. data/lib/reactor/cm/log_entry.rb +64 -0
  26. data/lib/reactor/cm/missing_credentials.rb +8 -0
  27. data/lib/reactor/cm/multi_xml_request.rb +102 -0
  28. data/lib/reactor/cm/obj.rb +544 -0
  29. data/lib/reactor/cm/obj_class.rb +187 -0
  30. data/lib/reactor/cm/object_base.rb +165 -0
  31. data/lib/reactor/cm/permissions.rb +44 -0
  32. data/lib/reactor/cm/user.rb +139 -0
  33. data/lib/reactor/cm/workflow.rb +41 -0
  34. data/lib/reactor/cm/xml_attribute.rb +36 -0
  35. data/lib/reactor/cm/xml_markup.rb +86 -0
  36. data/lib/reactor/cm/xml_multi_request_error.rb +10 -0
  37. data/lib/reactor/cm/xml_request.rb +83 -0
  38. data/lib/reactor/cm/xml_request_error.rb +11 -0
  39. data/lib/reactor/cm/xml_response.rb +43 -0
  40. data/lib/reactor/cm/xml_single_request_error.rb +21 -0
  41. data/lib/reactor/configuration.rb +8 -0
  42. data/lib/{engine.rb → reactor/engine.rb} +16 -1
  43. data/lib/reactor/legacy.rb +3 -3
  44. data/lib/reactor/link/temporary_link.rb +8 -4
  45. data/lib/reactor/migration.rb +87 -0
  46. data/lib/reactor/permission.rb +2 -2
  47. data/lib/reactor/persistence.rb +14 -12
  48. data/lib/reactor/plans/common_attribute.rb +33 -0
  49. data/lib/reactor/plans/common_channel.rb +32 -0
  50. data/lib/reactor/plans/common_group.rb +45 -0
  51. data/lib/reactor/plans/common_obj_class.rb +70 -0
  52. data/lib/reactor/plans/create_attribute.rb +33 -0
  53. data/lib/reactor/plans/create_channel.rb +24 -0
  54. data/lib/reactor/plans/create_group.rb +35 -0
  55. data/lib/reactor/plans/create_obj.rb +49 -0
  56. data/lib/reactor/plans/create_obj_class.rb +29 -0
  57. data/lib/reactor/plans/delete_attribute.rb +24 -0
  58. data/lib/reactor/plans/delete_channel.rb +22 -0
  59. data/lib/reactor/plans/delete_group.rb +29 -0
  60. data/lib/reactor/plans/delete_obj.rb +23 -0
  61. data/lib/reactor/plans/delete_obj_class.rb +23 -0
  62. data/lib/reactor/plans/prepared.rb +16 -0
  63. data/lib/reactor/plans/rename_group.rb +33 -0
  64. data/lib/reactor/plans/rename_obj_class.rb +25 -0
  65. data/lib/reactor/plans/update_attribute.rb +24 -0
  66. data/lib/reactor/plans/update_group.rb +31 -0
  67. data/lib/reactor/plans/update_obj.rb +31 -0
  68. data/lib/reactor/plans/update_obj_class.rb +27 -0
  69. data/lib/reactor/rails_connector_meta.rb +144 -0
  70. data/lib/reactor/tools/migrator.rb +136 -0
  71. data/lib/reactor/tools/response_handler/base.rb +23 -0
  72. data/lib/reactor/tools/response_handler/string.rb +20 -0
  73. data/lib/reactor/tools/response_handler/xml_attribute.rb +53 -0
  74. data/lib/reactor/tools/smart_xml_logger.rb +70 -0
  75. data/lib/reactor/tools/sower.rb +90 -0
  76. data/lib/reactor/tools/uploader.rb +134 -0
  77. data/lib/reactor/tools/versioner.rb +121 -0
  78. data/lib/reactor/tools/workflow_generator.rb +1 -1
  79. data/lib/reactor/tools/xml_attributes.rb +71 -0
  80. data/lib/reactor/version.rb +1 -1
  81. data/lib/tasks/cm_migrate.rake +8 -0
  82. data/lib/tasks/cm_seeds.rake +41 -0
  83. metadata +82 -13
  84. data/README.md +0 -186
@@ -0,0 +1,50 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Reactor
3
+ module Cm
4
+ class Bridge
5
+ # credit goes to Anton
6
+ def self.login_for(sessionId)
7
+ old_username = Reactor::Configuration.xml_access[:username]
8
+ Reactor::Configuration.xml_access[:username] = 'root'
9
+ begin
10
+ response = Reactor::Cm::XmlRequest.prepare do |xml|
11
+ xml.tag!('licenseManager-logins')
12
+ end.execute!
13
+ login = nil
14
+ result = response.xpath('//licenseManager-logins/listitem')
15
+ result = [result] unless result.kind_of?(Array)
16
+ result.each do |login_data_element|
17
+ properties = deserialize_login_data(login_data_element.text)
18
+ if properties[:sessionId] == sessionId && properties[:interface] == "X"
19
+ login = properties[:login]
20
+ break
21
+ end
22
+ end
23
+ login
24
+ rescue => e
25
+ Rails.logger.error "Login to CM failed! #{e.class}: #{e.message}"
26
+ nil
27
+ ensure
28
+ Reactor::Configuration.xml_access[:username] = old_username
29
+ end
30
+ end
31
+
32
+ private
33
+ def self.deserialize_login_data(serialized_property_list)
34
+ entry_delimiter = /;\r?\n/
35
+ no_braces = serialized_property_list[1..(serialized_property_list.rindex(entry_delimiter) - 1)]
36
+ property_list_lines = no_braces.split(entry_delimiter)
37
+ property_list_lines.inject(properties = {}) do |map, line|
38
+ key, value = line.strip.scan(/^([^=]*) = (.*)$/).first
39
+ if value[0..0] == '"'
40
+ value = value[1..(value.length - 2)]
41
+ value.gsub!(/\\(.)/, '\1')
42
+ end
43
+ map[key.to_sym] = value
44
+ map
45
+ end
46
+ properties
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,18 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'reactor/cm/object_base'
3
+
4
+ module Reactor
5
+ module Cm
6
+ class Channel < ObjectBase
7
+ # Attribute definitions
8
+ attribute :name, :except => [:set]
9
+ attribute :title
10
+
11
+ primary_key :name
12
+
13
+ def self.create(name)
14
+ super(name, {:name => name})
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'reactor/cm/group'
3
+
4
+ module Reactor
5
+
6
+ module Cm
7
+
8
+ # The EditorialGroup class respects the user management configured in the content manager and
9
+ # handles all editorial groups. See @Group for further details.
10
+ class EditorialGroup < Group
11
+
12
+ protected
13
+
14
+ # Overwritten method from +Group+.
15
+ def base_name
16
+ 'groupProxy'
17
+ end
18
+
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,241 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'reactor/cm/xml_request'
3
+ require 'reactor/cm/xml_response'
4
+ require 'reactor/cm/xml_request_error'
5
+ require 'reactor/tools/xml_attributes'
6
+ require 'reactor/tools/response_handler/string'
7
+
8
+ require 'reactor/cm/permissions'
9
+
10
+ module Reactor
11
+
12
+ module Cm
13
+
14
+ # The Group class can be used to work with user groups defined or known to the content manager.
15
+ # It allows you to create, edit and delete groups, handle users and permissions and get the
16
+ # group meta data. The Group class does not respect the user management defined under
17
+ # "config/userManagement.xml", but is the basis for class like @EditorialGroup or @LiveGroup
18
+ # that respect the user management.
19
+ class Group
20
+
21
+ include XmlAttributes
22
+
23
+ class << self
24
+
25
+ # Method returns true if a group with the given +name+ exists, false otherwise.
26
+ def exists?(name)
27
+ object = new(:name => name)
28
+
29
+ begin
30
+ object.send(:get).present?
31
+ rescue XmlRequestError
32
+ false
33
+ end
34
+ end
35
+
36
+ # Returns all known group names as an array of strings.
37
+ def all(match = '')
38
+ object = new
39
+
40
+ base_name = object.send(:base_name)
41
+
42
+ request = XmlRequest.prepare do |xml|
43
+ xml.where_key_tag!(base_name, 'groupText', match)
44
+ xml.get_key_tag!(base_name, 'name')
45
+ end
46
+
47
+ begin
48
+ response = request.execute!
49
+ groups = ResponseHandler::String.new.get(response, '//group/name/text()')
50
+
51
+ groups.is_a?(Array) ? groups : [groups]
52
+ rescue XmlRequestError
53
+ []
54
+ end
55
+
56
+ end
57
+
58
+ # See @get.
59
+ def get(name)
60
+ object = new(:name => name)
61
+ object.send(:get)
62
+ object
63
+ end
64
+
65
+ # See @create.
66
+ def create(attributes = {})
67
+ object = new(attributes)
68
+ object.send(:create)
69
+ object
70
+ end
71
+
72
+ end
73
+
74
+ include Permissions
75
+
76
+ attribute :name, :except => [:set]
77
+ attribute :display_title, :name => :displayTitle, :only => [:get]
78
+ attribute :real_name, :name => :realName
79
+ attribute :owner
80
+ attribute :users, :type => :list
81
+
82
+ primary_key :name
83
+
84
+ # Returns true, if an user with the given +name+ exists, false otherwise.
85
+ def user?(name)
86
+ users.include?(name)
87
+ end
88
+
89
+ # Add the given +users+ to the current set of group users.
90
+ def add_users!(users)
91
+ users = users.kind_of?(Array) ? users : [users]
92
+ users = self.users | users
93
+
94
+ set_users(users)
95
+ end
96
+
97
+ # Remove the given +users+ from the current set of group users.
98
+ def remove_users!(users)
99
+ users = users.kind_of?(Array) ? users : [users]
100
+ users = self.users - users
101
+
102
+ set_users(users)
103
+ end
104
+
105
+ # Set the group users to the given +users+.
106
+ def set_users!(users)
107
+ request = XmlRequest.prepare do |xml|
108
+ xml.where_key_tag!(base_name, self.class.primary_key, self.name)
109
+ xml.set_key_tag!(base_name, self.class.xml_attribute(:users).name, users)
110
+ end
111
+
112
+ request.execute!
113
+
114
+ self.users = users
115
+ end
116
+
117
+ # Saves all settable instance attributes to the Content Manager.
118
+ def save!
119
+ request = XmlRequest.prepare do |xml|
120
+ xml.where_key_tag!(base_name, self.class.primary_key, self.name)
121
+ xml.set_tag!(base_name) do
122
+ self.class.attributes(:set).each do |name, xml_attribute|
123
+ value = self.send(name)
124
+
125
+ xml.value_tag!(xml_attribute.name, value)
126
+ end
127
+ end
128
+ end
129
+
130
+ response = request.execute!
131
+
132
+ response.ok?
133
+ end
134
+
135
+ # Deletes the current group instance.
136
+ def delete!
137
+ request = XmlRequest.prepare do |xml|
138
+ xml.where_key_tag!(base_name, self.class.primary_key, self.name)
139
+ xml.delete_tag!(base_name)
140
+ end
141
+
142
+ response = request.execute!
143
+
144
+ response.ok?
145
+ end
146
+
147
+ # As it is not possible to actually rename an existing group, this method creates a new group
148
+ # with the same attributes but a different name as the current instance and deletes the old
149
+ # group. The method returns the new group object.
150
+ def rename!(name)
151
+ new_attributes =
152
+ self.class.attributes.inject({}) do |hash, mapping|
153
+ key, _ = mapping
154
+
155
+ hash[key] = self.send(key)
156
+
157
+ hash
158
+ end
159
+
160
+ if self.delete!
161
+ new_attributes[:name] = name
162
+
163
+ self.class.create(new_attributes)
164
+ else
165
+ false
166
+ end
167
+ end
168
+
169
+ protected
170
+
171
+ # The group base name can either be "group", "groupProxy", or "secondaryGroupProxy". Only the
172
+ # two proxy group names take the configured user management (config/userManagement.xml) into
173
+ # account. Use +EditorialGroup+ to work on editorial groups and +LiveGroup+ to work on live
174
+ # groups.
175
+ def base_name
176
+ 'group'
177
+ end
178
+
179
+ def initialize(attributes = {})
180
+ update_attributes(attributes)
181
+ end
182
+
183
+ # Retrieves a single group matching the name set in the current instance.
184
+ def get
185
+ request = XmlRequest.prepare do |xml|
186
+ xml.where_key_tag!(base_name, self.class.primary_key, self.name)
187
+ xml.get_key_tag!(base_name, self.class.xml_attribute_names)
188
+ end
189
+
190
+ response = request.execute!
191
+
192
+ self.class.attributes(:get).each do |name, xml_attribute|
193
+ value = self.class.response_handler.get(response, xml_attribute)
194
+
195
+ set_attribute(name, value)
196
+ end
197
+
198
+ self
199
+ end
200
+
201
+ # Creates a new group and sets all attributes that are settable on create. Other attributes
202
+ # are ignored and would be overwritten by the final +get+ call.
203
+ def create
204
+ request = XmlRequest.prepare do |xml|
205
+ xml.create_tag!(base_name) do |xml|
206
+ self.class.attributes(:create).each do |name, xml_attribute|
207
+ value = self.send(name)
208
+
209
+ xml.value_tag!(xml_attribute.name, value) if value.present?
210
+ end
211
+ end
212
+ end
213
+
214
+ response = request.execute!
215
+
216
+ self.name = self.class.response_handler.get(response, self.class.xml_attribute(:name))
217
+
218
+ get
219
+ end
220
+
221
+ private
222
+
223
+ def update_attributes(attributes) # :nodoc:
224
+ self.class.attribute_names.each do |name|
225
+ value = attributes[name]
226
+
227
+ if value.present?
228
+ set_attribute(name, value)
229
+ end
230
+ end
231
+ end
232
+
233
+ def set_attribute(name, value) # :nodoc:
234
+ self.send("#{name}=", value)
235
+ end
236
+
237
+ end
238
+
239
+ end
240
+
241
+ end
@@ -0,0 +1,57 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Reactor
3
+ module Cm
4
+ class Language
5
+ def self.get(username = nil)
6
+ begin
7
+ options = {}
8
+ options = {:login => username} if username
9
+ request = XmlRequest.prepare do |xml|
10
+ xml.tag!('userConfig-getTexts', options) do
11
+ xml.tag!('listitem') do
12
+ xml.text!('languages.language')
13
+ end
14
+ end
15
+ end
16
+ response = request.execute!
17
+ response.xpath('//listitem').text
18
+ rescue => e
19
+ return nil
20
+ end
21
+ end
22
+
23
+ # FIXME: broken ([011003] Die Klasse '%s' wird nicht unterstützt.)
24
+ def self.set(*args)
25
+ username = language = nil
26
+ raise ArgumentError.new('set requires one or two parameters') unless [1,2].include? args.length
27
+
28
+ username, language = *args if args.length == 2
29
+ language = *args if args.length == 1
30
+
31
+ raise ArgumentError.new('language cannot be nil') if language.nil?
32
+ options = {}
33
+ options = {:login => username} if username
34
+
35
+ begin
36
+ request = XmlRequest.prepare do |xml|
37
+ xml.tag!('userConfig.setTexts', options) do
38
+ xml.tag!('dictitem') do
39
+ xml.tag!('key') do
40
+ xml.text!('languages.language')
41
+ end
42
+ xml.tag!('value') do
43
+ xml.text!(language)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ response = request.execute!
49
+ response.ok?
50
+ rescue => e
51
+ return false
52
+ end
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,136 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Reactor
3
+ module Cm
4
+ class Link
5
+ attr_reader :link_id, :dest_obj_id, :dest_url
6
+ attr_accessor :title, :target, :position
7
+
8
+ def self.exists?(id)
9
+ return !Link.get(id).nil?
10
+ rescue XmlRequestError => e
11
+ return false
12
+ end
13
+
14
+ def self.get(id)
15
+ link = Link.new
16
+ link.send(:get,id)
17
+ link
18
+ end
19
+
20
+ def self.create_inside(obj, attr, url, title=nil, target=nil)
21
+ create(obj.edited_content, attr, url, title, target)
22
+ end
23
+
24
+ def self.create(content, attr, url, title=nil, target=nil)
25
+ link = Link.new
26
+ link.send(:create, content, attr, url, title, target)
27
+ link
28
+ end
29
+
30
+ def is_external?
31
+ @is_external == true
32
+ end
33
+
34
+ def is_internal?
35
+ !is_external?
36
+ end
37
+
38
+ def dest_obj_id=(obj_id)
39
+ @is_external = false
40
+ @dest_url = Obj.get(obj_id).path
41
+ @dest_obj_id = obj_id
42
+ end
43
+
44
+ def dest_url=(url)
45
+ @is_external = (/^\// =~ url).nil?
46
+ @dest_obj_id = Obj.get(url).obj_id unless @is_external
47
+ @dest_url = url
48
+ end
49
+
50
+ def save!
51
+ request = XmlRequest.prepare do |xml|
52
+ xml.where_key_tag!(base_name, 'id', @link_id)
53
+ xml.set_tag!(base_name) do
54
+ xml.tag!('target', @target) if @target
55
+ xml.tag!('title', @title) if @title
56
+ xml.tag!('destinationUrl', @dest_url) if @dest_url
57
+ xml.tag!('position', @position) if @position
58
+ end
59
+ end
60
+ response = request.execute!
61
+ end
62
+
63
+ def hash
64
+ # yes, to_s.to_is is neccesary,
65
+ # because self.link_id is of type REXML::Text for the most of the time
66
+ self.link_id.to_s.to_i
67
+ end
68
+
69
+
70
+ def eql?(other)
71
+ self.link_id == other.link_id
72
+ end
73
+
74
+ def delete!
75
+ request = XmlRequest.prepare do |xml|
76
+ xml.where_key_tag!(base_name, 'id', @link_id)
77
+ xml.tag!("#{base_name}-delete")
78
+ end
79
+ response = request.execute!
80
+ end
81
+
82
+ protected
83
+ def initialize
84
+ end
85
+
86
+ def base_name
87
+ 'link'
88
+ end
89
+
90
+ def get(id)
91
+ request = XmlRequest.prepare do |xml|
92
+ xml.where_key_tag!(base_name, 'id', id)
93
+ xml.get_key_tag!(base_name, ['id', 'isExternalLink', 'target', 'title', 'destination', 'destinationUrl', 'position'])
94
+ end
95
+ response = request.execute!
96
+
97
+ @link_id = response.xpath('//id/text()')
98
+ @is_external = response.xpath('//isExternalLink/text()') == '1'
99
+ @target = response.xpath('//target/text()').presence
100
+ @title = response.xpath('//title/text()').presence
101
+ @dest_obj_id = response.xpath('//destination/text()').presence
102
+ @dest_url = response.xpath('//destinationUrl/text()').presence
103
+ @position = response.xpath('//position/text()').presence
104
+
105
+ self
106
+ end
107
+
108
+ def create(content, attr, url, title = nil, target = nil)
109
+ request = XmlRequest.prepare do |xml|
110
+ xml.create_tag!(base_name) do
111
+ xml.tag!('attributeName', attr.to_s)
112
+ xml.tag!('sourceContent', content.to_s)
113
+ xml.tag!('destinationUrl', url.to_s)
114
+ end
115
+ end
116
+ response = request.execute!
117
+
118
+ id = response.xpath('//id/text()')
119
+ get(id)
120
+
121
+ if !title.nil? || !target.nil?
122
+ request = XmlRequest.prepare do |xml|
123
+ xml.where_key_tag!(base_name, 'id', id)
124
+ xml.set_tag!(base_name) do
125
+ xml.value_tag!('title', title) if title
126
+ xml.value_tag!('target', target) if target
127
+ end
128
+ end
129
+ response = request.execute!
130
+ end
131
+
132
+ self
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'reactor/cm/group'
3
+
4
+ module Reactor
5
+
6
+ module Cm
7
+
8
+ # The LiveGroup class respects the user management configured in the content manager and
9
+ # handles all live groups. See @Group for further details.
10
+ class LiveGroup < Group
11
+
12
+ protected
13
+
14
+ # Overwritten method from +Group+.
15
+ def base_name
16
+ 'secondaryGroupProxy'
17
+ end
18
+
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,64 @@
1
+ module Reactor
2
+ module Cm
3
+ class LogEntry
4
+ class << self
5
+ def where(conditions = {})
6
+ request = XmlRequest.prepare do |xml|
7
+ where_part(xml, conditions)
8
+ xml.tag!('logEntry-get') do
9
+ xml.tag!('logTime')
10
+ xml.tag!('logText')
11
+ xml.tag!('logType')
12
+ xml.tag!('objectId')
13
+ xml.tag!('receiver')
14
+ xml.tag!('userLogin')
15
+ end
16
+ end
17
+ response = request.execute!
18
+
19
+ result = []
20
+ log_entries = response.xpath('//logEntry')
21
+ log_entries = [log_entries] unless log_entries.kind_of?(Array)
22
+ log_entries.each do |log_entry_node|
23
+ dict = {}
24
+ log_entry_node.each_element do |value_node|
25
+ if value_node.name == 'logTime'
26
+ dict[value_node.name] = value_node.elements['isoDateTime'].text.to_s
27
+ else
28
+ dict[value_node.name] = value_node.text.to_s
29
+ end
30
+ end
31
+
32
+ result << dict
33
+ end
34
+
35
+ return result
36
+ rescue Reactor::Cm::XmlRequestError => e
37
+ if e.message =~ /#{Regexp.escape('[060001] Es wurde kein Eintrag gefunden.')}/
38
+ return []
39
+ else
40
+ raise e
41
+ end
42
+ end
43
+
44
+ def delete(conditions)
45
+ request = XmlRequest.prepare do |xml|
46
+ where_part(xml, conditions)
47
+ xml.tag!('logEntry-delete')
48
+ end
49
+ response = request.execute!
50
+ result = response.xpath('//deleteLogEntriesCount').map {|x| x.text.to_s }.first
51
+ end
52
+
53
+ protected
54
+ def where_part(xml, conditions)
55
+ xml.tag!('logEntry-where') do
56
+ conditions.each do |key, value|
57
+ xml.tag!(key.to_s, value.to_s)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,8 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Reactor
3
+ module Cm
4
+ class MissingCredentials < StandardError
5
+ def initialize ; super("CM access credentials are missing. Check your configuration or supplied credentials.") ; end
6
+ end
7
+ end
8
+ end