sharepoint-ruby 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9066e1d5499871de09ed46063dd308a81980f9e108bcdcb833092e05c4aa3f98
4
- data.tar.gz: fda3bfa38a5730aa6328370f0a46e7aced79271851eb9eb02765f17e939b19db
3
+ metadata.gz: 06a548cde4c7aede93cbc0f46fd90e5343faff5f64e4d18bb877cf4ce4bdbf7e
4
+ data.tar.gz: 5b34f39ca74c0583f3dc5d509639f1dbe73972477aa2a259e6a741b7a0cbd649
5
5
  SHA512:
6
- metadata.gz: '0091b8b591e50ef402cb9f06b3922a50126e4c2e2818df1c3f318ab06aeedadbb07cd7f3d436ae2cbc6265f4965fa4e05f6a589d9389f68af43a513e4faacf38'
7
- data.tar.gz: 6b0cc5c1f06c2296168a3eb967c5b856dbfbc73202872df3b54c6102a021dc7cb6c245368725d786a409587406510119fecd661e8f86825808e90e48a07ccf02
6
+ metadata.gz: '0708c3ab5cf9238fd35617ebf07d634ef7ad0c766efec37f47ed4050938fc4aaecddc793b1a9ff4ce5e2ccc32cc0c829e650ad87ecf73abe3b5b1b6e4c857446'
7
+ data.tar.gz: ef28ea0e00baee2d803a30a36fedbb8b48e03e637972033e002db56fd401f8af33214bc30fb525275f41cb0503e8e3f5833e06bb6bef3cf46df21c94b7dcfdfb
@@ -0,0 +1,167 @@
1
+ sharepoint-ruby
2
+ ===============
3
+ A ruby gem that maps Sharepoint's REST API in a simple and accessible fashion.
4
+
5
+ How to use
6
+ ===============
7
+ First, you'll have to initialize a sharepoint site and open a session in order to start making requests to the REST API:
8
+
9
+ ```Ruby
10
+ require 'sharepoint-ruby'
11
+
12
+ site = Sharepoint::Site.new 'mysite.sharepoint.com', 'server-relative-site-url'
13
+ site.session.authenticate 'mylogin', 'mypassword'
14
+
15
+ blog = Sharepoint::Site.new 'mytenant.sharepoint.com', 'sites/blog'
16
+ blog.session.authenticate 'user', 'pwd'
17
+ lists = blog.lists
18
+ for l in lists
19
+ puts l.title
20
+ end
21
+ ```
22
+
23
+ Note that site.session.authenticate might throw an exception if the authentication doesn't go well (wrong urls, STS unavailable, or wrong login/password).
24
+ The exceptions might be of type ConnectionToStsFailed, AuthenticationFailed, ConnexionToSharepointFailed, UnknownAuthenticationError.
25
+
26
+ ### Connecting to your own STS
27
+ By default, sharepoint-ruby uses Microsoft's STS (https://login.microsoftonline.com/extSTS.srf), which works for Sharepoint Online. You may use your own STS by using the optional third parameter of Sharepoint::Site.new:
28
+
29
+ ```Ruby
30
+ site = Sharepoint::Site.new 'mysite.sharepoint.com', 'site-name'
31
+ site.session.authenticate 'username', 'password', 'https://sts_url.com/extSTS.srf'
32
+ ```
33
+
34
+ ### Connecting using NTLM
35
+ You may also connect using the NTLM method. For that purpose, you'll have to overwrite the default session handler with `Sharepoint::HttpAuth::Session`.
36
+
37
+ ```Ruby
38
+ require 'sharepoint-http-auth'
39
+
40
+ site = Sharepoint::Site.new 'mysite.sharepoint.com', 'site-name'
41
+ site.session = Sharepoint::HttpAuth::Session.new site
42
+ site.session.authenticate 'login', 'password'
43
+ site.protocole = 'http' # default protocole is https: don't forget to set this if you use http.
44
+ ```
45
+
46
+ ### Connecting using Kerberos
47
+ You may also connect using Kerberos if you're using *MIT Kerberos*.
48
+ For that purpose, you'll have to overwrite the default session handler with `Sharepoint::KerberosAuth::Session`.
49
+
50
+ ```Ruby
51
+ require 'sharepoint-kerberos-auth'
52
+
53
+ site = Sharepoint::Site.new 'mysite.sharepoint.com', 'site-name'
54
+ site.session = Sharepoint::KerberosAuth::Session.new site
55
+ site.session.authenticate 'login', 'password'
56
+ site.protocole = 'http' # default protocole is https: don't forget to set this if you use http.
57
+ ```
58
+
59
+ ### General features
60
+
61
+ Once you're logged in, you may access the site's ressource through the site object:
62
+ ```Ruby
63
+ fields = site.fields # Get all the site's fields
64
+ groups = site.groups # Get all the site's groups
65
+ users = site.users # Get all the site's users
66
+
67
+ lists = site.lists # Get all the site's list
68
+ list = site.list 'Documents' # Get a list by title
69
+ list = site.list '51925dd7-2108-481a-b1ef-4bfa4e69d48b' # Get a list by guid
70
+ views = list.views # Get all the lists views
71
+
72
+ folders = site.folders # Get all the site's folder
73
+ folder = site.folder '/SiteAssets/documents' # Get a folder by server relative path
74
+ files = folder.files # Get all the folder's files
75
+ ```
76
+
77
+ ### OData mapping
78
+ When Sharepoint answers with an OData object, the `site.query` method will automatically map it to the corresponding Sharepoint::Object class.
79
+ For instance, if Sharepoint answered with an OData object of type 'SP.List', `site.query` will return an instance of the Sharepoint::List class. These classes implement a getter and a setter for all the properties declared for the corresponding object in Sharepoint's 2013 Documentation.
80
+
81
+ N.B: Note that the setter only exists if the property is declared as write-accessible in the documentation.
82
+ N.B#2: Note that despite the camel casing used by Sharepoint, the getter and setter are snake cased (i.e: the CustomMasterUrl property becomes accessible through the custom_master_url getter and custom_mater_url= getter).
83
+
84
+ #### Sharepoint::Object specifics
85
+ Sharepoint::Object contains a few methods to help you handle your objects:
86
+
87
+ The `guid` method can be used to retrieve the guid of any object.
88
+
89
+ The `reload` method returns an instance of the same object from the remote sharepoint site. It may be useful if you want to be sure that your object contains the latest changes.
90
+
91
+ The `save` method will automatically compile your changes and perform the MERGE request with the Sharepoint site.
92
+
93
+ The `destroy` method will destroy the remote ressource on the Sharepoint site.
94
+
95
+ The `copy` method can duplicate an existing object. If you send it a Sharepoint::Object as a parameter, it will duplicate into the parameter. If you don't send any parameter, it will create a new object. Note that no changes happen on the sharepoint site until you've called the `save` method on the returned object.
96
+
97
+ ### Deferred objects
98
+ Some of the properties of the OData object are 'deferred', which means that the property only provides a link to a ressource that you would have to get for yourself.
99
+ Not with the sharepoint-ruby gem however: the first time you try to access a deferred property, the object will on it's own go look for the corresponding remote ressource: the result will be stored for later uses, and then be returned to you.
100
+
101
+ ### Modifying Sharepoint's ressources
102
+ The Sharepoint REST API provides us with methods to create, update or delete resources. In the Sharepoint::Object, these behaviours are implemented through the save and delete methods.
103
+
104
+ ##### Updating objects
105
+ This piece of code will change the custom master page used by the Sharepoint site to 'oslo.master':
106
+ ```Ruby
107
+ web = site.context_info # Sharepoint::Site.context_info returns the Web object for the current site (see: http://msdn.microsoft.com/en-us/library/office/dn499819(v=office.15).aspx )
108
+ web.custom_master_url = '/_catalogs/masterpage/oslo.master'
109
+ web.save
110
+ ```
111
+
112
+ ##### Creating objects
113
+ You may also create your own objects. This will be slightly different: we will create our own instance of a Sharepoint::List object.
114
+ Some Sharepoint objects have values that can only be set during their initialization: `sharepoint-ruby` doesn't allow you to set these values through a setter.
115
+ In the case of list, Sharepoint will require you to specify the value for the `BaseTemplate` property. This is how you would specify the default value for an attribute that isn't write-accessible:
116
+ ```Ruby
117
+ list = Sharepoint::List.new site, { 'BaseTemplate' => Sharepoint::LIST_TEMPLATE_TYPE[:GenericList] }
118
+ list.title = 'My new list'
119
+ list.description = 'A list created by sharepoint-ruby'
120
+ list = list.save # At creation, the remote object created will be returned by the save method.
121
+ ```
122
+ Note that the attribute's name in the constructor remains camel cased (`BaseTemplate`), though the getter for this attribute is still snake cased (`base_template`).
123
+
124
+ ##### Destroying objects
125
+ Now, say you want to destroy the list you just created, this will do nicely:
126
+ ```Ruby
127
+ list.destroy
128
+ ```
129
+
130
+ ### Parenting
131
+ In the previous paragraph, we saw how to create a Sharepoint::List object. Sharepoint lists aren't parented to any other objects: Sharepoint views however are parented to a list. If you wanted to create a view for the list we just created, you would have to specify a parent for the view:
132
+
133
+ ```Ruby
134
+ view = Sharepoint::View.new site
135
+ view.title = 'My new view'
136
+ view.personal_view = false
137
+ view.parent = list # Setting the view's parent to the Sharepoint::List
138
+ view.save
139
+ ```
140
+
141
+ ### Collections
142
+ In sharepoint-ruby, collections are merely arrays of Sharepoint::Objects. If you wish to add an object to a colleciton, set the parent to the object providing the collection.
143
+
144
+ ### List Items
145
+ Sharepoint doesn't allow the user to fetch more than 100 items per query. When your list contains more than a 100 items, you may fetch them using the `find_items` method:
146
+
147
+ ```Ruby
148
+ list = site.list 'My List'
149
+ # Use the skip option to paginate
150
+ list.find_items skip: 50 # returns items from 50-150
151
+ # You may use other operators in your query, such as orderby, select, filter and top:
152
+ list.find_items skip: 100, orderby: 'Title asc'
153
+ ```
154
+
155
+ ### Exceptions
156
+ Inevitably, some of your requests will fail. The object sharepoint returns when an error happens is also mapped by sharepoint-ruby in the Sharepoint::SPException class.
157
+ The SPException class contains methods to inspect the query that was made to the server:
158
+
159
+ ```Ruby
160
+ begin
161
+ list = site.list 'title that does not exists'
162
+ rescue Sharepoint::SPException => e
163
+ puts "Sharepoint complained about something: #{e.message}"
164
+ puts "The action that was being executed was: #{e.uri}"
165
+ puts "The request had a body: #{e.request_body}" unless e.request_body.nil?
166
+ end
167
+ ```
@@ -0,0 +1,5 @@
1
+ module Sharepoint
2
+ module Data
3
+
4
+ end
5
+ end
@@ -0,0 +1,34 @@
1
+ module Sharepoint
2
+ class Error < StandardError; end
3
+
4
+ class RequestError < Error; end
5
+ class DataError < Error
6
+ def initialize data, uri = nil, body = nil
7
+ @data = data['error']
8
+ @uri = uri
9
+ @body = body
10
+ end
11
+
12
+ def lang ; @data['message']['lang'] ; end
13
+ def message ; @data['message']['value'] ; end
14
+ def code ; @data['code'] ; end
15
+ def uri ; @uri ; end
16
+ def request_body ; @body ; end
17
+ end
18
+
19
+ # @deprecated Use DataError instead
20
+ SPException = DataError
21
+ deprecate_constant :SPException
22
+
23
+ class UnsupportedType < Error
24
+ attr_accessor :type_name
25
+
26
+ def initialize type_name
27
+ @type_name = type_name
28
+ end
29
+
30
+ def message
31
+ "unsupported type '#{@type_name}'"
32
+ end
33
+ end
34
+ end
@@ -1,4 +1,6 @@
1
+ require 'sharepoint-errors'
1
2
  require 'open-uri'
