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,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 PermissionSet
@@ -6,22 +31,32 @@ module ActiveSP
6
31
 
7
32
  attr_reader :scope
8
33
 
34
+ # @private
9
35
  def initialize(scope)
10
36
  @scope = scope
11
37
  end
12
38
 
13
- def permissions
14
- @scope.send(:permissions)
15
- end
16
-
39
+ # See {Base#key}
40
+ # @return [String]
17
41
  def key
18
42
  encode_key("P", [@scope.key])
19
43
  end
20
44
 
45
+ # Returns the permissions in this permission set as an array of hashes with :accessor mapping to a user,
46
+ # group or role and :mask mapping to the permission as an integer
47
+ # @return [Array<Hash{:accessor, :permission => User, Group, Role, Integer}>]
48
+ # @example
49
+ # set.permissions #=> [{:accessor=>#<ActiveSP::User login_name=SHAREPOINT\system>, :mask=>134287360}]
50
+ def permissions
51
+ @scope.send(:permissions)
52
+ end
53
+
54
+ # @private
21
55
  def to_s
22
56
  "#<ActiveSP::PermissionSet scope=#{@scope}>"
23
57
  end
24
58
 
59
+ # @private
25
60
  alias inspect to_s
26
61
 
27
62
  end
@@ -1,7 +1,35 @@
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
+ # @private
3
29
  module PersistentCaching
4
30
 
31
+ private
32
+
5
33
  def persistent(&blk)
6
34
  class << self ; self ; end.instance_eval do
7
35
  alias_method :old_new, :new
@@ -18,6 +46,7 @@ module ActiveSP
18
46
 
19
47
  end
20
48
 
49
+ # @private
21
50
  class PersistentCache
22
51
 
23
52
  def initialize
@@ -38,11 +67,42 @@ module ActiveSP
38
67
 
39
68
  module PersistentCachingConfig
40
69
 
70
+ # Configures the scope of the persistent cache. The default scope of the cache
71
+ # is the {Connection} object, i.e., each connection has its own cache. For example
72
+ # you can use this to make thread local caches. Note that the cache is not actually
73
+ # thread safe at this point so this may not be such a bad idea.
74
+ #
75
+ # Caching in ActiveSP at the moment is very aggressive. What this means that everything
76
+ # you ever accessed will be cached. You can override the cache for a particular object
77
+ # by calling {Base#reload} on it. One advantage of this caching strategy is that every time
78
+ # you access an object in SharePoint, it is guaranteed to be the same object in Ruby as
79
+ # well, irrespective of how you obtained a reference to that object. This eliminates a
80
+ # whole slew of issues, but you need to be aware of this.
81
+ #
82
+ # This method expects a block to which a new cache object is passed. The idea is that
83
+ # you store this cache object in a place that reflects the scope of your cache. If you
84
+ # already had a cache object stored for you current scope, you do not do anything with
85
+ # the cache object. The cache object that the block returns is the cache that will be used.
86
+ # Note that the block is called everytime ActiveSP needs the cache, so make it as
87
+ # efficient as possible. The example below illustrates how you can use the ||= operator
88
+ # for this to get a thread local cache.
89
+ #
90
+ # You can use this block to return a cache of your own. A cache is only expected to have
91
+ # a lookup method to which the cache key is passed (do not assume it is an integer or a
92
+ # string because it is not) as parameter and is expected to return the value for that
93
+ # key. In case of a cache miss, the method should yield to retrieve the value, store it
94
+ # with the given key and return the value. You can use this to plug in a cache that has
95
+ # a limited size, or that uses weak references to clean up the cache. The latter suggestion
96
+ # is a lot safer than the former!
97
+ #
98
+ # @example How to configure caching strategy
99
+ # c = ActiveSP::Connection.new(:login => l, :password => p, :root => r)
100
+ # c.configure_persistent_cache { |cache| Thread.current[:sp_cache] ||= cache }
41
101
  def configure_persistent_cache(&blk)
42
102
  @last_persistent_cache_object = PersistentCache.new
43
103
  class << self ; self ; end.send(:define_method, :persistent_cache) do
44
104
  cache = blk.call(@last_persistent_cache_object)
45
- @last_persistent_cache_object = PersistentCache.new unless cache == @last_persistent_cache_object
105
+ @last_persistent_cache_object = PersistentCache.new if cache == @last_persistent_cache_object
46
106
  cache
47
107
  end
48
108
  end
