google_drive 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,31 +0,0 @@
1
- # Author: Hiroshi Ichikawa <http://gimite.net/>
2
- # The license of this source is "New BSD Licence"
3
-
4
- require "google_drive_v0/basic_fetcher"
5
-
6
-
7
- module GoogleDriveV0
8
-
9
- class ClientLoginFetcher < BasicFetcher #:nodoc:
10
-
11
- def initialize(auth_tokens, proxy)
12
- super(proxy)
13
- @auth_tokens = auth_tokens
14
- end
15
-
16
- attr_accessor(:auth_tokens)
17
-
18
- private
19
-
20
- def auth_header(auth)
21
- token = auth == :none ? nil : @auth_tokens[auth]
22
- if token
23
- return {"Authorization" => "GoogleLogin auth=#{token}"}
24
- else
25
- return {}
26
- end
27
- end
28
-
29
- end
30
-
31
- end
@@ -1,167 +0,0 @@
1
- # Author: Hiroshi Ichikawa <http://gimite.net/>
2
- # The license of this source is "New BSD Licence"
3
-
4
- require "google_drive_v0/util"
5
- require "google_drive_v0/error"
6
- require "google_drive_v0/spreadsheet"
7
-
8
-
9
- module GoogleDriveV0
10
-
11
- # Use GoogleDriveV0::Session#root_collection, GoogleDriveV0::Collection#subcollections,
12
- # or GoogleDriveV0::Session#collection_by_url to get GoogleDriveV0::Collection object.
13
- class Collection < GoogleDriveV0::File
14
-
15
- include(Util)
16
-
17
- ROOT_URL = "#{DOCS_BASE_URL}/folder%3Aroot" #:nodoc:
18
-
19
- alias collection_feed_url document_feed_url
20
-
21
- def contents_url
22
- if self.root?
23
- # The root collection doesn't have document feed.
24
- return concat_url(ROOT_URL, "/contents")
25
- else
26
- return self.document_feed_entry_internal.css(
27
- "content[type='application/atom+xml;type=feed']")[0]["src"]
28
- end
29
- end
30
-
31
- # Title of the collection.
32
- #
33
- # Set <tt>params[:reload]</tt> to true to force reloading the title.
34
- def title(params = {})
35
- if self.root?
36
- # The root collection doesn't have document feed.
37
- return nil
38
- else
39
- return super
40
- end
41
- end
42
-
43
- def resource_id
44
- return self.root? ? nil : super
45
- end
46
-
47
- # Adds the given GoogleDriveV0::File to the collection.
48
- def add(file)
49
- header = {"GData-Version" => "3.0", "Content-Type" => "application/atom+xml;charset=utf-8"}
50
- xml = <<-"EOS"
51
- <entry xmlns="http://www.w3.org/2005/Atom">
52
- <id>#{h(file.document_feed_url)}</id>
53
- </entry>
54
- EOS
55
- @session.request(
56
- :post, self.contents_url, :data => xml, :header => header, :auth => :writely)
57
- return nil
58
- end
59
-
60
- # Creates a sub-collection with given title. Returns GoogleDriveV0::Collection object.
61
- def create_subcollection(title)
62
- header = {"GData-Version" => "3.0", "Content-Type" => "application/atom+xml;charset=utf-8"}
63
- xml = <<-EOS
64
- <entry xmlns="http://www.w3.org/2005/Atom">
65
- <category scheme="http://schemas.google.com/g/2005#kind"
66
- term="http://schemas.google.com/docs/2007#folder"/>
67
- <title>#{h(title)}</title>
68
- </entry>
69
- EOS
70
- doc = @session.request(
71
- :post, contents_url, :data => xml, :header => header, :auth => :writely)
72
- return @session.entry_element_to_file(doc)
73
- end
74
-
75
- # Removes the given GoogleDriveV0::File from the collection.
76
- def remove(file)
77
- url = to_v3_url("#{contents_url}/#{file.resource_id}")
78
- @session.request(:delete, url, :auth => :writely, :header => {"If-Match" => "*"})
79
- end
80
-
81
- # Returns true if this is a root collection
82
- def root?
83
- self.document_feed_url == ROOT_URL
84
- end
85
-
86
- # Returns all the files (including spreadsheets, documents, subcollections) in the collection.
87
- #
88
- # You can specify query parameters described at
89
- # https://developers.google.com/google-apps/documents-list/#getting_a_list_of_documents_and_files
90
- #
91
- # e.g.
92
- #
93
- # # Gets all the files in collection, including subcollections.
94
- # collection.files
95
- #
96
- # # Gets only files with title "hoge".
97
- # collection.files("title" => "hoge", "title-exact" => "true")
98
- def files(params = {})
99
- return files_with_type(nil, params)
100
- end
101
-
102
- alias contents files
103
-
104
- # Returns all the spreadsheets in the collection.
105
- def spreadsheets(params = {})
106
- return files_with_type("spreadsheet", params)
107
- end
108
-
109
- # Returns all the Google Docs documents in the collection.
110
- def documents(params = {})
111
- return files_with_type("document", params)
112
- end
113
-
114
- # Returns all its subcollections.
115
- def subcollections(params = {})
116
- return files_with_type("folder", params)
117
- end
118
-
119
- # Returns a file (can be a spreadsheet, document, subcollection or other files) in the
120
- # collection which exactly matches +title+ as GoogleDriveV0::File.
121
- # Returns nil if not found. If multiple collections with the +title+ are found, returns
122
- # one of them.
123
- #
124
- # If given an Array, does a recursive subcollection traversal.
125
- def file_by_title(title)
126
- return file_by_title_with_type(title, nil)
127
- end
128
-
129
- # Returns its subcollection whose title exactly matches +title+ as GoogleDriveV0::Collection.
130
- # Returns nil if not found. If multiple collections with the +title+ are found, returns
131
- # one of them.
132
- #
133
- # If given an Array, does a recursive subcollection traversal.
134
- def subcollection_by_title(title)
135
- return file_by_title_with_type(title, "folder")
136
- end
137
-
138
- protected
139
-
140
- def file_by_title_with_type(title, type)
141
- if title.is_a?(Array)
142
- rel_path = title
143
- if rel_path.empty?
144
- return self
145
- else
146
- parent = subcollection_by_title(rel_path[0...-1])
147
- return parent && parent.file_by_title_with_type(rel_path[-1], type)
148
- end
149
- else
150
- return files_with_type(type, "title" => title, "title-exact" => "true")[0]
151
- end
152
- end
153
-
154
- private
155
-
156
- def files_with_type(type, params = {})
157
- contents_url = self.contents_url
158
- contents_url = concat_url(contents_url, "/-/#{type}") if type
159
- contents_url = concat_url(contents_url, "?" + encode_query(params))
160
- header = {"GData-Version" => "3.0", "Content-Type" => "application/atom+xml;charset=utf-8"}
161
- doc = @session.request(:get, contents_url, :header => header, :auth => :writely)
162
- return doc.css("feed > entry").map(){ |e| @session.entry_element_to_file(e) }
163
- end
164
-
165
- end
166
-
167
- end
@@ -1,12 +0,0 @@
1
- # Author: Hiroshi Ichikawa <http://gimite.net/>
2
- # The license of this source is "New BSD Licence"
3
-
4
-
5
- module GoogleDriveV0
6
-
7
- # Raised when spreadsheets.google.com has returned error.
8
- class Error < RuntimeError
9
-
10
- end
11
-
12
- end
@@ -1,258 +0,0 @@
1
- # Author: Hiroshi Ichikawa <http://gimite.net/>
2
- # The license of this source is "New BSD Licence"
3
-
4
- require "cgi"
5
- require "stringio"
6
-
7
- require "google_drive_v0/util"
8
- require "google_drive_v0/acl"
9
-
10
-
11
- module GoogleDriveV0
12
-
13
- # A file in Google Drive, including Google Docs document/spreadsheet/presentation.
14
- #
15
- # Use GoogleDriveV0::Session#files or GoogleDriveV0::Session#file_by_title to
16
- # get this object.
17
- class File
18
-
19
- include(Util)
20
-
21
- def initialize(session, entry_or_url) #:nodoc:
22
- @session = session
23
- if !entry_or_url
24
- # TODO Delete this after editing spreadsheet.rb.
25
- @document_feed_entry = nil
26
- @document_feed_url = entry_or_url
27
- elsif entry_or_url.is_a?(String)
28
- @document_feed_entry = nil
29
- @document_feed_url = entry_or_url
30
- else
31
- @document_feed_entry = entry_or_url
32
- # This is usually equal to the URL in <link rel="self">. But the URL in
33
- # <link rel="self"> in collection feed is e.g.
34
- # https://docs.google.com/feeds/default/private/full/folder%3Aroot/contents/folder%3Axxx
35
- # and deletion of the URL doesn't delete the file itself.
36
- # So we construct the URL here using resource ID instead.
37
- @document_feed_url = "%s/%s?v=3" % [DOCS_BASE_URL, CGI.escape(self.resource_id)]
38
- end
39
- @acl = nil
40
- end
41
-
42
- # URL of feed used in document list feed API.
43
- attr_reader(:document_feed_url)
44
-
45
- # <entry> element of document list feed as Nokogiri::XML::Element.
46
- #
47
- # Set <tt>params[:reload]</tt> to true to force reloading the feed.
48
- def document_feed_entry(params = {})
49
- warn(
50
- "WARNING: GoogleDriveV0::file\#document_feed_entry is deprecated and will be removed " +
51
- "in the next version.")
52
- return self.document_feed_entry_internal(params)
53
- end
54
-
55
- def document_feed_entry_internal(params = {}) #:nodoc:
56
- if !@document_feed_entry || params[:reload]
57
- @document_feed_entry =
58
- @session.request(:get, self.document_feed_url, :auth => :writely).css("entry")[0]
59
- end
60
- return @document_feed_entry
61
- end
62
-
63
- # Resource ID.
64
- def resource_id
65
- return self.document_feed_entry_internal.css("gd|resourceId").text
66
- end
67
-
68
- # The type of resourse. e.g. "document", "spreadsheet", "folder"
69
- def resource_type
70
- return self.resource_id.split(/:/)[0]
71
- end
72
-
73
- # Title of the file.
74
- #
75
- # Set <tt>params[:reload]</tt> to true to force reloading the title.
76
- def title(params = {})
77
- return document_feed_entry_internal(params).css("title").text
78
- end
79
-
80
- # URL to view/edit the file in a Web browser.
81
- #
82
- # e.g. "https://docs.google.com/file/d/xxxx/edit"
83
- def human_url
84
- return self.document_feed_entry_internal.css("link[rel='alternate']")[0]["href"]
85
- end
86
-
87
- # ACL feed URL of the file.
88
- def acl_feed_url
89
- orig_acl_feed_url = self.document_feed_entry_internal.css(
90
- "gd|feedLink[rel='http://schemas.google.com/acl/2007#accessControlList']")[0]["href"]
91
- case orig_acl_feed_url
92
- when %r{^https?://docs.google.com/feeds/default/private/full/.*/acl(\?.*)?$}
93
- return orig_acl_feed_url
94
- when %r{^https?://docs.google.com/feeds/acl/private/full/([^\?]*)(\?.*)?$}
95
- # URL of old API version. Converts to v3 URL.
96
- return "#{DOCS_BASE_URL}/#{$1}/acl"
97
- else
98
- raise(GoogleDriveV0::Error,
99
- "ACL feed URL is in unknown format: #{orig_acl_feed_url}")
100
- end
101
- end
102
-
103
- # Content types you can specify in methods download_to_file, download_to_string,
104
- # download_to_io .
105
- def available_content_types
106
- return self.document_feed_entry_internal.css("content").map(){ |c| c["type"] }
107
- end
108
-
109
- # Downloads the file to a local file.
110
- #
111
- # e.g.
112
- # file.download_to_file("/path/to/hoge.txt")
113
- # file.download_to_file("/path/to/hoge", :content_type => "text/plain")
114
- def download_to_file(path, params = {})
115
- params = params.dup()
116
- if !params[:content_type]
117
- params[:content_type] = EXT_TO_CONTENT_TYPE[::File.extname(path).downcase]
118
- params[:content_type_is_hint] = true
119
- end
120
- open(path, "wb") do |f|
121
- download_to_io(f, params)
122
- end
123
- end
124
-
125
- # Downloads the file and returns as a String.
126
- #
127
- # e.g.
128
- # file.download_to_string() #=> "Hello world."
129
- # file.download_to_string(:content_type => "text/plain") #=> "Hello world."
130
- def download_to_string(params = {})
131
- sio = StringIO.new()
132
- download_to_io(sio, params)
133
- return sio.string
134
- end
135
-
136
- # Downloads the file and writes it to +io+.
137
- def download_to_io(io, params = {})
138
- all_contents = self.document_feed_entry_internal.css("content")
139
- if params[:content_type] && (!params[:content_type_is_hint] || all_contents.size > 1)
140
- contents = all_contents.select(){ |c| c["type"] == params[:content_type] }
141
- else
142
- contents = all_contents
143
- end
144
- if contents.size == 1
145
- url = contents[0]["src"]
146
- else
147
- if contents.empty?
148
- raise(GoogleDriveV0::Error,
149
- ("Downloading with content type %p not supported for this file. " +
150
- "Specify one of these to content_type: %p") %
151
- [params[:content_type], self.available_content_types])
152
- else
153
- raise(GoogleDriveV0::Error,
154
- ("Multiple content types are available for this file. " +
155
- "Specify one of these to content_type: %p") %
156
- [self.available_content_types])
157
- end
158
- end
159
- # TODO Use streaming if possible.
160
- body = @session.request(:get, url, :response_type => :raw, :auth => :writely)
161
- io.write(body)
162
- end
163
-
164
- # Updates the file with the content of the local file.
165
- #
166
- # e.g.
167
- # file.update_from_file("/path/to/hoge.txt")
168
- def update_from_file(path, params = {})
169
- params = {:file_name => ::File.basename(path)}.merge(params)
170
- open(path, "rb") do |f|
171
- update_from_io(f, params)
172
- end
173
- end
174
-
175
- # Updates the file with +content+.
176
- #
177
- # e.g.
178
- # file.update_from_string("Good bye, world.")
179
- def update_from_string(content, params = {})
180
- update_from_io(StringIO.new(content), params)
181
- end
182
-
183
- # Reads content from +io+ and updates the file with the content.
184
- def update_from_io(io, params = {})
185
- params = {:header => {"If-Match" => "*"}}.merge(params)
186
- initial_url = self.document_feed_entry_internal.css(
187
- "link[rel='http://schemas.google.com/g/2005#resumable-edit-media']")[0]["href"]
188
- @document_feed_entry = @session.upload_raw(
189
- :put, initial_url, io, self.title, params)
190
- end
191
-
192
- # If +permanent+ is +false+, moves the file to the trash.
193
- # If +permanent+ is +true+, deletes the file permanently.
194
- def delete(permanent = false)
195
- url = to_v3_url(self.document_feed_url)
196
- url = concat_url(url, "?delete=true") if permanent
197
- @session.request(:delete, url,
198
- :auth => :writely, :header => {"If-Match" => "*"})
199
- end
200
-
201
- # Renames title of the file.
202
- def rename(title)
203
- edit_url = self.document_feed_entry_internal.css("link[rel='edit']").first["href"]
204
- xml = <<-"EOS"
205
- <atom:entry
206
- xmlns:atom="http://www.w3.org/2005/Atom"
207
- xmlns:docs="http://schemas.google.com/docs/2007">
208
- <atom:title>#{h(title)}</atom:title>
209
- </atom:entry>
210
- EOS
211
- header = {"Content-Type" => "application/atom+xml;charset=utf-8", "If-Match" => "*"}
212
- @session.request(:put, edit_url, :data => xml, :auth => :writely, :header => header)
213
- end
214
-
215
- alias title= rename
216
-
217
- # Returns GoogleDriveV0::Acl object for the file.
218
- #
219
- # With the object, you can see and modify people who can access the file.
220
- # Modifications take effect immediately.
221
- #
222
- # Set <tt>params[:reload]</tt> to true to force reloading the data.
223
- #
224
- # e.g.
225
- # # Dumps people who have access:
226
- # for entry in file.acl
227
- # p [entry.scope_type, entry.scope, entry.role]
228
- # # => e.g. ["user", "example1@gmail.com", "owner"]
229
- # end
230
- #
231
- # # Shares the file with new people:
232
- # # NOTE: This sends email to the new people.
233
- # file.acl.push(
234
- # {:scope_type => "user", :scope => "example2@gmail.com", :role => "reader"})
235
- # file.acl.push(
236
- # {:scope_type => "user", :scope => "example3@gmail.com", :role => "writer"})
237
- #
238
- # # Changes the role of a person:
239
- # file.acl[1].role = "writer"
240
- #
241
- # # Deletes an ACL entry:
242
- # file.acl.delete(file.acl[1])
243
- def acl(params = {})
244
- if !@acl || params[:reload]
245
- @acl = Acl.new(@session, self.acl_feed_url)
246
- end
247
- return @acl
248
- end
249
-
250
- def inspect
251
- fields = {:document_feed_url => self.document_feed_url}
252
- fields[:title] = self.title if @document_feed_entry
253
- return "\#<%p %s>" % [self.class, fields.map(){ |k, v| "%s=%p" % [k, v] }.join(", ")]
254
- end
255
-
256
- end
257
-
258
- end