ruby-egnyte 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
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