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.
- data/LICENSE +25 -0
- data/README.rdoc +105 -0
- data/Rakefile +35 -6
- data/VERSION +1 -1
- data/lib/activesp.rb +27 -0
- data/lib/activesp/associations.rb +76 -0
- data/lib/activesp/base.rb +93 -7
- data/lib/activesp/caching.rb +32 -3
- data/lib/activesp/connection.rb +53 -16
- data/lib/activesp/content_type.rb +50 -1
- data/lib/activesp/field.rb +48 -2
- data/lib/activesp/file.rb +71 -0
- data/lib/activesp/folder.rb +72 -9
- data/lib/activesp/ghost_field.rb +70 -1
- data/lib/activesp/group.rb +46 -7
- data/lib/activesp/item.rb +252 -23
- data/lib/activesp/list.rb +284 -81
- data/lib/activesp/permission_set.rb +39 -4
- data/lib/activesp/persistent_caching.rb +61 -1
- data/lib/activesp/role.rb +49 -8
- data/lib/activesp/root.rb +67 -3
- data/lib/activesp/site.rb +110 -20
- data/lib/activesp/url.rb +27 -0
- data/lib/activesp/user.rb +39 -1
- data/lib/activesp/util.rb +198 -40
- metadata +42 -16
@@ -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
|
-
|
14
|
-
|
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
|
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 =>
|
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 =>
|
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 =>
|
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 =>
|
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 =>
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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 =>
|
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 =>
|
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.
|
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 =>
|
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 =>
|
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 =>
|
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
|
-
|
146
|
-
|
147
|
-
|
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 =>
|
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
|
|