3
+ require 'securerandom'
2
4
 
3
5
  module Sharepoint
4
6
  class Folder < Sharepoint::Object
@@ -24,6 +26,12 @@ module Sharepoint
24
26
  body = { '__metadata' => { 'type' => 'SP.Folder' }, 'ServerRelativeUrl' => name.to_s }
25
27
  @site.query :post, uri, body.to_json
26
28
  end
29
+
30
+ def add_file_via_streaming name, file
31
+ add_file name, nil
32
+ spo_file = file_from_name name
33
+ spo_file.upload_file_via_streaming file
34
+ end
27
35
  end
28
36
 
29
37
  class File < Sharepoint::Object
@@ -60,6 +68,24 @@ module Sharepoint
60
68
  file.write content
61
69
  end
62
70
  end
71
+
72
+ def upload_file_via_streaming file
73
+ uuid = SecureRandom.uuid
74
+ bytes_written = 0
75
+ ::File.open(file) do |fh|
76
+ while data = fh.read(10 * 1024 * 1024) do
77
+ uri = (bytes_written == 0) ? "#{__metadata['uri']}/startupload(uploadId=guid'#{uuid}')" : "#{__metadata['uri']}/continueupload(uploadId=guid'#{uuid}',fileOffset=#{bytes_written})"
78
+ result = @site.query :post, uri, data, skip_json: true
79
+ new_position = (JSON.parse(result).dig('d', 'ContinueUpload') || JSON.parse(result).dig('d', 'StartUpload')).to_i
80
+ bytes_written += data.size
81
+ if new_position != bytes_written
82
+ raise Sharepoint::Error.new("Streamed #{bytes_written} bytes data, but sharepoint reports position #{new_position}")
83
+ end
84
+ end
85
+ end
86
+ uri = "#{__metadata['uri']}/finishupload(uploadId=guid'#{uuid}',fileOffset=#{bytes_written})"
87
+ result = @site.query :post, uri, nil, skip_json: true
88
+ end
63
89
  end
