activesp 0.0.1 → 0.0.4

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.
@@ -1,38 +1,101 @@
1
+ # Copyright (c) 2010 XAOP bvba
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person
4
+ # obtaining a copy of this software and associated documentation
5
+ # files (the "Software"), to deal in the Software without
6
+ # restriction, including without limitation the rights to use,
7
+ # copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the
9
+ # Software is furnished to do so, subject to the following
10
+ # conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ #
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
+ # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
+ # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
+ #
22
+ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
+ # OTHER DEALINGS IN THE SOFTWARE.
25
+
1
26
  module ActiveSP
2
27
 
3
28
  class Folder < Item
4
29
 
30
+ # See {Base#key}
31
+ # @return [String]
5
32
  def key
6
- encode_key("F", [parent.key, @id])
33
+ encode_key("F", [@list.key, @id])
7
34
  end
8
35
 
9
- def items(options = {})
10
- @list.items(options.merge(:folder => self))
36
+ def is_folder?
37
+ false
11
38
  end
12
39
 
40
+ # Returns the list of items in this folder
41
+ # @param [Hash] options See {List#each_item}, :folder option has no effect
42
+ # @return [Array<Item>]
43
+ def each_item(options = {}, &blk)
44
+ @list.each_item(options.merge(:folder => self), &blk)
45
+ end
46
+ association :items
47
+
48
+ def each_folder(options = {}, &blk)
49
+ @list.each_folder(options.merge(:folder => self), &blk)
50
+ end
51
+ association :folders do
52
+ def create(parameters = {})
53
+ @object.create_folder(parameters)
54
+ end
55
+ end
56
+
57
+ def create_folder(parameters = {})
58
+ @list.create_folder(parameters.merge(:folder => absolute_url))
59
+ end
60
+
61
+ def each_document(options = {}, &blk)
62
+ @list.each_document(options.merge(:folder => self), &blk)
63
+ end
64
+ association :documents do
65
+ def create(parameters = {})
66
+ @object.create_document(parameters)
67
+ end
68
+ end
69
+
70
+ def create_document(parameters = {})
71
+ @list.create_document(parameters.merge(:folder => absolute_url))
72
+ end
73
+
74
+ # Returns the item with the given name
75
+ # @param [String] name
76
+ # @return [Item]
13
77
  def item(name)
14
78
  query = Builder::XmlMarkup.new.Query do |xml|
15
79
  xml.Where do |xml|
16
80
  xml.Eq do |xml|
17
81
  xml.FieldRef(:Name => "FileLeafRef")
18
- xml.Value(name, :Type => "String")
82
+ xml.Value(name, :Type => "Text")
19
83
  end
20
84
  end
21
85
  end
22
86
  items(:query => query).first
23
87
  end
24
88
 
25
- def /(name)
26
- item(name)
27
- end
89
+ alias / item
28
90
 
29
- undef attachments
30
- undef content_urls
91
+ undef content
31
92
 
93
+ # @private
32
94
  def to_s
33
95
  "#<ActiveSP::Folder url=#{url}>"
34
96
  end
35
97
 
98
+ # @private
36
99
  alias inspect to_s
37
100
 
38
101
  end
@@ -1,21 +1,90 @@
1
+ # Copyright (c) 2010 XAOP bvba
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person
4
+ # obtaining a copy of this software and associated documentation
5
+ # files (the "Software"), to deal in the Software without
6
+ # restriction, including without limitation the rights to use,
7
+ # copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the
9
+ # Software is furnished to do so, subject to the following
10
+ # conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ #
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
+ # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
+ # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
+ #
22
+ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
+ # OTHER DEALINGS IN THE SOFTWARE.
25
+
1
26
  module ActiveSP
2
27
 
28
+ # This class represents the field definitions for objects in SharePoint for which the
29
+ # fields cannot be changed and are thus not represented by an object in SharePoint.
30
+ # These include fields of sites, lists, users, grouos, roles, content types and fields.
31
+ # The interface of this class is not as complete as the interface if a Field, mainly
32
+ # because it does not make much sense to do so
3
33
  class GhostField
4
34
 
5
35
  include Util
6
36
 
37
+ # @private
7
38
  attr_reader :Name, :internal_type, :Mult, :ReadOnly
8
39
 
40
+ # @private
9
41
  def initialize(name, type, mult, read_only)
10
42
  @Name, @internal_type, @Mult, @ReadOnly = name, type, mult, read_only
