proof-sharepoint-ruby 1.0.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +19 -0
- data/LICENSE +27 -0
- data/README.md +167 -0
- data/lib/sharepoint-error.rb +3 -0
- data/lib/sharepoint-fields.rb +126 -0
- data/lib/sharepoint-files.rb +80 -0
- data/lib/sharepoint-http-auth.rb +30 -0
- data/lib/sharepoint-kerberos-auth.rb +30 -0
- data/lib/sharepoint-lists.rb +235 -0
- data/lib/sharepoint-object.rb +179 -0
- data/lib/sharepoint-properties.rb +96 -0
- data/lib/sharepoint-ruby.rb +152 -0
- data/lib/sharepoint-session.rb +92 -0
- data/lib/sharepoint-stringutils.rb +37 -0
- data/lib/sharepoint-types.rb +84 -0
- data/lib/sharepoint-users.rb +36 -0
- data/lib/sharepoint-version.rb +3 -0
- data/lib/soap/authenticate.xml.erb +28 -0
- data/proof-sharepoint-ruby.gemspec +24 -0
- metadata +86 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'curb'
|
2
|
+
require 'cgi'
|
3
|
+
|
4
|
+
module Sharepoint
|
5
|
+
module HttpAuth
|
6
|
+
class Session
|
7
|
+
attr_accessor :site
|
8
|
+
attr_reader :user, :password
|
9
|
+
|
10
|
+
def initialize site
|
11
|
+
@site = site
|
12
|
+
end
|
13
|
+
|
14
|
+
def authenticate user, password
|
15
|
+
@user = user
|
16
|
+
@password = password
|
17
|
+
end
|
18
|
+
|
19
|
+
def cookie
|
20
|
+
String.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def curl curb
|
24
|
+
curb.http_auth_types = :ntlm
|
25
|
+
curb.username = @user
|
26
|
+
curb.password = @password
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'curb'
|
2
|
+
require 'cgi'
|
3
|
+
|
4
|
+
module Sharepoint
|
5
|
+
module KerberosAuth
|
6
|
+
class Session
|
7
|
+
attr_accessor :site
|
8
|
+
attr_reader :user, :password
|
9
|
+
|
10
|
+
def initialize site
|
11
|
+
@site = site
|
12
|
+
end
|
13
|
+
|
14
|
+
def authenticate user, password
|
15
|
+
@user = user
|
16
|
+
@password = password
|
17
|
+
end
|
18
|
+
|
19
|
+
def cookie
|
20
|
+
String.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def curl curb
|
24
|
+
curb.http_auth_types = :gssnegotiate
|
25
|
+
curb.username = @user
|
26
|
+
curb.password = @password
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,235 @@
|
|
1
|
+
module Sharepoint
|
2
|
+
LIST_TEMPLATE_TYPE = {
|
3
|
+
InvalidType: -1,
|
4
|
+
NoListTemplate: 0,
|
5
|
+
GenericList: 100,
|
6
|
+
DocumentLibrary: 101,
|
7
|
+
Survey: 102,
|
8
|
+
Links: 103,
|
9
|
+
Announcements: 104,
|
10
|
+
Contacts: 105,
|
11
|
+
Events: 106,
|
12
|
+
Tasks: 107,
|
13
|
+
DiscussionBoard: 108,
|
14
|
+
PictureLibrary: 109,
|
15
|
+
DataSources: 110,
|
16
|
+
UserInformation: 112,
|
17
|
+
WebPartCatalog: 113,
|
18
|
+
ListTemplateCatalog: 114,
|
19
|
+
XMLForm: 115,
|
20
|
+
MasterPageCatalog: 116,
|
21
|
+
NoCodeWorkflows: 117,
|
22
|
+
WorkflowProcess: 118,
|
23
|
+
WebPageLibrary: 119,
|
24
|
+
CustomGrid: 120,
|
25
|
+
SolutionCatalog: 121,
|
26
|
+
NoCodePublic: 122,
|
27
|
+
ThemeCatalog: 123,
|
28
|
+
DesignCatalog: 124,
|
29
|
+
AppDataCatalog: 125,
|
30
|
+
DataConnectionLibrary: 130,
|
31
|
+
WorkflowHistory: 140,
|
32
|
+
GanttTask: 150,
|
33
|
+
HelpLibrary: 151,
|
34
|
+
AccessRequest: 160,
|
35
|
+
TasksWithTimelineAndHierarchy: 171,
|
36
|
+
MaintenanceLogs: 175,
|
37
|
+
Meetings: 200,
|
38
|
+
Agenda: 201,
|
39
|
+
MeetingUser: 202,
|
40
|
+
Decision: 204,
|
41
|
+
MeetingObjective: 207,
|
42
|
+
TextBox: 210,
|
43
|
+
ThingsToBring: 211,
|
44
|
+
HomePageLibrary: 212,
|
45
|
+
Posts: 301,
|
46
|
+
Comments: 302,
|
47
|
+
Categories: 303,
|
48
|
+
Facility: 402,
|
49
|
+
Whereabouts: 403,
|
50
|
+
CallTrack: 404,
|
51
|
+
Circulation: 405,
|
52
|
+
Timecard: 420,
|
53
|
+
Hollidays: 421,
|
54
|
+
IMEDic: 499,
|
55
|
+
ExternalList: 600,
|
56
|
+
MySiteDocumentLibrary: 700,
|
57
|
+
IssueTracking: 1100,
|
58
|
+
AdminTasks: 1200,
|
59
|
+
HealthRules: 1220,
|
60
|
+
HealthReports: 1221,
|
61
|
+
DeveloperSiteDraftApps: 1230,
|
62
|
+
MicroFeed: 544 # Is undefined, but used by Sharepoint Online
|
63
|
+
}
|
64
|
+
|
65
|
+
module VtiBin
|
66
|
+
def self.translate_field_names input
|
67
|
+
return input unless defined? VtiDisplayNameDictionary
|
68
|
+
hash = Hash.new
|
69
|
+
input.keys.each do |key|
|
70
|
+
if VtiDisplayNameDictionary.keys.include? key
|
71
|
+
hash[VtiDisplayNameDictionary[key]] = input[key]
|
72
|
+
else
|
73
|
+
hash[key] = input[key]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
hash
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class List < Sharepoint::Object
|
81
|
+
include Sharepoint::Type
|
82
|
+
sharepoint_resource get_from_name: 'lists/getbytitle'
|
83
|
+
|
84
|
+
def find_items options = {}
|
85
|
+
@site.query :get, (make_item_filter options)
|
86
|
+
end
|
87
|
+
|
88
|
+
def item_count
|
89
|
+
@site.query :get, "#{__metadata['id']}/ItemCount"
|
90
|
+
end
|
91
|
+
|
92
|
+
def add_item attributes
|
93
|
+
attributes['__metadata'] ||= Hash.new
|
94
|
+
attributes['__metadata']['type'] ||= list_item_entity_type_full_name
|
95
|
+
@site.query :post, item_uri, attributes.to_json
|
96
|
+
end
|
97
|
+
|
98
|
+
def add_folder path, attributes
|
99
|
+
path = path.gsub(/\/*$/, '') # remove slashes at the end of the path
|
100
|
+
site_url = "#{@site.protocol}://#{@site.server_url}/"
|
101
|
+
action = "#{site_url}_vti_bin/listdata.svc/#{self.title}"
|
102
|
+
path = root_folder.server_relative_url + '/' + path
|
103
|
+
attributes['ContentTypeID'] ||= '0x01200059042D1A09191046851FA83D5B89816A'
|
104
|
+
attributes['Path'] ||= path
|
105
|
+
payload = VtiBin.translate_field_names(attributes).to_json
|
106
|
+
# Create the item using _vti_bin api
|
107
|
+
response = @site.query :post, action, payload, true do |curl|
|
108
|
+
curl.headers['Slug'] = "#{path}/#{attributes['Title']}|0x0120"
|
109
|
+
end
|
110
|
+
response = JSON.parse response
|
111
|
+
unless response['d'].nil?
|
112
|
+
# Fetch the item we just created using the REST api
|
113
|
+
item_id = response['d']['ID']
|
114
|
+
@site.query :get, "#{site_url}_api/#{__metadata['id']}/items(#{item_id})"
|
115
|
+
else
|
116
|
+
raise Sharepoint::SPException.new response, action, payload
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
field 'BaseTemplate', access: [ :read, :initialize ], default: LIST_TEMPLATE_TYPE[:GenericList]
|
121
|
+
field 'ContentTypesEnabled', default: true
|
122
|
+
field 'DefaultContentApprovalWorkflowId'
|
123
|
+
field 'DefaultDisplayFormUrl'
|
124
|
+
field 'DefaultEditFormUrl'
|
125
|
+
field 'DefaultNewFormUrl'
|
126
|
+
field 'Description'
|
127
|
+
field 'Direction'
|
128
|
+
field 'DocumentTemplateUrl'
|
129
|
+
field 'DraftVersionVisibility', default: 1
|
130
|
+
field 'EnableAttachments', default: false
|
131
|
+
field 'EnableFolderCreation', default: true
|
132
|
+
field 'EnableMinorVersions', default: true
|
133
|
+
field 'EnableModeration', default: true
|
134
|
+
field 'EnableVersioning', default: true
|
135
|
+
field 'ForceCheckout', default: false
|
136
|
+
field 'Hidden', default: false
|
137
|
+
field 'IrmEnabled', default: false
|
138
|
+
field 'IrmExpire', default: false
|
139
|
+
field 'IrmReject', default: false
|
140
|
+
field 'IsApplicationList', default: false
|
141
|
+
field 'MultipleDataList', default: false
|
142
|
+
field 'NoCrawl', default: false
|
143
|
+
field 'OnQuickLaunch', default: false
|
144
|
+
field 'Title'
|
145
|
+
field 'ValidationFormula'
|
146
|
+
field 'ValidationMessage'
|
147
|
+
|
148
|
+
private
|
149
|
+
def item_uri
|
150
|
+
url = @data['Items']['__deferred']
|
151
|
+
url = url['uri'] if url.class != String
|
152
|
+
url
|
153
|
+
end
|
154
|
+
|
155
|
+
def make_item_filter options = {}
|
156
|
+
url = item_uri
|
157
|
+
has_options = false
|
158
|
+
options.each do |key,value|
|
159
|
+
url += if has_options then '&' else '?' end
|
160
|
+
url += "$#{key}=#{URI::encode value.to_s}"
|
161
|
+
has_options = true
|
162
|
+
end
|
163
|
+
url
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
class ListItem < Sharepoint::Object
|
168
|
+
include Sharepoint::Type
|
169
|
+
belongs_to :list
|
170
|
+
|
171
|
+
method :break_role_inheritance, default_params: ({ copyroleassignements: true })
|
172
|
+
method :recycle
|
173
|
+
method :reset_role_inheritance
|
174
|
+
method :validate_update_item_list
|
175
|
+
end
|
176
|
+
|
177
|
+
class View < Sharepoint::Object
|
178
|
+
include Sharepoint::Type
|
179
|
+
belongs_to :list
|
180
|
+
|
181
|
+
field 'Aggregations'
|
182
|
+
field 'AggregationsStatus'
|
183
|
+
field 'ContentTypeId'
|
184
|
+
field 'DefaultView'
|
185
|
+
field 'DefaultViewForContentType'
|
186
|
+
field 'EditorModified'
|
187
|
+
field 'Formats'
|
188
|
+
field 'Hidden'
|
189
|
+
field 'IncludeRootFolder'
|
190
|
+
#field 'JsLink'
|
191
|
+
field 'ListViewXml'
|
192
|
+
field 'Method'
|
193
|
+
field 'MobileDefaultView'
|
194
|
+
field 'MobileView'
|
195
|
+
field 'Paged'
|
196
|
+
field 'RowLimit'
|
197
|
+
field 'Scope'
|
198
|
+
field 'Title'
|
199
|
+
field 'Toolbar'
|
200
|
+
field 'ViewData'
|
201
|
+
field 'ViewJoins'
|
202
|
+
field 'ViewProjectedFields'
|
203
|
+
field 'ViewQuery'
|
204
|
+
|
205
|
+
method :break_role_inheritance, default_params: ({ copyroleassignements: true })
|
206
|
+
method :recycle
|
207
|
+
method :render_list_form_data
|
208
|
+
method :reserve_list_item_id
|
209
|
+
end
|
210
|
+
|
211
|
+
class ViewFieldCollection < Sharepoint::Object
|
212
|
+
include Sharepoint::Type
|
213
|
+
sharepoint_resource
|
214
|
+
belongs_to :view
|
215
|
+
|
216
|
+
def add_view_field name
|
217
|
+
@site.query :post, "#{__metadata['uri']}/addviewfield('#{URI.encode name}')"
|
218
|
+
end
|
219
|
+
|
220
|
+
def move_view_field_to name, index
|
221
|
+
@site.query :post, "#{__metadata['uri']}/moveviewfieldto", {
|
222
|
+
field: name,
|
223
|
+
index: index
|
224
|
+
}.to_json
|
225
|
+
end
|
226
|
+
|
227
|
+
def remove_all_view_fields
|
228
|
+
@site.query :post, "#{__metadata['uri']}/removeallviewfields"
|
229
|
+
end
|
230
|
+
|
231
|
+
def remove_view_field name
|
232
|
+
@site.query :post, "#{__metadata['uri']}/removeviewfield('#{URI.encode name}')"
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
require 'sharepoint-properties'
|
2
|
+
require 'sharepoint-stringutils'
|
3
|
+
|
4
|
+
module Sharepoint
|
5
|
+
class Site
|
6
|
+
end
|
7
|
+
|
8
|
+
class Object < Sharepoint::ObjectProperties
|
9
|
+
class << self
|
10
|
+
attr_accessor :fields
|
11
|
+
|
12
|
+
def fields
|
13
|
+
@fields ||= []
|
14
|
+
if self.superclass != Sharepoint::Object
|
15
|
+
self.superclass.fields | @fields
|
16
|
+
else
|
17
|
+
@fields
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def field name, options = {}
|
24
|
+
options[:access] ||= [ :read, :write ]
|
25
|
+
@fields ||= []
|
26
|
+
@fields << { name: name, access: options[:access], default: options[:default] }
|
27
|
+
end
|
28
|
+
|
29
|
+
def method name, method_params = {}
|
30
|
+
method_params[:http_method] ||= :post
|
31
|
+
method_params[:endpoint] ||= name.to_s.camelize
|
32
|
+
method_params[:default_params] ||= Hash.new
|
33
|
+
define_method name, ->(params = Hash.new) do
|
34
|
+
action = "#{__metadata['uri']}/#{method_params[:endpoint]}"
|
35
|
+
body = nil
|
36
|
+
# Set default parameters
|
37
|
+
(method_params[:default_params].each do |key,value|
|
38
|
+
params[key] == value if params[key].nil?
|
39
|
+
end)
|
40
|
+
if (method_params[:http_method] == :get) and (params.class < Hash) and (params.keys.count > 0)
|
41
|
+
# if method is get, Fill action with parameters
|
42
|
+
action += '('
|
43
|
+
(params.each do |key,value|
|
44
|
+
action += ',' unless params.keys.first == key
|
45
|
+
action += key + '='
|
46
|
+
action += (if (value.class < String) or (value.class < Symbol)
|
47
|
+
"'#{(URI.encode value.gsub("'", %q(\\\')))}'"
|
48
|
+
else
|
49
|
+
value
|
50
|
+
end)
|
51
|
+
end)
|
52
|
+
action += ')'
|
53
|
+
else
|
54
|
+
# if method is post, send parameters in the body
|
55
|
+
body = (params.class < Hash ? params.to_json : params)
|
56
|
+
end
|
57
|
+
# Call action
|
58
|
+
@site.query method_params[:http_method], action, body, method_params[:skip_json]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def sharepoint_resource options = {}
|
63
|
+
options[:method_name] ||= (self.name).split('::').last.downcase + 's'
|
64
|
+
options[:getter] ||= options[:method_name]
|
65
|
+
options[:get_from_name] ||= options[:getter]
|
66
|
+
Sharepoint::Site.send :define_method, options[:method_name] do
|
67
|
+
self.query :get, options[:getter].to_s
|
68
|
+
end unless options[:no_root_collection] == true
|
69
|
+
Sharepoint::Site.send :define_method, (self.name).split('::').last.downcase do |id|
|
70
|
+
if id =~ /^[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}$/
|
71
|
+
self.query :get, "#{options[:getter]}(guid'#{id}')"
|
72
|
+
else
|
73
|
+
self.query :get, "#{options[:get_from_name]}('#{URI.encode id}')"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def belongs_to resource_name
|
79
|
+
resource_name = resource_name.to_s
|
80
|
+
class_name = (self.name).split('::').last.downcase
|
81
|
+
method_name = class_name.pluralize
|
82
|
+
define_singleton_method "all_from_#{resource_name}" do |resource|
|
83
|
+
resource.site.query :get, "#{resource.__metadata['uri']}/#{method_name}"
|
84
|
+
end
|
85
|
+
define_singleton_method "get_from_#{resource_name}" do |resource, name|
|
86
|
+
resource.site.query :get, "#{resource.__metadata['uri']}/#{method_name}('#{URI.encode name}')"
|
87
|
+
end
|
88
|
+
define_method "create_uri" do
|
89
|
+
unless self.parent.nil?
|
90
|
+
"#{self.parent.__metadata['uri']}/#{method_name}"
|
91
|
+
else
|
92
|
+
method_name
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
attr_accessor :parent
|
99
|
+
|
100
|
+
def initialize site, data
|
101
|
+
@parent = nil
|
102
|
+
super site, data
|
103
|
+
end
|
104
|
+
|
105
|
+
def guid
|
106
|
+
return @guid unless @guid.nil?
|
107
|
+
__metadata['id'].scan(/guid'([^']+)'/) do ||
|
108
|
+
@guid = $1
|
109
|
+
break
|
110
|
+
end
|
111
|
+
@guid
|
112
|
+
end
|
113
|
+
|
114
|
+
def reload
|
115
|
+
@site.query :get, __metadata['uri']
|
116
|
+
end
|
117
|
+
|
118
|
+
def save
|
119
|
+
if @data['__metadata'].nil? or @data['__metadata']['id'].nil?
|
120
|
+
create
|
121
|
+
elsif @updated_data.keys.count > 0
|
122
|
+
update
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def destroy
|
127
|
+
@site.query :post, resource_uri do |curl|
|
128
|
+
curl.headers['X-HTTP-Method'] = 'DELETE'
|
129
|
+
curl.headers['If-Match'] = __metadata['etag']
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def copy new_object = nil
|
134
|
+
updating = !new_object.nil?
|
135
|
+
new_object ||= self.class.new @site
|
136
|
+
self.class.fields.each do |field|
|
137
|
+
next unless @data.keys.include? field[:name].to_s
|
138
|
+
next if (field[:access] & [ :write, :initialize ]).count == 0
|
139
|
+
value = @data[field[:name].to_s]
|
140
|
+
if updating == false
|
141
|
+
new_object.data[field[:name].to_s] = value
|
142
|
+
elsif new_object.data[field[:name].to_s] != value
|
143
|
+
new_object.updated_data[field[:name].to_s] = value
|
144
|
+
end
|
145
|
+
end
|
146
|
+
new_object
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
def sharepoint_typename
|
151
|
+
if self.is_a?(Sharepoint::GenericSharepointObject)
|
152
|
+
@generic_type_name
|
153
|
+
else
|
154
|
+
self.class.name.split('::').last
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def resource_uri
|
159
|
+
@data['__metadata']['uri'].gsub(/^https:\/\/[^\/]+\/_api\/web\//i, '')
|
160
|
+
end
|
161
|
+
|
162
|
+
def create_uri
|
163
|
+
sharepoint_typename.downcase.pluralize
|
164
|
+
end
|
165
|
+
|
166
|
+
def create
|
167
|
+
@site.query :post, create_uri, @data.to_json
|
168
|
+
end
|
169
|
+
|
170
|
+
def update
|
171
|
+
@updated_data['__metadata'] ||= @data['__metadata']
|
172
|
+
@site.query :post, resource_uri, @updated_data.to_json do |curl|
|
173
|
+
curl.headers['X-HTTP-Method'] = 'MERGE'
|
174
|
+
curl.headers['If-Match'] = __metadata['etag']
|
175
|
+
end
|
176
|
+
@updated_data = Hash.new
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|