64
90
 
65
91
  class FileVersion < Sharepoint::Object
@@ -113,7 +113,7 @@ module Sharepoint
113
113
  item_id = response['d']['ID']
114
114
  @site.query :get, "#{site_url}_api/#{__metadata['id']}/items(#{item_id})"
115
115
  else
116
- raise Sharepoint::SPException.new response, action, payload
116
+ raise Sharepoint::DataError.new response, action, payload
117
117
  end
118
118
  end
119
119
 
@@ -1,24 +1,11 @@
1
1
  require 'curb'
2
2
  require 'json'
3
+ require 'sharepoint-errors'
3
4
  require 'sharepoint-session'
4
5
  require 'sharepoint-object'
5
6
  require 'sharepoint-types'
6
7
 
7
8
  module Sharepoint
8
- class SPException < Exception
9
- def initialize data, uri = nil, body = nil
10
- @data = data['error']
11
- @uri = uri
12
- @body = body
13
- end
14
-
15
- def lang ; @data['message']['lang'] ; end
16
- def message ; @data['message']['value'] ; end
17
- def code ; @data['code'] ; end
18
- def uri ; @uri ; end
19
- def request_body ; @body ; end
20
- end
21
-
22
9
  class Site
23
10
  attr_reader :server_url
24
11
  attr_accessor :url, :protocol
