infopark_reactor 1.10.0.beta → 1.11.0.beta2

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