ruby-egnyte 0.1.6

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.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/Gemfile +5 -0
  4. data/LICENSE.txt +23 -0
  5. data/README.markdown +113 -0
  6. data/Rakefile +4 -0
  7. data/egnyte.gemspec +32 -0
  8. data/includes/cacert.pem +3849 -0
  9. data/lib/egnyte.rb +25 -0
  10. data/lib/egnyte/client.rb +11 -0
  11. data/lib/egnyte/errors.rb +28 -0
  12. data/lib/egnyte/file.rb +51 -0
  13. data/lib/egnyte/folder.rb +112 -0
  14. data/lib/egnyte/folder_structure.rb +13 -0
  15. data/lib/egnyte/group.rb +185 -0
  16. data/lib/egnyte/helper.rb +41 -0
  17. data/lib/egnyte/item.rb +43 -0
  18. data/lib/egnyte/link.rb +109 -0
  19. data/lib/egnyte/permission.rb +181 -0
  20. data/lib/egnyte/session.rb +197 -0
  21. data/lib/egnyte/user.rb +207 -0
  22. data/lib/egnyte/version.rb +3 -0
  23. data/spec/file_spec.rb +71 -0
  24. data/spec/fixtures/folder_listing_no_files.json +12 -0
  25. data/spec/fixtures/group/group_all.json +17 -0
  26. data/spec/fixtures/group/group_by_parameter.json +10 -0
  27. data/spec/fixtures/group/group_by_parameter_empty.json +7 -0
  28. data/spec/fixtures/group/group_create.json +1 -0
  29. data/spec/fixtures/link/link.json +1 -0
  30. data/spec/fixtures/link/link_create.json +1 -0
  31. data/spec/fixtures/link/link_list.json +1 -0
  32. data/spec/fixtures/link/link_list_empty.json +1 -0
  33. data/spec/fixtures/list_file.json +27 -0
  34. data/spec/fixtures/list_folder.json +23 -0
  35. data/spec/fixtures/permission/permission_list.json +1 -0
  36. data/spec/fixtures/user/user_all.json +1007 -0
  37. data/spec/fixtures/user/user_by_email.json +27 -0
  38. data/spec/fixtures/user/user_create.json +20 -0
  39. data/spec/fixtures/user/user_find.json +20 -0
  40. data/spec/fixtures/user/user_update.json +20 -0
  41. data/spec/folder_spec.rb +207 -0
  42. data/spec/group_spec.rb +166 -0
  43. data/spec/helper_spec.rb +30 -0
  44. data/spec/links_spec.rb +156 -0
  45. data/spec/permissions_spec.rb +98 -0
  46. data/spec/spec_helper.rb +17 -0
  47. data/spec/user_spec.rb +212 -0
  48. metadata +260 -0