@@ -80,14 +67,16 @@ module Sharepoint
80
67
  @session.send :curl, curl unless not @session.methods.include? :curl
81
68
  block.call curl unless block.nil?
82
69
  end
83
- unless skip_json || (result.body_str.nil? || result.body_str.empty?)
70
+ if !(skip_json || (result.body_str.nil? || result.body_str.empty?))
84
71
  begin
85
72
  data = JSON.parse result.body_str
86
- raise Sharepoint::SPException.new data, uri, body unless data['error'].nil?
73
+ raise Sharepoint::DataError.new data, uri, body unless data['error'].nil?
87
74
  make_object_from_response data
88
75
  rescue JSON::ParserError => e
89
- raise Exception.new("Exception with body=#{body}, e=#{e.inspect}, #{e.backtrace.inspect}, response=#{result.body_str}")
76
+ raise Sharepoint::RequestError.new("Exception with body=#{body}, e=#{e.inspect}, #{e.backtrace.inspect}, response=#{result.body_str}")
90
77
  end
78
+ elsif result.status.to_i >= 400
79
+ raise Sharepoint::RequestError.new("#{method.to_s.upcase} #{uri} responded with #{result.status}")
91
80
  else
92
81
  result.body_str
93
82
  end
@@ -119,10 +108,10 @@ module Sharepoint
119
108
  type_parts = type_name.split '.'
