viewpoint-spws 0.5.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/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/LICENSE +202 -0
- data/README.md +75 -0
- data/Rakefile +7 -0
- data/lib/extensions/string.rb +35 -0
- data/lib/viewpoint/spws.rb +63 -0
- data/lib/viewpoint/spws/connection.rb +84 -0
- data/lib/viewpoint/spws/spws_client.rb +107 -0
- data/lib/viewpoint/spws/types.rb +27 -0
- data/lib/viewpoint/spws/types/document_library.rb +41 -0
- data/lib/viewpoint/spws/types/list.rb +107 -0
- data/lib/viewpoint/spws/types/list_item.rb +248 -0
- data/lib/viewpoint/spws/types/tasks_list.rb +48 -0
- data/lib/viewpoint/spws/types/user.rb +80 -0
- data/lib/viewpoint/spws/version.rb +5 -0
- data/lib/viewpoint/spws/websvc/copy.rb +108 -0
- data/lib/viewpoint/spws/websvc/lists.rb +484 -0
- data/lib/viewpoint/spws/websvc/user_group.rb +96 -0
- data/lib/viewpoint/spws/websvc/web_service_base.rb +65 -0
- data/preamble +17 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/spws_client_spec.rb +43 -0
- data/viewpoint-spws.gemspec +32 -0
- metadata +120 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
=begin
|
2
|
+
This file is part of ViewpointSPWS; the Ruby library for Microsoft Sharepoint Web Services.
|
3
|
+
|
4
|
+
Copyright © 2011 Dan Wanek <dan.wanek@gmail.com>
|
5
|
+
|
6
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
you may not use this file except in compliance with the License.
|
8
|
+
You may obtain a copy of the License at
|
9
|
+
|
10
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
|
12
|
+
Unless required by applicable law or agreed to in writing, software
|
13
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
See the License for the specific language governing permissions and
|
16
|
+
limitations under the License.
|
17
|
+
=end
|
18
|
+
|
19
|
+
# This class represents a Sharepoint List returned from the Lists Web Service with a
|
20
|
+
# ServerTemplate id of 107 (Tasks).
|
21
|
+
# @see http://msdn.microsoft.com/en-us/library/ms774810(v=office.12).aspx
|
22
|
+
class Viewpoint::SPWS::Types::TasksList < Viewpoint::SPWS::Types::List
|
23
|
+
include Viewpoint::SPWS::Types
|
24
|
+
|
25
|
+
# Add a Task to this List
|
26
|
+
# @param [Hash] opts parameters for this Task
|
27
|
+
# @option opts [String] :title The title of this Task
|
28
|
+
# @option opts [DateTime] :due_date The date in which this Task is due
|
29
|
+
# @option opts [Symbol] :priority The priority of the Task
|
30
|
+
# :high, :normal, :low
|
31
|
+
# @option opts [Symbol] :status The status of the Task
|
32
|
+
# :not_started, :in_progress, :completed, :deferred, :waiting
|
33
|
+
# @option opts [Fixnum] :percent_complete The percentage of completion.
|
34
|
+
# Must be a number from 0 to 100.
|
35
|
+
# @return [Viewpoint::SPWS::Types::ListItem] The newly added Task
|
36
|
+
def add_item!(opts)
|
37
|
+
raise "Title argument required" unless opts[:title]
|
38
|
+
topts = opts.clone
|
39
|
+
topts[:priority] = :normal unless topts[:priority]
|
40
|
+
topts[:status] = :not_started unless topts[:status]
|
41
|
+
if(topts[:percent_complete] && !(0..100).include?(topts[:percent_complete]))
|
42
|
+
raise "Invalid :percent_complete #{topts[:percent_complete]}"
|
43
|
+
end
|
44
|
+
|
45
|
+
super(topts)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
=begin
|
2
|
+
This file is part of ViewpointSPWS; the Ruby library for Microsoft Sharepoint Web Services.
|
3
|
+
|
4
|
+
Copyright © 2011 Dan Wanek <dan.wanek@gmail.com>
|
5
|
+
|
6
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
you may not use this file except in compliance with the License.
|
8
|
+
You may obtain a copy of the License at
|
9
|
+
|
10
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
|
12
|
+
Unless required by applicable law or agreed to in writing, software
|
13
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
See the License for the specific language governing permissions and
|
16
|
+
limitations under the License.
|
17
|
+
=end
|
18
|
+
|
19
|
+
# This class represents a Sharepoint User Item returned from the UserGroup Web Service
|
20
|
+
class Viewpoint::SPWS::Types::User
|
21
|
+
include Viewpoint::SPWS::Types
|
22
|
+
|
23
|
+
attr_reader :id, :sid, :name, :login_name, :email, :notes, :flags, :site_user
|
24
|
+
|
25
|
+
# @param [Viewpoint::SPWS::Websvc::UserGroup] ws The webservice instance this user spawned from
|
26
|
+
# @param [Nokogiri::XML::Element] xml the List element we are building from
|
27
|
+
def initialize(ws, xml)
|
28
|
+
@ws = ws
|
29
|
+
parse_xml_fields(xml)
|
30
|
+
end
|
31
|
+
|
32
|
+
def is_site_admin?
|
33
|
+
@is_site_admin
|
34
|
+
end
|
35
|
+
|
36
|
+
def is_domain_group?
|
37
|
+
@is_domain_group
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# Parse the fields out of the passed XML document.
|
43
|
+
# @param[Nokogiri::XML::Element] xml
|
44
|
+
def parse_xml_fields(xml)
|
45
|
+
@xmldoc = xml
|
46
|
+
set_field :@id, 'ID'
|
47
|
+
set_field :@sid, 'Sid'
|
48
|
+
set_field :@name, 'Name'
|
49
|
+
set_field :@login_name, 'LoginName'
|
50
|
+
set_field :@email, 'Email'
|
51
|
+
set_field :@notes, 'Notes'
|
52
|
+
set_field :@is_site_admin, 'IsSiteAdmin', 'Boolean'
|
53
|
+
set_field :@is_domain_group, 'IsDomainGroup', 'Boolean'
|
54
|
+
set_field :@flags, 'Flags'
|
55
|
+
set_field :@site_user, 'SiteUser'
|
56
|
+
@xmldoc = nil
|
57
|
+
end
|
58
|
+
|
59
|
+
# Parse a Sharepoint managed field
|
60
|
+
# @param [Symbol] vname The instance variable we will set the value to if it exists
|
61
|
+
# @param [String] fname The field name to check for
|
62
|
+
def set_mfield(vname, fname)
|
63
|
+
instance_variable_set vname, @xmldoc[fname].split(';#').last if @xmldoc[fname]
|
64
|
+
end
|
65
|
+
|
66
|
+
# @param [Symbol] vname The instance variable we will set the value to if it exists
|
67
|
+
# @param [String] fname The field name to check for
|
68
|
+
# @param [String] type ('String') optional type for additional processing
|
69
|
+
def set_field(vname, fname, type = 'String')
|
70
|
+
case type
|
71
|
+
when 'Boolean'
|
72
|
+
val = (@xmldoc[fname] =~ /True/i) ? true : false
|
73
|
+
instance_variable_set vname, val
|
74
|
+
else
|
75
|
+
instance_variable_set vname, @xmldoc[fname] if @xmldoc[fname]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
@@ -0,0 +1,108 @@
|
|
1
|
+
=begin
|
2
|
+
This file is part of ViewpointSPWS; the Ruby library for Microsoft Sharepoint Web Services.
|
3
|
+
|
4
|
+
Copyright © 2011 Dan Wanek <dan.wanek@gmail.com>
|
5
|
+
|
6
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
you may not use this file except in compliance with the License.
|
8
|
+
You may obtain a copy of the License at
|
9
|
+
|
10
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
|
12
|
+
Unless required by applicable law or agreed to in writing, software
|
13
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
See the License for the specific language governing permissions and
|
16
|
+
limitations under the License.
|
17
|
+
=end
|
18
|
+
|
19
|
+
# This class represents the Sharepoint Copy Web Service.
|
20
|
+
# @see http://msdn.microsoft.com/en-us/library/copy(v=office.12).aspx
|
21
|
+
class Viewpoint::SPWS::Websvc::Copy
|
22
|
+
include Viewpoint::SPWS::Websvc::WebServiceBase
|
23
|
+
|
24
|
+
def initialize(spcon)
|
25
|
+
@default_ns = 'http://schemas.microsoft.com/sharepoint/soap/'
|
26
|
+
@ws_endpoint = '_vti_bin/Copy.asmx'
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
30
|
+
# Copies a document represented by a Byte array to one or more locations on a server.
|
31
|
+
# @see http://msdn.microsoft.com/en-us/library/copy.copy.copyintoitems(v=office.12).aspx
|
32
|
+
# @param [String] srcfile Either a relative or absolute path to the input file
|
33
|
+
# @param [Array<String>] tgturls An array of absolute URLs to copy the source to.
|
34
|
+
# @todo parse the return and check for errors
|
35
|
+
def copy_into_items(srcfile, tgturls)
|
36
|
+
soapmsg = build_soap_envelope do |type, builder|
|
37
|
+
if(type == :header)
|
38
|
+
else
|
39
|
+
builder.CopyIntoItems {
|
40
|
+
builder.parent.default_namespace = @default_ns
|
41
|
+
builder.SourceUrl(srcfile)
|
42
|
+
builder.DestinationUrls {
|
43
|
+
tgturls.each {|tgt| builder.string(tgt) }
|
44
|
+
}
|
45
|
+
builder.Fields
|
46
|
+
builder.Stream(Base64.encode64(File.read(srcfile)))
|
47
|
+
}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
soaprsp = Nokogiri::XML(send_soap_request(soapmsg.doc.to_xml))
|
52
|
+
end
|
53
|
+
|
54
|
+
# Copies a document from one location on a server running Windows SharePoint Services
|
55
|
+
# to another location on the same server.
|
56
|
+
# @see http://msdn.microsoft.com/en-us/library/copy.copy.copyintoitemslocal(v=office.12).aspx
|
57
|
+
# @param [String] srcurl An absolute URL to the document you want to copy from.
|
58
|
+
# @param [Array<String>] tgturls An array of absolute URLs to copy the source to.
|
59
|
+
# @todo parse the return and check for errors
|
60
|
+
def copy_into_items_local(srcurl, tgturls)
|
61
|
+
soapmsg = build_soap_envelope do |type, builder|
|
62
|
+
if(type == :header)
|
63
|
+
else
|
64
|
+
builder.CopyIntoItemsLocal {
|
65
|
+
builder.parent.default_namespace = @default_ns
|
66
|
+
builder.SourceUrl(srcurl)
|
67
|
+
builder.DestinationUrls {
|
68
|
+
tgturls.each {|tgt| builder.string(tgt) }
|
69
|
+
}
|
70
|
+
}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
soaprsp = Nokogiri::XML(send_soap_request(soapmsg.doc.to_xml))
|
75
|
+
end
|
76
|
+
|
77
|
+
# Generates a Byte array representation of a document
|
78
|
+
# @see http://msdn.microsoft.com/en-us/library/copy.copy.getitem(v=office.12).aspx
|
79
|
+
# @param [String] tgturl An absolute URL to the document you want to retrieve the
|
80
|
+
# byte stream for.
|
81
|
+
# @return [Hash] it returns a Hash with the keys :stream that has the Base64 encoded
|
82
|
+
# file data and a key :fields which is an Array of Hash data that contains document
|
83
|
+
# metadata.
|
84
|
+
def get_item(tgturl)
|
85
|
+
soapmsg = build_soap_envelope do |type, builder|
|
86
|
+
if(type == :header)
|
87
|
+
else
|
88
|
+
builder.GetItem {
|
89
|
+
builder.parent.default_namespace = @default_ns
|
90
|
+
builder.Url(tgturl)
|
91
|
+
}
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
soaprsp = Nokogiri::XML(send_soap_request(soapmsg.doc.to_xml))
|
96
|
+
ns = {"xmlns"=> @default_ns}
|
97
|
+
data = {}
|
98
|
+
data[:stream] = soaprsp.xpath('//xmlns:GetItemResponse/xmlns:Stream',ns).first.content
|
99
|
+
fields = []
|
100
|
+
soaprsp.xpath('//xmlns:GetItemResponse/xmlns:Fields/xmlns:FieldInformation',ns).each do |f|
|
101
|
+
fields << {:type => f['Type'], :display_name => f['DisplayName'],
|
102
|
+
:id => f['Id'], :value => f['Value']}
|
103
|
+
end
|
104
|
+
data[:fields] = fields
|
105
|
+
data
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
@@ -0,0 +1,484 @@
|
|
1
|
+
=begin
|
2
|
+
This file is part of ViewpointSPWS; the Ruby library for Microsoft Sharepoint Web Services.
|
3
|
+
|
4
|
+
Copyright © 2011 Dan Wanek <dan.wanek@gmail.com>
|
5
|
+
|
6
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
you may not use this file except in compliance with the License.
|
8
|
+
You may obtain a copy of the License at
|
9
|
+
|
10
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
|
12
|
+
Unless required by applicable law or agreed to in writing, software
|
13
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
See the License for the specific language governing permissions and
|
16
|
+
limitations under the License.
|
17
|
+
=end
|
18
|
+
|
19
|
+
# This class represents the Sharepoint Lists Web Service.
|
20
|
+
# @see http://msdn.microsoft.com/en-us/library/ms774654(v=office.12).aspx
|
21
|
+
class Viewpoint::SPWS::Websvc::Lists
|
22
|
+
include Viewpoint::SPWS::Websvc::WebServiceBase
|
23
|
+
|
24
|
+
def initialize(spcon)
|
25
|
+
@default_ns = 'http://schemas.microsoft.com/sharepoint/soap/'
|
26
|
+
@ws_endpoint = '_vti_bin/Lists.asmx'
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
30
|
+
# Add a List to this site.
|
31
|
+
# @see http://msdn.microsoft.com/en-us/library/lists.lists.addlist(v=office.12).aspx
|
32
|
+
# @param [String] name A name for the List
|
33
|
+
# @param [String] desc A description of the List
|
34
|
+
# @param [Integer] templ_id The template type for this List. See the Microsoft docs for
|
35
|
+
# additional information.
|
36
|
+
# @return [Viewpoint::SPWS::List] The new List object
|
37
|
+
def add_list(name, desc, templ_id)
|
38
|
+
soapmsg = build_soap_envelope do |type, builder|
|
39
|
+
if(type == :header)
|
40
|
+
else
|
41
|
+
builder.AddList {
|
42
|
+
builder.parent.default_namespace = @default_ns
|
43
|
+
builder.listName(name)
|
44
|
+
builder.description(desc)
|
45
|
+
builder.templateID(templ_id)
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
soaprsp = Nokogiri::XML(send_soap_request(soapmsg.doc.to_xml))
|
50
|
+
return soaprsp
|
51
|
+
ns = {"xmlns"=> @default_ns}
|
52
|
+
new_list(soaprsp.xpath('//xmlns:AddListResult/xmlns:List', ns).first)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Add a List to this site from a feature ID.
|
56
|
+
# @see http://msdn.microsoft.com/en-us/library/lists.lists.addlistfromfeature(v=office.12).aspx
|
57
|
+
# @param [String] name A name for the List
|
58
|
+
# @param [String] desc A description of the List
|
59
|
+
# @param [String] feature_id The GUID of the feature ID.
|
60
|
+
# @param [Integer] templ_id The template type for this List. See the Microsoft docs for
|
61
|
+
# additional information.
|
62
|
+
# @return [Viewpoint::SPWS::List] The new List object
|
63
|
+
def add_list_from_feature(name, desc, feature_id, templ_id)
|
64
|
+
soapmsg = build_soap_envelope do |type, builder|
|
65
|
+
if(type == :header)
|
66
|
+
else
|
67
|
+
builder.AddListFromFeature {
|
68
|
+
builder.parent.default_namespace = @default_ns
|
69
|
+
builder.listName(name)
|
70
|
+
builder.description(desc)
|
71
|
+
builder.featureID(feature_id)
|
72
|
+
builder.templateID(templ_id)
|
73
|
+
}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
soaprsp = Nokogiri::XML(send_soap_request(soapmsg.doc.to_xml))
|
77
|
+
ns = {"xmlns"=> @default_ns}
|
78
|
+
new_list(soaprsp.xpath('//xmlns:AddListResult/xmlns:List', ns).first)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Delete a list from this site.
|
82
|
+
# @param [String] name Either the name or the GUID of the list
|
83
|
+
# @todo Work out the return value
|
84
|
+
def delete_list(name)
|
85
|
+
soapmsg = build_soap_envelope do |type, builder|
|
86
|
+
if(type == :header)
|
87
|
+
else
|
88
|
+
builder.DeleteList {
|
89
|
+
builder.parent.default_namespace = @default_ns
|
90
|
+
builder.listName(name)
|
91
|
+
}
|
92
|
+
end
|
93
|
+
end
|
94
|
+
soaprsp = Nokogiri::XML(send_soap_request(soapmsg.doc.to_xml))
|
95
|
+
#ns = {"xmlns"=> @default_ns}
|
96
|
+
end
|
97
|
+
|
98
|
+
# Returns a collection of content type definition schemas
|
99
|
+
# @see http://msdn.microsoft.com/en-us/library/lists.lists.getlistcontenttypes(v=office.12).aspx
|
100
|
+
# @param [String] name Either the name or the GUID of the list
|
101
|
+
# @param [String] content_type_id (nil) The content type ID. I'm still not clear on what specifying
|
102
|
+
# this value does. In my limitted testing it does not seem to have an effect on the output.
|
103
|
+
# @todo Work out the return value
|
104
|
+
def get_list_content_types(name, content_type_id = nil)
|
105
|
+
soapmsg = build_soap_envelope do |type, builder|
|
106
|
+
if(type == :header)
|
107
|
+
else
|
108
|
+
builder.GetListContentTypes {
|
109
|
+
builder.parent.default_namespace = @default_ns
|
110
|
+
builder.listName(name)
|
111
|
+
builder.contentTypeId(content_type_id)
|
112
|
+
}
|
113
|
+
end
|
114
|
+
end
|
115
|
+
soaprsp = Nokogiri::XML(send_soap_request(soapmsg.doc.to_xml))
|
116
|
+
end
|
117
|
+
|
118
|
+
# Returns all the lists for a Sharepoint site.
|
119
|
+
# @param [Boolean] show_hidden Whether or not to show hidden lists. Default = false
|
120
|
+
# @see http://msdn.microsoft.com/en-us/library/lists.lists.getlistcollection(v=office.12).aspx
|
121
|
+
def get_list_collection(show_hidden = false)
|
122
|
+
soapmsg = build_soap_envelope do |type, builder|
|
123
|
+
if(type == :header)
|
124
|
+
else
|
125
|
+
builder.GetListCollection {
|
126
|
+
builder.parent.default_namespace = @default_ns
|
127
|
+
}
|
128
|
+
end
|
129
|
+
end
|
130
|
+
soaprsp = Nokogiri::XML(send_soap_request(soapmsg.doc.to_xml))
|
131
|
+
ns = {"xmlns"=> @default_ns}
|
132
|
+
lists = []
|
133
|
+
soaprsp.xpath('//xmlns:Lists/xmlns:List', ns).each do |l|
|
134
|
+
lists << new_list(l)
|
135
|
+
end
|
136
|
+
if(!show_hidden)
|
137
|
+
lists.reject! do |i|
|
138
|
+
i.hidden?
|
139
|
+
end
|
140
|
+
end
|
141
|
+
lists
|
142
|
+
end
|
143
|
+
|
144
|
+
# Retrieve a specific Sharepoint List
|
145
|
+
# @see http://msdn.microsoft.com/en-us/library/lists.lists.getlist(v=office.12).aspx
|
146
|
+
# @param [String] list title or the GUID for the list
|
147
|
+
# @return [Viewpoint::SPWS::List]
|
148
|
+
def get_list(list)
|
149
|
+
soapmsg = build_soap_envelope do |type, builder|
|
150
|
+
if(type == :header)
|
151
|
+
else
|
152
|
+
builder.GetList {
|
153
|
+
builder.parent.default_namespace = @default_ns
|
154
|
+
builder.listName(list)
|
155
|
+
}
|
156
|
+
end
|
157
|
+
end
|
158
|
+
soaprsp = Nokogiri::XML(send_soap_request(soapmsg.doc.to_xml))
|
159
|
+
ns = {"xmlns"=> @default_ns}
|
160
|
+
new_list(soaprsp.xpath('//xmlns:GetListResult/xmlns:List', ns).first)
|
161
|
+
end
|
162
|
+
|
163
|
+
# Get List Items based on certain parameters
|
164
|
+
# @see http://msdn.microsoft.com/en-us/library/lists.lists.getlistitems(v=office.12).aspx
|
165
|
+
# @param [String] list title or the GUID for the list
|
166
|
+
# @param [Hash] opts
|
167
|
+
# @option opts [String] :view_name ('') GUID for the view surrounded by curly braces
|
168
|
+
# If nothing is passed it used the default of the View
|
169
|
+
# @option opts [String] :row_limit ('') A String representing the number of rows to return.
|
170
|
+
# @option opts [Boolean] :recursive (true) If true look in subfolders as well as root
|
171
|
+
# @option opts [Boolean] :date_in_utc (true) If true return dates in UTC
|
172
|
+
# @option opts [String] :folder ('')
|
173
|
+
# Filter document library items for items in the specified folder
|
174
|
+
# @yield [builder] Yields a Builder object that can be used to build a CAML Query. See the
|
175
|
+
# example on how to use it.
|
176
|
+
# @yieldparam [Nokogiro::XML::Builder] builder The builder object used to create the Query
|
177
|
+
# @option opts [Array<String,Symbol>] :view_fields and array of String or Symbols that
|
178
|
+
# represent which fields to return with the query.
|
179
|
+
# @example The following example shows how to prepare a CAML Query with a block. It filters for all objects of ObjectType '0' = Files
|
180
|
+
# items = listws.get_list_items('Shared Documents',:recursive => true) do |b|
|
181
|
+
# b.Query {
|
182
|
+
# b.Where {
|
183
|
+
# b.Eq {
|
184
|
+
# b.FieldRef(:Name => 'FSObjType')
|
185
|
+
# b.Value(0, :Type => 'Integer')
|
186
|
+
# }
|
187
|
+
# }
|
188
|
+
# }
|
189
|
+
# end
|
190
|
+
def get_list_items(list, opts = {})
|
191
|
+
# Set Default values
|
192
|
+
opts[:recursive] = true unless opts.has_key?(:recursive)
|
193
|
+
opts[:view_name] = '' unless opts.has_key?(:view_name)
|
194
|
+
opts[:row_limit] = '' unless opts.has_key?(:row_limit)
|
195
|
+
opts[:date_in_utc] = true unless opts.has_key?(:date_in_utc)
|
196
|
+
opts[:folder] = '' unless opts.has_key?(:folder)
|
197
|
+
|
198
|
+
soapmsg = build_soap_envelope do |type, builder|
|
199
|
+
if(type == :header)
|
200
|
+
else
|
201
|
+
builder.GetListItems {
|
202
|
+
builder.parent.default_namespace = @default_ns
|
203
|
+
builder.listName(list)
|
204
|
+
builder.viewName(opts[:view_name])
|
205
|
+
builder.rowLimit(opts[:row_limit])
|
206
|
+
|
207
|
+
if block_given?
|
208
|
+
builder.query {
|
209
|
+
builder.parent.default_namespace = ''
|
210
|
+
yield builder
|
211
|
+
}
|
212
|
+
end
|
213
|
+
|
214
|
+
if(opts[:view_fields])
|
215
|
+
builder.viewFields {
|
216
|
+
builder.ViewFields {
|
217
|
+
builder.parent.default_namespace = ''
|
218
|
+
opts[:view_fields].each do |f|
|
219
|
+
builder.FieldRef(:Name => f.to_s.camel_case)
|
220
|
+
end
|
221
|
+
}
|
222
|
+
}
|
223
|
+
end
|
224
|
+
|
225
|
+
builder.queryOptions {
|
226
|
+
builder.QueryOptions {
|
227
|
+
builder.parent.default_namespace = ''
|
228
|
+
builder.Folder(opts[:folder])
|
229
|
+
builder.ViewAttributes(:Scope => 'Recursive') if opts[:recursive]
|
230
|
+
builder.DateInUtc('True') if opts[:date_in_utc]
|
231
|
+
builder.IncludeAttachmentUrls('True')
|
232
|
+
}
|
233
|
+
}
|
234
|
+
# @todo Is this worth supporting???
|
235
|
+
#builder.webID(parms[:web_id])
|
236
|
+
}
|
237
|
+
end
|
238
|
+
end
|
239
|
+
soaprsp = Nokogiri::XML(send_soap_request(soapmsg.doc.to_xml))
|
240
|
+
ns = {'xmlns:z' => "#RowsetSchema"}
|
241
|
+
items = []
|
242
|
+
soaprsp.xpath('//z:row', ns).each do |li|
|
243
|
+
items << Types::ListItem.new(self, list, li)
|
244
|
+
end
|
245
|
+
items
|
246
|
+
end
|
247
|
+
|
248
|
+
# Get List Items changes from a given change token
|
249
|
+
# @see http://msdn.microsoft.com/en-us/library/lists.lists.getlistitemchangessincetoken(v=office.12).aspx
|
250
|
+
# @param [String] list title or the GUID for the list
|
251
|
+
# @param [String] token (nil) The change token or nil to get all
|
252
|
+
# @param [Hash] opts
|
253
|
+
# @option opts [String] :view_name ('') GUID for the view surrounded by curly braces
|
254
|
+
# If nothing is passed it used the default of the View
|
255
|
+
# @option opts [String] :row_limit ('') A String representing the number of rows to return.
|
256
|
+
# @option opts [Boolean] :recursive (true) If true look in subfolders as well as root
|
257
|
+
# @option opts [Boolean] :date_in_utc (true) If true return dates in UTC
|
258
|
+
# @option opts [String] :folder ('')
|
259
|
+
# Filter document library items for items in the specified folder
|
260
|
+
# @yield [builder] Yields a Builder object that can be used to build a CAML Query. See the
|
261
|
+
# example on how to use it.
|
262
|
+
# @yieldparam [Nokogiro::XML::Builder] builder The builder object used to create the Query
|
263
|
+
# @example The following example shows how to prepare a CAML Query with a block. It filters for all objects of ObjectType '0' = Files
|
264
|
+
# items = listws.get_list_items('Shared Documents',:recursive => true) do |b|
|
265
|
+
# b.Query {
|
266
|
+
# b.Where {
|
267
|
+
# b.Eq {
|
268
|
+
# b.FieldRef(:Name => 'FSObjType')
|
269
|
+
# b.Value(0, :Type => 'Integer')
|
270
|
+
# }
|
271
|
+
# }
|
272
|
+
# }
|
273
|
+
# end
|
274
|
+
# @return [Hash] returns a Hash with the keys :last_change_token, which contains a String
|
275
|
+
# that holds a change token that may be used in subsequent calls, and :items which holds
|
276
|
+
# an Array of ListItem objects.
|
277
|
+
def get_list_item_changes_since_token(list, token=nil, opts = {})
|
278
|
+
# Set Default values
|
279
|
+
opts[:recursive] = true unless opts.has_key?(:recursive)
|
280
|
+
opts[:view_name] = '' unless opts.has_key?(:view_name)
|
281
|
+
opts[:row_limit] = '' unless opts.has_key?(:row_limit)
|
282
|
+
opts[:date_in_utc] = true unless opts.has_key?(:date_in_utc)
|
283
|
+
opts[:folder] = '' unless opts.has_key?(:folder)
|
284
|
+
|
285
|
+
soapmsg = build_soap_envelope do |type, builder|
|
286
|
+
if(type == :header)
|
287
|
+
else
|
288
|
+
builder.GetListItemChangesSinceToken {
|
289
|
+
builder.parent.default_namespace = @default_ns
|
290
|
+
builder.listName(list)
|
291
|
+
builder.viewName(opts[:view_name])
|
292
|
+
builder.rowLimit(opts[:row_limit])
|
293
|
+
|
294
|
+
if block_given?
|
295
|
+
builder.query {
|
296
|
+
builder.parent.default_namespace = ''
|
297
|
+
yield builder
|
298
|
+
}
|
299
|
+
end
|
300
|
+
|
301
|
+
builder.queryOptions {
|
302
|
+
builder.QueryOptions {
|
303
|
+
builder.parent.default_namespace = ''
|
304
|
+
builder.Folder(opts[:folder])
|
305
|
+
builder.ViewAttributes(:Scope => 'Recursive') if opts[:recursive]
|
306
|
+
builder.DateInUtc('True') if opts[:date_in_utc]
|
307
|
+
builder.IncludeAttachmentUrls('True')
|
308
|
+
}
|
309
|
+
}
|
310
|
+
|
311
|
+
builder.changeToken(token)
|
312
|
+
# @todo Is this worth supporting???
|
313
|
+
#builder.contains()
|
314
|
+
}
|
315
|
+
end
|
316
|
+
end
|
317
|
+
soaprsp = Nokogiri::XML(send_soap_request(soapmsg.doc.to_xml))
|
318
|
+
ns = {'xmlns:z' => "#RowsetSchema",
|
319
|
+
'xmlns:rs' => "urn:schemas-microsoft-com:rowset",
|
320
|
+
'xmlns' => @default_ns,
|
321
|
+
}
|
322
|
+
items = []
|
323
|
+
soaprsp.xpath('//rs:data/z:row', ns).each do |li|
|
324
|
+
items << Types::ListItem.new(self, list, li)
|
325
|
+
end
|
326
|
+
changes = soaprsp.xpath('//xmlns:GetListItemChangesSinceTokenResult/xmlns:listitems/xmlns:Changes',ns).first
|
327
|
+
{:last_change_token => changes['LastChangeToken'], :items => items}
|
328
|
+
end
|
329
|
+
|
330
|
+
# Adds, deletes, or updates the specified items in a list
|
331
|
+
# @see http://msdn.microsoft.com/en-us/library/lists.lists.updatelistitems(v=office.12).aspx
|
332
|
+
# @see BATCH Operation http://msdn.microsoft.com/en-us/library/ms437562(v=office.12).aspx
|
333
|
+
# @param [String] list title or the GUID for the list
|
334
|
+
# @param [Hash] updates
|
335
|
+
# @option updates [String] :view_name ('') GUID for the view without curly braces
|
336
|
+
# If nothing is passed it used the default of the View
|
337
|
+
# @option updates [String] :on_error ('Continue') What to do if an error ocurrs. It must
|
338
|
+
# be either 'Return' or 'Contiue'
|
339
|
+
# @option updates [String] :list_version ('') The version of the list we wish to modify
|
340
|
+
# @option updates [String] :version ('') The version of Sharepoint we are acting on
|
341
|
+
# @option updates [Array<Hash>] :item_updates An array of Hashes that specify what to update.
|
342
|
+
# Each hash needs an :id key to specify the item ID and a :command key that specifies
|
343
|
+
# "New", "Update" or "Delete". All other keys are field names in either CamelCase or
|
344
|
+
# ruby_case with values to set them to.
|
345
|
+
# {:item_updates =>
|
346
|
+
# [{:id => 95, :command => 'Update', :status => 'Completed'},
|
347
|
+
# {:id => 107, :command => 'Update', :title => "Test"}]}
|
348
|
+
# @yield [builder] Yields a Builder object that can be used to build a Batch request. See the
|
349
|
+
# example on how to use it. For more information on Batch requests:
|
350
|
+
# @see http://msdn.microsoft.com/en-us/library/dd585784(v=office.11).aspx
|
351
|
+
# @yieldparam [Nokogiro::XML::Builder] builder The builder object used to create the Batch
|
352
|
+
# @example The following example shows how to prepare a Batch request with a block. It updates a Task item to Status 'Completed'.
|
353
|
+
# item_id = 95
|
354
|
+
# listws.update_list_items('Task List') do |b|
|
355
|
+
# b.Method(:ID => 1, :Cmd => 'Update') do
|
356
|
+
# b.Field(item_id,:Name => 'ID')
|
357
|
+
# b.Field("Completed", :Name => 'Status')
|
358
|
+
# end
|
359
|
+
# end
|
360
|
+
# @example How to Add and Delete via passed parameters
|
361
|
+
# updates = [
|
362
|
+
# {:id => "New", :command => "New", :title => "Test Task"},
|
363
|
+
# {:id => 'New',:command => 'New', :title => 'Test Task 2'},
|
364
|
+
# {:id => 98,:command => 'Delete'},
|
365
|
+
# ]
|
366
|
+
# resp = listws.update_list_items('Task List',:item_updates => updates)
|
367
|
+
def update_list_items(list, updates = {})
|
368
|
+
# Set Default values
|
369
|
+
updates[:view_name] = '' unless updates.has_key?(:view_name)
|
370
|
+
updates[:on_error] = 'Continue' unless updates.has_key?(:on_error)
|
371
|
+
updates[:list_version] = '' unless updates.has_key?(:list_version)
|
372
|
+
updates[:version] = '' unless updates.has_key?(:version)
|
373
|
+
|
374
|
+
soapmsg = build_soap_envelope do |type, builder|
|
375
|
+
if(type == :header)
|
376
|
+
else
|
377
|
+
builder.UpdateListItems {
|
378
|
+
builder.parent.default_namespace = @default_ns
|
379
|
+
builder.listName(list)
|
380
|
+
|
381
|
+
builder.updates {
|
382
|
+
builder.Batch(:ViewName => updates[:view_name],
|
383
|
+
:OnError => updates[:on_error],
|
384
|
+
:ListVersion => updates[:list_version],
|
385
|
+
:Version => updates[:version]) {
|
386
|
+
builder.parent.default_namespace = ''
|
387
|
+
|
388
|
+
# First format passed item_updates
|
389
|
+
updates[:item_updates] && updates[:item_updates].each_with_index do |iu,idx|
|
390
|
+
iu = iu.clone
|
391
|
+
builder.Method(:ID => "VP_IDX#{idx}", :Cmd => iu.delete(:command)) do
|
392
|
+
builder.Field(iu.delete(:id), :Name => 'ID')
|
393
|
+
iu.each_pair do |k,v|
|
394
|
+
builder.Field(v, :Name => k.to_s.camel_case)
|
395
|
+
end
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
# Now include block-passed updates
|
400
|
+
if block_given?
|
401
|
+
yield builder
|
402
|
+
end
|
403
|
+
}
|
404
|
+
}
|
405
|
+
}
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
soaprsp = Nokogiri::XML(send_soap_request(soapmsg.doc.to_xml))
|
410
|
+
parse_update_list_items(list, soaprsp)
|
411
|
+
end
|
412
|
+
|
413
|
+
|
414
|
+
# ------------------------- Helper Methods ------------------------- #
|
415
|
+
|
416
|
+
# Retrieve a file from Sharepoint. This is not a standard Web Service method, buth
|
417
|
+
# rather a convenience method that is part of ViewpointSPWS.
|
418
|
+
# @param [String] file_ref The fileref property from a ListItem object
|
419
|
+
# @return [String] A String representing the bytestream of a file. You should be able
|
420
|
+
# to write it out to a file with something like this:
|
421
|
+
# @example
|
422
|
+
# resp = listws.get_file(listitem.file_ref)
|
423
|
+
# File.open(listitem.file_name,'w+') do |f|
|
424
|
+
# f.write(resp)
|
425
|
+
# end
|
426
|
+
def get_file(file_ref)
|
427
|
+
p1 = Pathname.new @spcon.site_base.request_uri
|
428
|
+
p2 = Pathname.new "/#{file_ref}"
|
429
|
+
target = p2.relative_path_from p1
|
430
|
+
@spcon.get(target.to_s)
|
431
|
+
end
|
432
|
+
|
433
|
+
|
434
|
+
private
|
435
|
+
|
436
|
+
# Parse the SOAP Response and return an appropriate List type
|
437
|
+
def new_list(xmllist)
|
438
|
+
case xmllist['ServerTemplate']
|
439
|
+
when "101"
|
440
|
+
Types::DocumentLibrary.new(self, xmllist)
|
441
|
+
when "107"
|
442
|
+
Types::TasksList.new(self, xmllist)
|
443
|
+
else
|
444
|
+
Types::List.new(self, xmllist)
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
def parse_update_list_items(list, soaprsp)
|
449
|
+
updates = {}
|
450
|
+
ns = {'xmlns' => @default_ns, 'xmlns:z' => '#RowsetSchema'}
|
451
|
+
soaprsp.xpath('//xmlns:Results/xmlns:Result',ns).each do |rs|
|
452
|
+
estat = check_update_error(rs.xpath('./xmlns:ErrorCode',ns).first.text)
|
453
|
+
id, status = rs['ID'].split(/,/)
|
454
|
+
case status
|
455
|
+
when 'New'
|
456
|
+
updates[:new] = [] unless updates.has_key?(:new)
|
457
|
+
li = rs.xpath('./z:row',ns).first
|
458
|
+
updates[:new] << Types::ListItem.new(self, list, li)
|
459
|
+
when 'Update'
|
460
|
+
updates[:update] = [] unless updates.has_key?(:update)
|
461
|
+
lu = rs.xpath('./z:row',ns).first
|
462
|
+
attrs = {}
|
463
|
+
lu.attributes.each_pair {|k,v| attrs[k] = v.value}
|
464
|
+
updates[:update] << attrs
|
465
|
+
when 'Delete'
|
466
|
+
updates[:delete] = {} unless updates.has_key?(:delete)
|
467
|
+
updates[:delete][id] = estat
|
468
|
+
else
|
469
|
+
raise "Unknown update return value, #{rs['ID']}"
|
470
|
+
end
|
471
|
+
end
|
472
|
+
updates
|
473
|
+
end
|
474
|
+
|
475
|
+
def check_update_error(code)
|
476
|
+
case code
|
477
|
+
when '0x00000000'
|
478
|
+
true
|
479
|
+
else
|
480
|
+
raise "Error code returned in update_list_items: #{code}"
|
481
|
+
end
|
482
|
+
end
|
483
|
+
|
484
|
+
end
|