data/lib/activesp/role.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 Role < Base
@@ -7,43 +32,59 @@ 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, [:role, 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("R", [@name])
19
45
  end
20
46
 
47
+ # Returns the list of users in this role
48
+ # @return [User]
21
49
  def users
22
50
  call("UserGroup", "get_user_collection_from_role", "roleName" => @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
28
56
 
57
+ # Returns the list of groups in this role
58
+ # @return [Group]
29
59
  def groups
30
60
  call("UserGroup", "get_group_collection_from_role", "roleName" => @name).xpath("//spdir:Group", NS).map do |row|
31
61
  attributes = clean_attributes(row.attributes)
32
62
  Group.new(@site, attributes["Name"])
33
63
  end
34
64
  end
35
- cache :groups, :dup => true
65
+ cache :groups, :dup => :always
66
+
67
+ # Returns true. The same method is present on {Group} where it returns false. Roles and groups can generally be
68
+ # duck-typed, and this method is there for the rare case where you do need to make the distinction
69
+ # @return [Boolean]
70
+ def is_role?
71
+ true
72
+ end
36
73
 
74
+ # See {Base#save}
75
+ # @return [void]
76
+ def save
77
+ p untype_cast_attributes(@site, nil, internal_attribute_types, changed_attributes)
78
+ end
79
+
80
+ # @private
37
81
  def to_s
38
82
  "#<ActiveSP::Role name=#{@name}>"
39
83
  end
40
84
 
85
+ # @private
41
86
  alias inspect to_s
42
87
 
43
- def is_role?
44
- true
45
- end
46
-
47
88
  private
48
89
 
49
90
  def data
data/lib/activesp/root.rb CHANGED
@@ -1,5 +1,31 @@
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
+ # @private
3
29
  NS = {
4
30
  "sp" => "http://schemas.microsoft.com/sharepoint/soap/",
5
31
  "z" => "#RowsetSchema",
@@ -10,34 +36,71 @@ module ActiveSP
10
36
 
11
37
  extend Caching
12
38
 
39
+ # Returns the root site as an object of class {Site}
40
+ # @return [Site]
13
41
  def root
14
42
  Site.new(self, @root_url)
15
43
  end
16
44
  cache :root
17
45
 
46
+ # Returns the list of users in the system
47
+ # @return [Array<User>]
18
48
  def users
19
49
  root.send(:call, "UserGroup", "get_user_collection_from_site").xpath("//spdir:User", NS).map do |row|
20
50
  attributes = clean_attributes(row.attributes)
21
51
  User.new(root, attributes["LoginName"])
22
52
  end
23
53
  end
24
- cache :users, :dup => true
54
+ cache :users, :dup => :always
25
55
 
56
+ # Returns the user with the given login, or nil when the user does not exist
57
+ # @param [String] login The login of the user
58
+ # @return [User, nil]
59
+ def user(login)
60
+ if user = users_by_login[login]
61
+ user
62
+ elsif data = root.send(:call, "UserGroup", "get_user_info", "userLoginName" => login).xpath("//spdir:User", NS).first
63
+ users_by_login[login] = User.new(root, login, clean_attributes(data))
64
+ end
65
+ end
66
+
67
+ # Returns the list of groups in the system
68
+ # @return [Array<Group>]
26
69
  def groups
27
70
  root.send(:call, "UserGroup", "get_group_collection_from_site").xpath("//spdir:Group", NS).map do |row|
28
71
  attributes = clean_attributes(row.attributes)
29
72
  Group.new(root, attributes["Name"])
30
73
  end
31
74
  end
32
- cache :groups, :dup => true
75
+ cache :groups, :dup => :always
76
+
77
+ def group(name)
78
+ if group = groups_by_name[name]
79
+ group
80
+ end
81
+ end
33
82
 
83
+ # Returns the list of roles in the system
84
+ # @return [Array<Role>]
34
85
  def roles
35
86
  root.send(:call, "UserGroup", "get_role_collection_from_web").xpath("//spdir:Role", NS).map do |row|
36
87
  attributes = clean_attributes(row.attributes)
37
88
  Role.new(root, attributes["Name"])
38
89
  end
39
90
  end
40
- cache :roles, :dup => true
91
+ cache :roles, :dup => :always
92
+
93
+ private
94
+
95
+ def users_by_login
96
+ users.inject({}) { |h, u| h[u.login_name] = u ; h }
97
+ end
98
+ cache :users_by_login
99
+
100
+ def groups_by_name
101
+ groups.inject({}) { |h, g| h[g.Name] = g ; h }
102
+ end
103
+ cache :groups_by_name
41
104
 
42
105
  end
43
106
 
@@ -47,6 +110,7 @@ module ActiveSP
47
110
 
48
111
  end
49
112
 
113
+ # @private
50
114
  module InSite
51
115
 
52
116
  private
data/lib/activesp/site.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 Site < Base
@@ -6,51 +31,73 @@ module ActiveSP
6
31
  extend PersistentCaching
7
32
  include Util
8
33
 
9
- attr_reader :url, :connection
34
+ # The URL of this site
35
+ # @return [String]
36
+ attr_reader :url
37
+ # @private
38
+ attr_reader :connection
10
39
 
11
40
  persistent { |connection, url, *a| [connection, [:site, url]] }
41
+ # @private
12
42
  def initialize(connection, url, depth = 0)
13
43
  @connection, @url, @depth = connection, url, depth
14
44
  @services = {}
15
45
  end
16
46
 
47
+ # @private
17
48
  def relative_url(url = @url)
18
49
  url[@connection.root_url.rindex("/") + 1..-1]
19
50
  end
20
51
 
52
+ # Returns the containing site, or nil if this is the root site
53
+ # @return [Site]
21
54
  def supersite
22
- if @depth > 0
23
- Site.new(@connection, File.dirname(@url), @depth - 1)
55
+ unless is_root_site?
56
+ Site.new(@connection, ::File.dirname(@url), @depth - 1)
24
57
  end
25
58
  end
26
59
  cache :supersite
27
60
 
61
+ # Returns the root site, or this site if it is the root site
62
+ # @return [Site]
28
63
  def rootsite
29
- @depth > 0 ? supersite.rootsite : self
64
+ is_root_site? ? self : supersite.rootsite
30
65
  end
31
66
  cache :rootsite
32
67
 
68
+ # Returns true if this site is the root site
69
+ # @return [Boolean]
33
70
  def is_root_site?
34
71
  @depth == 0
35
72
  end
36
73
 
37
- def key
74
+ # See {Base#key}
75
+ # @return [String]
76
+ def key # This documentation is not ideal. The ideal doesn't work out of the box
38
77
  encode_key("S", [@url[@connection.root_url.length + 1..-1], @depth])
39
78
  end
40
79
 
80
+ # Returns the list of sites below this site. Does not recurse
81
+ # @return [Array<List>]
41
82
  def sites
42
83
  result = call("Webs", "get_web_collection")
43
84
  result.xpath("//sp:Web", NS).map { |web| Site.new(connection, web["Url"].to_s, @depth + 1) }
44
85
  end
45
- cache :sites, :dup => true
86
+ cache :sites, :dup => :always
46
87
 
88
+ # Returns the site with the given name. This name is what appears in the URL as name and is immutable. Return nil
89
+ # if such a site does not exist
90
+ # @param [String] name The name if the site
91
+ # @return [Site]
47
92
  def site(name)
48
- result = call("Webs", "get_web", "webUrl" => File.join(@url, name))
93
+ result = call("Webs", "get_web", "webUrl" => ::File.join(@url, name))
49
94
  Site.new(connection, result.xpath("//sp:Web", NS).first["Url"].to_s, @depth + 1)
50
95
  rescue Savon::SOAPFault
51
96
  nil
52
97
  end
53
98
 
99
+ # Returns the list if lists in this sute. Does not recurse
100
+ # @return [Array<List>]
54
101
  def lists
55
102
  result1 = call("Lists", "get_list_collection")
56
103
  result2 = call("SiteData", "get_list_collection")
@@ -66,28 +113,42 @@ module ActiveSP
66
113
  List.new(self, list["ID"].to_s, list["Title"].to_s, clean_attributes(list.attributes), result2_by_id[list["ID"].to_s])
67
114
  end
68
115
  end
69
- cache :lists, :dup => true
116
+ cache :lists, :dup => :always
70
117
 
118
+ # Returns the list with the given name. The name is what appears in the URL as name and is immutable. Returns nil
119
+ # if such a list does not exist
120
+ # @param [String] name The name of the list
121
+ # @return [List]
71
122
  def list(name)
72
- lists.find { |list| File.basename(list.attributes["RootFolder"]) == name }
123
+ lists.find { |list| ::File.basename(list.url) == name }
73
124
  end
74
125
 
126
+ # Returns the site or list with the given name, or nil if it does not exist
127
+ # @param [String] name The name of the site or list
128
+ # @return [Site, List]
75
129
  def /(name)
76
130
  list(name) || site(name)
77
131
  end
78
132
 
133
+ # Returns the list of content types defined for this site. These include the content types defined on
134
+ # containing sites as they are automatically inherited
135
+ # @return [Array<ContentType>]
79
136
  def content_types
80
137
  result = call("Webs", "get_content_types", "listName" => @id)
81
138
  result.xpath("//sp:ContentType", NS).map do |content_type|
82
139
  supersite && supersite.content_type(content_type["ID"]) || ContentType.new(self, nil, content_type["ID"], content_type["Name"], content_type["Description"], content_type["Version"], content_type["Group"])
83
140
  end
84
141
  end
85
- cache :content_types, :dup => true
142
+ cache :content_types, :dup => :always
86
143
 
144
+ # @private
87
145
  def content_type(id)
88
146
  content_types.find { |t| t.id == id }
89
147
  end
90
148
 
149
+ # Returns the permission set associated with this site. This returns the permission set of
150
+ # the containing site if it does not have a permission set of its own
151
+ # @return [PermissionSet]
91
152
  def permission_set
92
153
  if attributes["InheritedSecurity"]
93
154
  supersite.permission_set
@@ -97,27 +158,47 @@ module ActiveSP
97
158
  end
98
159
  cache :permission_set
99
160
 
161
+ # Returns the list of fields for this site. This includes fields inherited from containing sites
162
+ # @return [Array<Field>]
100
163
  def fields
101
164
  call("Webs", "get_columns").xpath("//sp:Field", NS).map do |field|
102
165
  attributes = clean_attributes(field.attributes)
103
166
  supersite && supersite.field(attributes["ID"].downcase) || Field.new(self, attributes["ID"].downcase, attributes["StaticName"], attributes["Type"], nil, attributes) if attributes["ID"] && attributes["StaticName"]
104
167
  end.compact
105
168
  end
106
- cache :fields, :dup => true
169
+ cache :fields, :dup => :always
107
170
 
171
+ # Returns the result of {Site#fields} hashed by name
172
+ # @return [Hash{String => Field}]
108
173
  def fields_by_name
109
174
  fields.inject({}) { |h, f| h[f.attributes["StaticName"]] = f ; h }
110
175
  end
111
- cache :fields_by_name, :dup => true
176
+ cache :fields_by_name, :dup => :always
112
177
 
178
+ # @private
113
179
  def field(id)
114
180
  fields.find { |f| f.ID == id }
115
181
  end
116
182
 
183
+ # See {Base#save}
184
+ # @return [void]
185
+ def save
186
+ p untype_cast_attributes(self, nil, internal_attribute_types, changed_attributes)
187
+ end
188
+
189
+ def accessible?
190
+ data
191
+ true
192
+ rescue Savon::HTTPError
193
+ false
194
+ end
195
+
196
+ # @private
117
197
  def to_s
118
198
  "#<ActiveSP::Site url=#{@url}>"
119
199
  end
120
200
 
201
+ # @private
121
202
  alias inspect to_s
122
203
 
123
204
  private
@@ -136,17 +217,25 @@ module ActiveSP
136
217
  end
137
218
 
138
219
  def data
220
+ # Looks like you can't call this as a non-admin. To investigate further
139
221
  call("SiteData", "get_web")
222
+ rescue Savon::HTTPError
223
+ # This can fail when you don't have access to this site
224
+ call("Webs", "get_web", "webUrl" => ".")
140
225
  end
141
226
  cache :data
142
227
 
143
228
  def attributes_before_type_cast
144
- element = data.xpath("//sp:sWebMetadata", NS).first
145
- result = {}
146
- element.children.each do |ch|
147
- result[ch.name] = ch.inner_text
229
+ if element = data.xpath("//sp:sWebMetadata", NS).first
230
+ result = {}
231
+ element.children.each do |ch|
232
+ result[ch.name] = ch.inner_text
233
+ end
234
+ result
235
+ else
236
+ element = data.xpath("//sp:Web", NS).first
237
+ clean_attributes(element.attributes)
148
238
  end
149
- result
150
239
  end
151
240
  cache :attributes_before_type_cast
152
241
 
@@ -176,19 +265,20 @@ module ActiveSP
176
265
  end
177
266
 
178
267
  def permissions
179
- result = call("Permissions", "get_permission_collection", "objectName" => File.basename(@url), "objectType" => "Web")
268
+ result = call("Permissions", "get_permission_collection", "objectName" => ::File.basename(@url), "objectType" => "Web")
180
269
  result.xpath("//spdir:Permission", NS).map do |row|
181
270
  accessor = row["MemberIsUser"][/true/i] ? User.new(rootsite, row["UserLogin"]) : Group.new(rootsite, row["GroupName"])
182
271
  { :mask => Integer(row["Mask"]), :accessor => accessor }
183
272
  end
184
273
  end
185
- cache :permissions, :dup => true
274
+ cache :permissions, :dup => :always
186
275
 
276
+ # @private
187
277
  class Service
188
278
 
189
279
  def initialize(site, name)
190
280
  @site, @name = site, name
191
- @client = Savon::Client.new(File.join(site.url, "_vti_bin", name + ".asmx?WSDL"))
281
+ @client = Savon::Client.new(::File.join(URI.escape(site.url), "_vti_bin", name + ".asmx?WSDL"))
192
282
  @client.request.ntlm_auth(site.connection.login, site.connection.password) if site.connection.login
193
283
  end
194
284