120
109
  type_name = type_parts.pop
121
110
  constant = Sharepoint
122
- type_parts.each do |part| constant = constant.const_get part end
111
+ type_parts.each do |part| constant = constant.const_get(part, false) end
123
112
 
124
- klass = constant.const_get type_name rescue nil
125
- if klass
113
+ if constant.const_defined? type_name
114
+ klass = constant.const_get type_name rescue nil
126
115
  klass.new self, data
127
116
  else
128
117
  Sharepoint::GenericSharepointObject.new type_name, self, data
@@ -28,12 +28,11 @@ module Sharepoint
28
28
  end
29
29
 
30
30
  class Session
31
- class ConnexionToStsFailed < Exception ; end
32
- class ConnexionToSharepointFailed < Exception; end
33
- class UnknownAuthenticationError < Exception; end
34
- class AuthenticationFailed < Exception
35
- def initialize message ; super message ; end
36
- end
31
+ class Error < Sharepoint::Error; end
32
+ class ConnexionToStsFailed < Sharepoint::Session::Error; end
33
+ class ConnexionToSharepointFailed < Sharepoint::Session::Error; end
34
+ class UnknownAuthenticationError < Sharepoint::Session::Error; end
35
+ class AuthenticationFailed < Sharepoint::Session::Error; end
37
36
 
38
37
  attr_accessor :site
39
38
 
@@ -1,18 +1,6 @@
1
1
  require 'sharepoint-object'
2
2
 
3
3
  module Sharepoint
4
- class UnsupportedType < ::Exception
5
- attr_accessor :type_name
6
-
7
- def initialize type_name
8
- @type_name = type_name
9
- end
10
-
11
- def message
12
- "unsupported type '#{@type_name}'"
13
- end
14
- end
15
-
16
4
  module Type
17
5
  def initialize site, data = nil
18
6
  data ||= Hash.new
@@ -28,6 +16,7 @@ require 'sharepoint-users'
28
16
  require 'sharepoint-lists'
29
17
  require 'sharepoint-files'
30
18
  require 'sharepoint-fields'
19
+ require 'sharepoint-data'
31
20
  require 'date'
32
21
 
33
22
  module Sharepoint
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sharepoint-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Martin Moro
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-11 00:00:00.000000000 Z
11
+ date: 2021-01-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: curb
@@ -36,6 +36,9 @@ executables: []
36
36
  extensions: []
37
37
  extra_rdoc_files: []
38
38
  files:
39
+ - README.md
40
+ - lib/sharepoint-data.rb
41
+ - lib/sharepoint-errors.rb
39
42
  - lib/sharepoint-fields.rb
40
43
  - lib/sharepoint-files.rb
41
44
  - lib/sharepoint-http-auth.rb
@@ -53,7 +56,7 @@ homepage: https://github.com/Plaristote/sharepoint-ruby
53
56
  licenses:
54
57
  - BSD
55
58
  metadata: {}
56
- post_install_message:
59
+ post_install_message:
57
60
  rdoc_options: []
58
61
  require_paths:
59
62
  - lib
@@ -68,9 +71,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
68
71
  - !ruby/object:Gem::Version
69
72
  version: '0'
70
73
  requirements: []
71
- rubyforge_project:
74
+ rubyforge_project:
72
75
  rubygems_version: 2.7.9
73
- signing_key:
76
+ signing_key:
74
77
  specification_version: 4
75
78
  summary: sharepoint client
76
79
  test_files: []