@@ -0,0 +1,43 @@
1
+ module Egnyte
2
+ class Item
3
+
4
+ attr_accessor :session
5
+
6
+ def initialize(data, session)
7
+ @data = data
8
+ @session = session
9
+ end
10
+
11
+ def method_missing(method, *args, &block)
12
+ @data[method.to_s]
13
+ end
14
+
15
+ def update_data(data)
16
+ @data = @data.update(data)
17
+ self
18
+ end
19
+
20
+ # mode can be either fs, or fs-content.
21
+ def fs_path(mode='fs')
22
+ Egnyte::Item.fs_path(@session, mode)
23
+ end
24
+
25
+ def self.fs_path(session, mode='fs')
26
+ "https://#{session.domain}.#{EGNYTE_DOMAIN}/#{session.api}/v1/#{mode}/"
27
+ end
28
+
29
+ def move_or_copy(destination_path, action)
30
+ item_path = "#{fs_path}#{Egnyte::Helper.normalize_path(path)}"
31
+ @session.post(item_path, { action: action, destination: destination_path }.to_json, return_parsed_response=true)
32
+ end
33
+
34
+ def move(destination_path)
35
+ move_or_copy(destination_path, 'move')
36
+ end
37
+
38
+ def copy(destination_path)
39
+ move_or_copy(destination_path, 'copy')
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,109 @@
1
+ module Egnyte
2
+
3
+ class Client
4
+
5
+ def links
6
+ Link::all(@session)
7
+ end
8
+
9
+ def links_where(params)
10
+ Link::where(@session, params)
11
+ end
12
+
13
+ def link(id)
14
+ Link::find(@session, id)
15
+ end
16
+
17
+ def create_link(params)
18
+ Link::create(@session, params)
19
+ end
20
+
21
+ def delete_link(id)
22
+ Link::delete(@session, id)
23
+ end
24
+
25
+ end
26
+
27
+ class Link
28
+
29
+ @@required_attributes = ['path', 'type', 'accessibility']
30
+ attr_accessor :path, :type, :accessibility, :send_email, :recipients, :messages, :copy_me, :notify, :link_to_current, :expiry_date, :expiry_clicks, :add_filename, :creation_date
31
+ attr_reader :id
32
+
33
+ def initialize(session, params)
34
+ @session = session
35
+ params.each do |k,v|
36
+ instance_variable_set("@#{k}", v)
37
+ end
38
+ end
39
+
40
+ def self.all(session)
41
+ self.where(session)
42
+ end
43
+
44
+ def self.create(session, params)
45
+ link = self.new(session, params)
46
+ link.save
47
+ end
48
+
49
+ def self.find(session, id)
50
+ response = session.get("#{self.link_path(session)}/#{id}", return_parsed_response=true)
51
+ self.new(session, response)
52
+ end
53
+
54
+ def self.where(session, params=nil)
55
+ url = self.link_path(session)
56
+ url += Egnyte::Helper.params_to_s(params) if params
57
+ parsed_body = session.get(url)
58
+ parsed_body["ids"].nil? ? [] : parsed_body["ids"]
59
+ end
60
+
61
+ def save
62
+ raise Egnyte::MissingAttribute.new(missing_attributes) unless valid?
63
+ response = @session.post(link_path, to_json, return_parsed_response=true)
64
+ link = Egnyte::Link.find(@session, response['links'].first['id'])
65
+ link.instance_variables.each do |ivar|
66
+ instance_variable_set(ivar, link.instance_variable_get(ivar))
67
+ end
68
+ self
69
+ end
70
+
71
+ def delete
72
+ Egnyte::Link.delete(@session, @id)
73
+ end
74
+
75
+ def self.delete(session, id)
76
+ session.delete("#{self.link_path(session)}/#{id}", return_parsed_response=false)
77
+ end
78
+
79
+ def valid?
80
+ return missing_attributes.size < 1
81
+ end
82
+
83
+ def missing_attributes
84
+ missing = @@required_attributes.collect do |param|
85
+ param unless instance_variable_get("@#{param}")
86
+ end
87
+ missing.compact
88
+ end
89
+
90
+ def to_json
91
+ hash = {}
92
+ instance_variables.each do |iv|
93
+ next if [:@session, :@client].include? iv
94
+ next if instance_variable_get(iv) == nil
95
+ hash[iv.to_s[1..-1]] = instance_variable_get(iv)
96
+ end
97
+ hash.to_json
98
+ end
99
+
100
+ def link_path
101
+ Egnyte::Link.link_path(@session)
102
+ end
103
+
104
+ def self.link_path(session)
105
+ "https://#{session.domain}.#{EGNYTE_DOMAIN}/#{session.api}/v1/links"
106
+ end
107
+
108
+ end
109
+ end
@@ -0,0 +1,181 @@
1
+ module Egnyte
2
+
3
+ class Permission
4
+
5
+ attr_accessor :data
6
+ ### Representative Structure of @data
7
+ # {
8
+ # 'users': {
9
+ # 'jsmith': 'Full',
10
+ # 'jdoe': 'Editor'
11
+ # },
12
+ # 'groups': {
13
+ # 'employees': 'Full',
14
+ # 'partners': 'Viewer'
15
+ # }
16
+ # }
17
+ @@valid_perm_levels = ["None", "Viewer", "Editor", "Full", "Owner"]
18
+
19
+ def initialize(permissions_hash={})
20
+ raise Egnyte::InvalidParameters unless (permissions_hash.empty? or permissions_hash['users'] or permissions_hash['groups'])
21
+ @data = empty_permissions_hash
22
+ merge!(permissions_hash)
23
+ end
24
+
25
+ def merge(new_perm_set)
26
+ old_perm_set = @data.dup
27
+ new_perm_set = new_perm_set.data if new_perm_set.class == Egnyte::Permission
28
+ raise Egnyte::InvalidParameters unless new_perm_set.class == Hash
29
+ new_perm_set.each do |type, perms_hash|
30
+ perms_hash.each do |username, permission|
31
+ permission.capitalize!
32
+ old_perm_set[type][username] = permission if ["None", "Viewer", "Editor", "Full", "Owner"].include? permission
33
+ end
34
+ end
35
+ old_perm_set
36
+ end
37
+
38
+ def merge!(new_perm_set)
39
+ @data = merge(new_perm_set)
40
+ end
41
+
42
+ def empty_permissions_hash
43
+ Egnyte::Permission.empty_permissions_hash
44
+ end
45
+
46
+ def self.empty_permissions_hash
47
+ { 'users' => {}, 'groups' => {} }
48
+ end
49
+
50
+ def self.build_from_api_listing(json_listing)
51
+ perm = empty_permissions_hash
52
+ json_listing.each do |type, data|
53
+ data.each do |item|
54
+ perm[type][item["subject"]] = item["permission"]
55
+ end
56
+ end
57
+ Egnyte::Permission.new(perm)
58
+ end
59
+
60
+ def self.folder_permissions(session, path, params=nil)
61
+ path = Egnyte::Helper.normalize_path(path)
62
+ path += Egnyte::Helper.params_to_filter_string(params) if params
63
+ response = session.get("#{self.permission_path(session)}/#{path}")
64
+ self.build_from_api_listing(response)
65
+ end
66
+
67
+ def self.inherited_permissions(session, path, params=nil)
68
+ path = Egnyte::Helper.normalize_path(path)
69
+ path = path.split('/')[0..-2].join('/')
70
+ self.folder_permissions(session, path, params)
71
+ end
72
+
73
+ def self.explicit_permissions(session, path, params=nil)
74
+ inherited = self.inherited_permissions(session, path, params).data
75
+ permissions = self.folder_permissions(session, path, params).data
76
+ explicit = self.empty_permissions_hash
77
+
78
+ #filter out permissions that exist in the parent folder's permissions
79
+ permissions.each do |type, perm|
80
+ perm.each do |k,v|
81
+ explicit[type][k] = v unless inherited[type][k] == v
82
+ end
83
+ end
84
+ self.new(explicit)
85
+ end
86
+
87
+ def self.permission_path(session)
88
+ "https://#{session.domain}.#{EGNYTE_DOMAIN}/#{session.api}/v1/perms/folder"
89
+ end
90
+
91
+ def valid?
92
+ return @data['users'].class == Hash && @data['groups'].class == Hash
93
+ end
94
+
95
+ def has_data?
96
+ return @data['users'].size > 0 || @data['groups'].size > 0
97
+ end
98
+
99
+ def empty?
100
+ return !has_data?
101
+ end
102
+
103
+ def to_hash
104
+ @data
105
+ end
106
+
107
+ def to_json
108
+ to_hash.to_json
109
+ end
110
+
111
+ def to_s
112
+ to_json
113
+ end
114
+
115
+ def self.transfrom_by_perm_level(permission_object)
116
+ perm_type_hash = {
117
+ 'users' => { "None" => [], "Viewer" => [], "Editor" => [], "Full" => [], "Owner" => [] },
118
+ 'groups' => { "None" => [], "Viewer" => [], "Editor" => [], "Full" => [], "Owner" => [] }
119
+ }
120
+ permission_object.data.each do |type, perm|
121
+ perm.each do |k,v|
122
+ perm_type_hash[type][v] << k
123
+ end
124
+ end
125
+ perm_type_hash
126
+ end
127
+
128
+ def self.apply(session, permission_object, target_path)
129
+ if permission_object.valid? and permission_object.has_data?
130
+ permissions_set = transfrom_by_perm_level(permission_object)
131
+ ["None", "Viewer", "Editor", "Full", "Owner"].each do |level|
132
+ tmp_hash = {}
133
+ tmp_hash['users'] = permissions_set['users'][level] unless permissions_set['users'].nil?
134
+ tmp_hash['groups'] = permissions_set['groups'][level] unless permissions_set['groups'].nil?
135
+ tmp_hash['permission'] = level
136
+ unless tmp_hash['users'].nil? and tmp_hash['groups'].nil?
137
+ unless tmp_hash['users'].empty? and tmp_hash['groups'].empty?
138
+ session.post("#{self.permission_path(session)}/#{target_path}", tmp_hash.to_json, false)
139
+ end
140
+ end
141
+ end
142
+ "Permissions set on #{target_path}: #{permission_object.to_hash}"
143
+ end
144
+ end
145
+
146
+ def ==(other_perm_object)
147
+ @data == other_perm_object.data
148
+ end
149
+
150
+ def diff(other_perm_object)
151
+ only_originial = Egnyte::Permission.new
152
+ common_perms = Egnyte::Permission.new
153
+ only_other = Egnyte::Permission.new
154
+ discrepancies = {'original' => Egnyte::Permission.new, 'other' => Egnyte::Permission.new}
155
+
156
+ # find whether permission is only in the self's set or is common between self and other
157
+ @data.each do |level, perm_hash|
158
+ perm_hash.each do |item, permission|
159
+ if other_perm_object.data[level][item].nil?
160
+ only_originial.data[level][item] = permission
161
+ elsif other_perm_object.data[level][item] != permission
162
+ discrepancies['original'].data[level][item] = permission
163
+ discrepancies['other'].data[level][item] = other_perm_object.data[level][item]
164
+ end
165
+ common_perms.data[level][item] = permission if other_perm_object.data[level][item] == permission
166
+ end
167
+ end
168
+
169
+ # find whether permission is in the other_perm_object
170
+ other_perm_object.data.each do |level, perm_hash|
171
+ perm_hash.each do |item, permission|
172
+ only_other.data[level][item] = permission if @data[level][item].nil? || @data[level][item] != permission
173
+ end
174
+ end
175
+
176
+ [only_originial, common_perms, only_other, discrepancies]
177
+ end
178
+
179
+ end
180
+
181
+ end
@@ -0,0 +1,197 @@
1
+ require 'os'
2
+
3
+ module Egnyte
4
+ class Session
5
+
6
+ attr_accessor :domain, :api, :username
7
+ attr_reader :access_token
8
+
9
+ def initialize(opts, strategy=:implicit, backoff=0.5)
10
+
11
+ @strategy = strategy # the authentication strategy to use.
12
+ raise Egnyte::UnsupportedAuthStrategy unless [:implicit, :password].include? @strategy
13
+
14
+ @backoff = backoff # only two requests are allowed a second by Egnyte.
15
+ @api = 'pubapi' # currently we only support the public API.
16
+
17
+ @username = opts[:username]
18
+
19
+ # the domain of the egnyte account to interact with.
20
+ raise Egnyte::DomainRequired unless @domain = opts[:domain]
21
+
22
+ @client = OAuth2::Client.new(opts[:key], nil, {
23
+ :site => "https://#{@domain}.#{EGNYTE_DOMAIN}",
24
+ :authorize_url => "/puboauth/token",
25
+ :token_url => "/puboauth/token"
26
+ })
27
+
28
+ if @strategy == :implicit
29
+ @access_token = OAuth2::AccessToken.new(@client, opts[:access_token]) if opts[:access_token]
30
+ elsif @strategy == :password
31
+ if opts[:access_token]
32
+ @access_token = OAuth2::AccessToken.new(@client, opts[:access_token])
33
+ else
34
+ raise Egnyte::OAuthUsernameRequired unless @username
35
+ raise Egnyte::OAuthPasswordRequired unless opts[:password]
36
+ if true #OS.windows?
37
+ body = {
38
+ :client_id => opts[:key],
39
+ :username => @username,
40
+ :password => opts[:password],
41
+ :grant_type => 'password'
42
+ }.map {|k,v| "#{k}=#{v}"}.join("&")
43
+ url = "https://#{@domain}.#{EGNYTE_DOMAIN}/puboauth/token"
44
+ response = login_post(url, body, return_parsed_response=true)
45
+ @access_token = OAuth2::AccessToken.new(@client, response["access_token"])
46
+ else
47
+ @access_token = @client.password.get_token(@username, opts[:password])
48
+ end
49
+ end
50
+ @username = info["username"] unless @username
51
+ end
52
+
53
+ end
54
+
55
+ def info
56
+ information
57
+ end
58
+
59
+ def information
60
+ get("https://#{@domain}.#{EGNYTE_DOMAIN}/#{@api}/v1/userinfo", return_parsed_response=true)
61
+ end
62
+
63
+ def authorize_url(redirect_uri)
64
+ @client.implicit.authorize_url(:redirect_uri => redirect_uri)
65
+ end
66
+
67
+ def create_access_token(token)
68
+ @access_token = OAuth2::AccessToken.new(@client, token) if @strategy == :implicit
69
+ end
70
+
71
+ def get(url, return_parsed_response=true)
72
+ uri = URI.parse(Egnyte::Helper.encode_url(url))
73
+ request = Net::HTTP::Get.new( uri.request_uri )
74
+ resp = request( uri, request, return_parsed_response )
75
+ end
76
+
77
+ def delete(url, return_parsed_response=true)
78
+ uri = URI.parse(Egnyte::Helper.encode_url(url))
79
+ request = Net::HTTP::Delete.new( uri.request_uri )
80
+ resp = request( uri, request, return_parsed_response )
81
+ end
82
+
83
+ def post(url, body, return_parsed_response=true)
84
+ uri = URI.parse(Egnyte::Helper.encode_url(url))
85
+ request = Net::HTTP::Post.new(uri.request_uri)
86
+ request.body = body
87
+ request.content_type = "application/json"
88
+ resp = request(uri, request, return_parsed_response)
89
+ end
90
+
91
+ def login_post(url, body, return_parsed_response=true)
92
+ uri = URI.parse(Egnyte::Helper.encode_url(url))
93
+ request = Net::HTTP::Post.new(uri.request_uri)
94
+ request.body = body
95
+ request.content_type = "application/x-www-form-urlencoded"
96
+ resp = request(uri, request, return_parsed_response)
97
+ end
98
+
99
+ def patch(url, body, return_parsed_response=true)
100
+ uri = URI.parse(Egnyte::Helper.encode_url(url))
101
+ request = Net::HTTP::Patch.new(uri.request_uri)
102
+ request.body = body
103
+ request.content_type = "application/json"
104
+ resp = request(uri, request, return_parsed_response)
105
+ end
106
+
107
+ def put(url, body, return_parsed_response=true)
108
+ uri = URI.parse(Egnyte::Helper.encode_url(url))
109
+ request = Net::HTTP::Put.new(uri.request_uri)
110
+ request.body = body
111
+ request.content_type = "application/json"
112
+ resp = request(uri, request, return_parsed_response)
113
+ end
114
+
115
+ def multipart_post(url, filename, data, return_parsed_response=true)
116
+ uri = URI.parse(Egnyte::Helper.encode_url(url))
117
+
118
+ request = Net::HTTP::Post.new(uri.request_uri)
119
+ request.body = data.read
120
+ request.content_type = 'application/binary'
121
+
122
+ resp = request(uri, request, return_parsed_response)
123
+ end
124
+
125
+ # perform a streaming download of a file
126
+ # rather than in-memory.
127
+ def streaming_download(url, opts)
128
+ uri = URI.parse(Egnyte::Helper.encode_url(url))
129
+
130
+ params = {
131
+ :content_length_proc => opts[:content_length_proc],
132
+ :progress_proc => opts[:progress_proc],
133
+ 'Authorization' => "Bearer #{@access_token.token}"
134
+ }
135
+
136
+ open(uri, params)
137
+ end
138
+
139
+ private
140
+
141
+ def request(uri, request, return_parsed_response=true)
142
+ http = Net::HTTP.new(uri.host, uri.port)
143
+ http.use_ssl = true
144
+ if OS.windows? # Use provided certificate on Windows where gem doesn't have access to a cert store.
145
+ http.cert_store = OpenSSL::X509::Store.new
146
+ http.cert_store.set_default_paths
147
+ http.cert_store.add_file("#{::File.dirname(__FILE__)}/../../includes/cacert.pem")
148
+ end
149
+ #http.set_debug_output($stdout)
150
+
151
+ unless request.content_type == "application/x-www-form-urlencoded"
152
+ request.add_field('Authorization', "Bearer #{@access_token.token}")
153
+ end
154
+
155
+ response = http.request(request)
156
+
157
+ # Egnyte throttles requests to
158
+ # two requests per second by default.
159
+ sleep(@backoff)
160
+
161
+ # puts "#{response.code.to_i} ||||| #{response.body}"
162
+
163
+
164
+ return_value = return_parsed_response ? parse_response_body(response.body) : response
165
+ parse_response_code(response.code.to_i, return_value)
166
+
167
+ return_value
168
+ end
169
+
170
+ def parse_response_code(status, response)
171
+ case status
172
+ when 400
173
+ raise BadRequest.new(response)
174
+ when 401
175
+ raise NotAuthorized.new(response)
176
+ when 403
177
+ raise InsufficientPermissions.new(response)
178
+ when 404
179
+ raise RecordNotFound.new(response)
180
+ when 405
181
+ raise DuplicateRecordExists.new(response)
182
+ when 413
183
+ raise FileSizeExceedsLimit.new(response)
184
+ end
185
+
186
+ # Handle all other request errors.
187
+ raise RequestError.new(response) if status >= 400
188
+ end
189
+
190
+ def parse_response_body(body)
191
+ JSON.parse(body)
192
+ rescue
193
+ {}
194
+ end
195
+
196
+ end
197
+ end