google_drive 1.0.4 → 1.0.5

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.
@@ -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