11
43
  end
12
44
 
45
+ # @private
13
46
  def Type
14
47
  translate_internal_type(self)
15
48
  end
16
49
 
50
+ # Returns the attributes of this object as a Hash
51
+ # @return [Hash{String => Integer, Float, String, Time, Boolean, Base}]
17
52
  def attributes
18
- @attributes ||= {
53
+ original_attributes.dup
54
+ end
55
+
56
+ # Returns the value of the attribute of the given name, or nil if this object does not have an attribute by the given name
57
+ # @param [String] name The name of the attribute
58
+ # @return [Integer, Float, String, Time, Boolean, Base]
59
+ def attribute(name)
60
+ current_attributes[name]
61
+ end
62
+
63
+ # Returns whether or not this object has an attribute with the given name
64
+ # @param [String] name The name of the attribute
65
+ # @return [Boolean]
66
+ def has_attribute?(name)
67
+ current_attributes.has_key?(name)
68
+ end
69
+
70
+ # See {Base#method_missing}
71
+ def method_missing(m, *a, &b)
72
+ ms = m.to_s
73
+ if a.length == 0 && has_attribute?(ms)
74
+ attribute(ms)
75
+ else
76
+ super
77
+ end
78
+ end
79
+
80
+ private
81
+
82
+ def current_attributes
83
+ original_attributes
84
+ end
85
+
86
+ def original_attributes
87
+ @original_attributes ||= {
19
88
  "ColName" => @Name,
20
89
  "DisplayName" => @Name,
21
90
  "Mult" => @Mult,
@@ -1,3 +1,28 @@
1
+ # Copyright (c) 2010 XAOP bvba
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person
4
+ # obtaining a copy of this software and associated documentation
5
+ # files (the "Software"), to deal in the Software without
6
+ # restriction, including without limitation the rights to use,
7
+ # copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the
9
+ # Software is furnished to do so, subject to the following
10
+ # conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ #
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
+ # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
+ # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
+ #
22
+ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
+ # OTHER DEALINGS IN THE SOFTWARE.
25
+
1
26
  module ActiveSP
2
27
 
3
28
  class Group < Base
@@ -7,35 +32,49 @@ module ActiveSP
7
32
  include Util
8
33
  include InSite
9
34
 
10
- # attr_reader :name
11
-
12
35
  persistent { |site, name, *a| [site.connection, [:group, name]] }
36
+ # @private
13
37
  def initialize(site, name)
14
38
  @site, @name = site, name
15
39
  end
16
40
 
41
+ # See {Base#key}
42
+ # @return [String]
17
43
  def key
18
44
  encode_key("G", [@name])
19
45
  end
20
46
 
47
+ # Returns the list of users in this group
48
+ # @return [User]
21
49
  def users
22
50
  call("UserGroup", "get_user_collection_from_group", "groupName" => @name).xpath("//spdir:User", NS).map do |row|
23
51
  attributes = clean_attributes(row.attributes)
24
52
  User.new(@site, attributes["LoginName"])
25
53
  end
26
54
  end
27
- cache :users, :dup => true
55
+ cache :users, :dup => :always
56
+
57
+ # Returns false. The same method is present on {Role} where it returns true. Roles and groups can generally be
58
+ # duck-typed, and this method is there for the rare case where you do need to make the distinction
59
+ # @return [Boolean]
60
+ def is_role?
61
+ false
62
+ end
28
63
 
64
+ # See {Base#save}
65
+ # @return [void]
66
+ def save
67
+ p untype_cast_attributes(@site, nil, internal_attribute_types, changed_attributes)
68
+ end
69
+
70
+ # @private
29
71
  def to_s
30
72
  "#<ActiveSP::Group name=#{@name}>"
31
73
  end
32
74
 
75
+ # @private
33
76
  alias inspect to_s
34
77
 
35
- def is_role?
36
- false
37
- end
38
-
39
78
  private
40
79
 
41
80
  def data
data/lib/activesp/item.rb CHANGED
@@ -1,3 +1,28 @@
1
+ # Copyright (c) 2010 XAOP bvba
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person
4
+ # obtaining a copy of this software and associated documentation
5
+ # files (the "Software"), to deal in the Software without
6
+ # restriction, including without limitation the rights to use,
7
+ # copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the
9
+ # Software is furnished to do so, subject to the following
10
+ # conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ #
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
+ # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
+ # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
+ #
22
+ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
+ # OTHER DEALINGS IN THE SOFTWARE.
25
+
1
26
  module ActiveSP
2
27
 
3
28
  class Item < Base
@@ -6,56 +31,151 @@ module ActiveSP
6
31
  extend Caching
7
32
  include Util
8
33
 
34
+ # Returns the list in which the item is located
35
+ # @return [List]
9
36
  attr_reader :list
10
37
 
11
- def initialize(list, id, folder, uid = nil, url = nil, attributes_before_type_cast = nil)
12
- @list, @id, @folder = list, id, folder
38
+ # @private
39
+ def initialize(list, id, folder = :unset, uid = nil, url = nil, attributes_before_type_cast = nil)
40
+ @list, @id = list, id
41
+ @folder = folder if folder != :unset # We have to allow for nil
13
42
  @uid = uid if uid
14
43
  @site = list.site
15
44
  @url = url if url
16
45
  @attributes_before_type_cast = attributes_before_type_cast if attributes_before_type_cast
17
46
  end
18
47
 
48
+ def ID
49
+ @id
50
+ end
51
+
52
+ def is_folder?
53
+ false
54
+ end
55
+
56
+ # Returns the folder, if any, that this item is located in.
57
+ # @return [Folder, nil]
58
+ def folder
59
+ query = Builder::XmlMarkup.new.Query do |xml|
60
+ xml.Where do |xml|
61
+ xml.Eq do |xml|
62
+ xml.FieldRef(:Name => "FileRef")
63
+ xml.Value(::File.dirname(url), :Type => "Text")
64
+ end
65
+ xml.Eq do |xml|
66
+ xml.FieldRef(:Name => "FSObjType")
67
+ xml.Value(1, :Type => "Text")
68
+ end
69
+ end
70
+ end
71
+ @list.items(:folder => :all, :query => query).first
72
+ end
73
+ cache :folder
74
+
75
+ # Returns the parent of this item.
76
+ # @return [Folder, List]
19
77
  def parent
20
- @folder || @list
78
+ folder || @list
21
79
  end
22
80
 
81
+ # @private
23
82
  def id
24
83
  uid
25
84
  end
26
85
 
86
+ # @private
27
87
  def uid
28
88
  attributes["UniqueID"]
29
89
  end
30
90
  cache :uid
31
91
 
92
+ # The URL of this item
93
+ # @return [String]
32
94
  def url
33
- URL(@list.url).join(attributes["ServerUrl"]).to_s
95
+ # URL(@list.url).join(attributes["ServerUrl"]).to_s
96
+ attributes["ServerUrl"]
34
97
  end
35
98
  cache :url
36
99
 
100
+ def absolute_url
101
+ URL(@list.url).join(attributes["ServerUrl"]).to_s
102
+ end
103
+ cache :absolute_url
104
+
105
+ # See {Base#key}
106
+ # @return [String]
37
107
  def key
38
- encode_key("I", [parent.key, @id])
108
+ encode_key("I", [@list.key, @id])
39
109
  end
40
110
 
41
- def attachments
42
- result = call("Lists", "get_attachment_collection", "listName" => @list.id, "listItemID" => @id)
43
- result.xpath("//sp:Attachment", NS).map { |att| att.text }
111
+ # Returns a list of the URLs of the attachments of this item. Note that for items in a document
112
+ # library, this returns an empty list
113
+ # @return [Array<String>]
114
+ def attachment_urls
115
+ @list.when_list do
116
+ result = call("Lists", "get_attachment_collection", "listName" => @list.id, "listItemID" => @id)
117
+ return result.xpath("//sp:Attachment", NS).map { |att| att.text }
118
+ end
119
+ @list.when_document_library { raise TypeError, "a document library does not support attachments" }
120
+ @list.raise_on_unknown_type
44
121
  end
45
- cache :attachments, :dup => true
122
+ cache :attachment_urls, :dup => :always
46
123
 
47
- def content_urls
48
- case @list.attributes["BaseType"]
49
- when "0", "5"
50
- attachments
51
- when "1"
52
- [url]
53
- else
54
- raise "not yet BaseType = #{@list.attributes["BaseType"].inspect}"
124
+ # Yields each attachment as a ActiveSP::File object.
125
+ #
126
+ def each_attachment
127
+ attachment_urls.each { |url| yield ActiveSP::File.new(self, url, true) }
128
+ end
129
+
130
+ def add_attachment(parameters = {})
131
+ @list.when_list do
132
+ parameters = parameters.dup
133
+ content = parameters.delete(:content) or raise ArgumentError, "Specify the content in the :content parameter"
134
+ file_name = parameters.delete(:file_name) or raise ArgumentError, "Specify the file name in the :file_name parameter"
135
+ result = call("Lists", "add_attachment", "listName" => @list.ID, "listItemID" => self.ID, "fileName" => file_name, "attachment" => Base64.encode64(content.to_s))
136
+ add_result = result.xpath("//sp:AddAttachmentResult", NS).first
137
+ if add_result
138
+ clear_cache_for(:attachment_urls)
139
+ return ActiveSP::File.new(self, add_result.text, true)
140
+ else
141
+ raise "cannot add attachment"
142
+ end
143
+ end
144
+ @list.when_document_library { raise TypeError, "a document library does not support attachments" }
145
+ @list.raise_on_unknown_type
146
+ end
147
+
148
+ association :attachments do
149
+ def create(parameters = {})
150
+ @object.add_attachment(parameters)
55
151
  end
56
152
  end
57
- cache :content_urls, :dup => true
58
153
 
154
+ def content
155
+ @list.when_list { raise TypeError, "a list has attachments" }
156
+ @list.when_document_library { return ActiveSP::File.new(self, url, false) }
157
+ @list.raise_on_unknown_type
158
+ end
159
+
160
+ def content=(data)
161
+ @list.when_list { raise TypeError, "a list has attachments" }
162
+ @list.when_document_library { @list.create_document(:overwrite => true, :content => data, "FileLeafRef" => original_attributes["FileLeafRef"]) }
163
+ @list.raise_on_unknown_type
164
+ end
165
+
166
+ # Returns a list of the content URLs for this item. For items in document libraries, this
167
+ # returns the url, for other items this returns the attachments. These URLs can be used
168
+ # to download all contents. See {Connection#fetch}
169
+ # @return [Array<String>]
170
+ def content_urls
171
+ @list.when_list { return attachment_urls }
172
+ @list.when_document_library { return is_folder? ? [] : [url] }
173
+ @list.raise_on_unknown_type
174
+ end
175
+ cache :content_urls, :dup => :always
176
+
177
+ # Returns the content type of this item
178
+ # @return [ContentType]
59
179
  def content_type
60
180
  ContentType.new(@site, @list, attributes["ContentTypeId"])
61
181
  end
@@ -65,15 +185,99 @@ module ActiveSP
65
185
  # call("Versions", "get_versions", "fileName" => attributes["ServerUrl"])
66
186
  # end
67
187
 
188
+ # See {Base#save}
189
+ # @return [self]
190
+ def save
191
+ update_attributes_internal(untype_cast_attributes(@site, nil, internal_attribute_types, changed_attributes))
192
+ self
193
+ end
194
+
195
+ def check_out
196
+ @list.when_list { raise TypeError, "cannot check out list items; they would disappear" }
197
+ @list.raise_on_unknown_type
198
+ result = call("Lists", "check_out_file", "pageUrl" => absolute_url, "checkoutToLocal" => false)
199
+ checkout_result = result.xpath("//sp:CheckOutFileResult", NS).first.text
200
+ if checkout_result == "true"
201
+ self
202
+ else
203
+ raise "cannot check out this item"
204
+ end
205
+ end
206
+
207
+ def check_in(options = {})
208
+ options = options.dup
209
+ type = options.delete(:type) or raise ArgumentError, ":type parameter not specified"
210
+ comment = options.delete(:comment)
211
+ options.empty? or raise ArgumentError, "unsupported options #{options.keys.map { |k| k.inspect }.join(", ")}"
212
+ @list.when_list { raise TypeError, "cannot check in list items because you can't check them out" }
213
+ @list.raise_on_unknown_type
214
+ if checkin_type = { :minor => 0, :major => 1, :overwrite => 2 }[type]
215
+ if type == :minor && !@list.attribute("EnableMinorVersion")
216
+ raise TypeError, "this list does not support minor versions"
217
+ end
218
+ result = call("Lists", "check_in_file", "pageUrl" => absolute_url, "comment" => comment, "CheckinType" => checkin_type)
219
+ checkin_result = result.xpath("//sp:CheckInFileResult", NS).first.text
220
+ if checkin_result == "true"
221
+ self
222
+ else
223
+ raise "cannot check in this item"
224
+ end
225
+ else
226
+ raise ArgumentError, "invalid checkin type #{type.inspect}, valid values are :minor, :major and :overwrite"
227
+ end
228
+ end
229
+
230
+ def cancel_checkout
231
+ @list.when_list { raise TypeError, "cannot undo check-out for list items because you can't check them out" }
232
+ @list.raise_on_unknown_type
233
+ result = call("Lists", "undo_check_out", "pageUrl" => absolute_url)
234
+ cancel_result = result.xpath("//sp:UndoCheckOutResult", NS).first.text
235
+ if cancel_result == "true"
236
+ self
237
+ else
238
+ raise "cannot cancel check-out for this item"
239
+ end
240
+ end
241
+
242
+ def update_attributes(attributes)
243
+ attributes.each do |k, v|
244
+ set_attribute(k, v)
245
+ end
246
+ save
247
+ end
248
+
249
+ def destroy
250
+ updates = Builder::XmlMarkup.new.Batch("OnError" => "Continue", "ListVersion" => 1) do |xml|
251
+ xml.Method("ID" => 1, "Cmd" => "Delete") do
252
+ xml.Field(self.ID, "Name" => "ID")
253
+ end
254
+ end
255
+ result = call("Lists", "update_list_items", "listName" => @list.id, "updates" => updates)
256
+ create_result = result.xpath("//sp:Result", NS).first
257
+ error_code = create_result.xpath("./sp:ErrorCode", NS).first.text.to_i(0)
258
+ if error_code == 0
259
+ @ID = nil
260
+ else
261
+ raise "cannot create item, error code = #{error_code}"
262
+ end
263
+ self
264
+ end
265
+
266
+ # @private
68
267
  def to_s
69
268
  "#<ActiveSP::Item url=#{url}>"
70
269
  end
71
270
 
271
+ # @private
72
272
  alias inspect to_s
73
273
 
274
+ def ==(object)
275
+ ::ActiveSP::List === object && self.ID == object.ID
276
+ end
277
+
74
278
  private
75
279
 
76
- def data
280
+ def raw_attributes
77
281
  query_options = Builder::XmlMarkup.new.QueryOptions do |xml|
78
282
  xml.Folder
79
283
  end
@@ -85,13 +289,14 @@ module ActiveSP
85
289
  end
86
290
  end
87
291
  end
88
- result = call("Lists", "get_list_items", "listName" => @list.id, "viewFields" => "<ViewFields></ViewFields>", "queryOptions" => query_options, "query" => query)
89
- result.xpath("//z:row", NS).first
292
+ @list.__each_item(query_options, "query" => query) do |attributes|
293
+ return attributes
294
+ end
90
295
  end
91
- cache :data
296
+ cache :raw_attributes
92
297
 
93
298
  def attributes_before_type_cast
94
- clean_item_attributes(data.attributes)
299
+ clean_item_attributes(raw_attributes)
95
300
  end
96
301
  cache :attributes_before_type_cast
97
302
 
@@ -104,6 +309,30 @@ module ActiveSP
104
309
  list.fields_by_name
105
310
  end
106
311
 
312
+ def update_attributes_internal(attributes)
313
+ attributes = attributes.dup
314
+ if file_leaf_ref = attributes.delete("FileLeafRef")
315
+ base_name = ::File.basename(file_leaf_ref, ".*")
316
+ end
317
+ updates = Builder::XmlMarkup.new.Batch("OnError" => "Continue", "ListVersion" => 1) do |xml|
318
+ xml.Method("ID" => 1, "Cmd" => "Update") do
319
+ xml.Field(self.ID, "Name" => "ID")
320
+ construct_xml_for_update_list_items(xml, @list.fields_by_name, attributes)
321
+ xml.Field(base_name, "Name" => "BaseName") if base_name
322
+ end
323
+ end
324
+ result = call("Lists", "update_list_items", "listName" => @list.id, "updates" => updates)
325
+ create_result = result.xpath("//sp:Result", NS).first
326
+ error_code = create_result.xpath("./sp:ErrorCode", NS).first.text.to_i(0)
327
+ if error_code == 0
328
+ row = result.xpath("//z:row", NS).first
329
+ @attributes_before_type_cast = clean_item_attributes(row.attributes)
330
+ reload
331
+ else
332
+ raise "cannot create item, error code = #{error_code}"
333
+ end
334
+ end
335
+
107
336
  end
108
337
 
109
338
  end