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