middleman-google_drive 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +11 -1
- data/lib/google_drive.rb +132 -69
- data/lib/middleman-google_drive/extension.rb +36 -2
- data/lib/middleman-google_drive/version.rb +1 -1
- data/middleman-google_drive.gemspec +2 -1
- data/test/google_drive_test.rb +50 -0
- metadata +22 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2857e937b68c10de7780fa28220f3d70e6953f29
|
4
|
+
data.tar.gz: a4c19ba124ac231e4795d86047d6c8a5aafd7786
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 27ebca38276d76f625c781204b68fed14ed387a204d1c7a9543b58bb35d020548dde02cb6d04198e90bd37d5f2dc0292ae56b4fc92008d5098cc555d52d46509
|
7
|
+
data.tar.gz: 4822b82da85d3ddc9e20d963170c5802267f54e81749acb185d0d1eb31bf8ccb5965200a3410b381e8acb4bc3cdd43884fca6fbbd1b9a048f297f34d5ec109c0
|
data/Rakefile
CHANGED
@@ -1,2 +1,12 @@
|
|
1
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/clean'
|
2
5
|
|
6
|
+
Rake::TestTask.new do |t|
|
7
|
+
t.libs << 'lib'
|
8
|
+
t.test_files = FileList['test/*_test.rb']
|
9
|
+
end
|
10
|
+
|
11
|
+
desc 'Run tests'
|
12
|
+
task default: :test
|
data/lib/google_drive.rb
CHANGED
@@ -5,94 +5,65 @@ require 'google/api_client/auth/file_storage'
|
|
5
5
|
require 'google/api_client/auth/installed_app'
|
6
6
|
|
7
7
|
class GoogleDrive
|
8
|
+
attr_reader :client
|
8
9
|
def initialize
|
9
|
-
credentials = ENV['GOOGLE_DRIVE_OAUTH'] || File.expand_path(
|
10
|
+
@credentials = ENV['GOOGLE_DRIVE_OAUTH'] || File.expand_path(
|
10
11
|
'~/.google_drive_oauth2.json')
|
11
|
-
client_secrets = ENV['GOOGLE_CLIENT_SECRETS'] || File.expand_path(
|
12
|
+
@client_secrets = ENV['GOOGLE_CLIENT_SECRETS'] || File.expand_path(
|
12
13
|
'~/.google_client_secrets.json')
|
13
14
|
|
14
|
-
person = ENV['GOOGLE_OAUTH_PERSON']
|
15
|
-
issuer = ENV['GOOGLE_OAUTH_ISSUER']
|
16
|
-
key_path = ENV['GOOGLE_OAUTH_KEYFILE']
|
17
|
-
private_key = ENV['GOOGLE_OAUTH_PRIVATE_KEY']
|
15
|
+
@person = ENV['GOOGLE_OAUTH_PERSON']
|
16
|
+
@issuer = ENV['GOOGLE_OAUTH_ISSUER']
|
17
|
+
@key_path = ENV['GOOGLE_OAUTH_KEYFILE']
|
18
|
+
@private_key = ENV['GOOGLE_OAUTH_PRIVATE_KEY']
|
18
19
|
|
19
20
|
# try to read the file,
|
20
21
|
# throw errors if not readable or not found
|
21
|
-
if key_path
|
22
|
-
key = Google::APIClient::KeyUtils.load_from_pkcs12(
|
23
|
-
key_path, 'notasecret')
|
22
|
+
if @key_path
|
23
|
+
@key = Google::APIClient::KeyUtils.load_from_pkcs12(
|
24
|
+
@key_path, 'notasecret')
|
24
25
|
elsif @private_key
|
25
|
-
key = OpenSSL::PKey::RSA.new(
|
26
|
-
private_key, 'notasecret')
|
26
|
+
@key = OpenSSL::PKey::RSA.new(
|
27
|
+
@private_key, 'notasecret')
|
27
28
|
end
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
authorization: Signet::OAuth2::Client.new(
|
34
|
-
token_credential_uri: 'https://accounts.google.com/o/oauth2/token',
|
35
|
-
audience: 'https://accounts.google.com/o/oauth2/token',
|
36
|
-
person: person,
|
37
|
-
issuer: issuer,
|
38
|
-
signing_key: key,
|
39
|
-
scope: ['https://www.googleapis.com/auth/drive']
|
40
|
-
)
|
41
|
-
)
|
42
|
-
@client.authorization.fetch_access_token!
|
43
|
-
else
|
44
|
-
@client = Google::APIClient.new(
|
45
|
-
application_name: 'Middleman',
|
46
|
-
application_version: Middleman::GoogleDrive::VERSION
|
47
|
-
)
|
48
|
-
begin
|
49
|
-
file_storage = Google::APIClient::FileStorage.new(credentials)
|
50
|
-
rescue URI::InvalidURIError
|
51
|
-
File.delete credentials
|
52
|
-
file_storage = Google::APIClient::FileStorage.new(credentials)
|
53
|
-
end
|
54
|
-
if file_storage.authorization.nil?
|
55
|
-
unless File.exist? client_secrets
|
56
|
-
fail ConfigurationError, 'You need to create a client_secrets.json file and save it to ~/.google_client_secrets.json.'
|
57
|
-
end
|
58
|
-
puts 'Please login via your web browser'
|
59
|
-
client_secrets = Google::APIClient::ClientSecrets.load(client_secrets)
|
60
|
-
flow = Google::APIClient::InstalledAppFlow.new(
|
61
|
-
client_id: client_secrets.client_id,
|
62
|
-
client_secret: client_secrets.client_secret,
|
63
|
-
scope: ['https://www.googleapis.com/auth/drive']
|
64
|
-
)
|
65
|
-
@client.authorization = flow.authorize(file_storage)
|
66
|
-
else
|
67
|
-
@client.authorization = file_storage.authorization
|
68
|
-
end
|
69
|
-
end
|
30
|
+
@_files = {}
|
31
|
+
@_spreadsheets = {}
|
32
|
+
|
33
|
+
do_auth
|
70
34
|
end
|
71
35
|
|
72
|
-
def
|
73
|
-
|
74
|
-
|
75
|
-
data = {}
|
36
|
+
def find(key)
|
37
|
+
return @_files[key] unless @_files[key].nil?
|
38
|
+
|
76
39
|
drive = @client.discovered_api('drive', 'v2')
|
77
40
|
|
78
41
|
# get the file metadata
|
79
|
-
|
42
|
+
resp = @client.execute(
|
80
43
|
api_method: drive.files.get,
|
81
44
|
parameters: { fileId: key })
|
82
45
|
|
83
46
|
# die if there's an error
|
84
|
-
fail
|
47
|
+
fail GoogleDriveError, resp.error_message if resp.error?
|
48
|
+
|
49
|
+
@_files[key] = resp.data
|
50
|
+
end
|
51
|
+
|
52
|
+
def spreadsheet(key)
|
53
|
+
require 'roo'
|
54
|
+
|
55
|
+
list_resp = find(key)
|
85
56
|
|
86
57
|
# Grab the export url. We're gonna request the spreadsheet
|
87
58
|
# in excel format. Because it includes all the worksheets.
|
88
|
-
uri = list_resp
|
59
|
+
uri = list_resp['exportLinks'][
|
89
60
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
|
90
61
|
|
91
62
|
# get the export
|
92
63
|
get_resp = @client.execute(uri: uri)
|
93
64
|
|
94
65
|
# die if there's an error
|
95
|
-
fail get_resp.error_message if get_resp.error?
|
66
|
+
fail GoogleDriveError, get_resp.error_message if get_resp.error?
|
96
67
|
|
97
68
|
# get a temporary file. The export is binary, so open the tempfile in
|
98
69
|
# write binary mode
|
@@ -101,10 +72,17 @@ class GoogleDrive
|
|
101
72
|
fp.write get_resp.body
|
102
73
|
fp.close
|
103
74
|
|
104
|
-
# now open the file with Roo
|
105
|
-
|
106
|
-
|
107
|
-
|
75
|
+
# now open the file with Roo
|
76
|
+
ret = Roo::Spreadsheet.open(filename)
|
77
|
+
|
78
|
+
fp.unlink # delete our tempfile
|
79
|
+
|
80
|
+
ret
|
81
|
+
end
|
82
|
+
|
83
|
+
def prepared_spreadsheet(key)
|
84
|
+
xls = spreadsheet(key)
|
85
|
+
data = {}
|
108
86
|
xls.each_with_pagename do |title, sheet|
|
109
87
|
# if the sheet is called microcopy, copy or ends with copy, we assume
|
110
88
|
# the first column contains keys and the second contains values.
|
@@ -126,15 +104,33 @@ class GoogleDrive
|
|
126
104
|
end
|
127
105
|
else
|
128
106
|
# otherwise parse the sheet into a hash
|
129
|
-
sheet.header_line = 2 #
|
107
|
+
sheet.header_line = 2 # a bug in Roo.
|
130
108
|
data[title] = sheet.parse(headers: true)
|
131
109
|
end
|
132
110
|
end
|
133
|
-
fp.unlink # delete our tempfile
|
134
111
|
data
|
135
112
|
end
|
136
113
|
|
137
|
-
def
|
114
|
+
def doc(key, format = 'html')
|
115
|
+
doc = find(key)
|
116
|
+
|
117
|
+
# Grab the export url.
|
118
|
+
if format.to_s == 'html'
|
119
|
+
uri = doc['exportLinks']['text/html']
|
120
|
+
else
|
121
|
+
uri = doc['exportLinks']['text/plain']
|
122
|
+
end
|
123
|
+
|
124
|
+
# get the export
|
125
|
+
resp = @client.execute(uri: uri)
|
126
|
+
|
127
|
+
# die if there's an error
|
128
|
+
fail GoogleDriveError, resp.error_message if resp.error?
|
129
|
+
|
130
|
+
resp.body
|
131
|
+
end
|
132
|
+
|
133
|
+
def copy(file_id, title = nil)
|
138
134
|
drive = @client.discovered_api('drive', 'v2')
|
139
135
|
|
140
136
|
if title.nil?
|
@@ -153,7 +149,74 @@ class GoogleDrive
|
|
153
149
|
return { id: cp_resp.data['id'], url: cp_resp.data['alternateLink'] }
|
154
150
|
end
|
155
151
|
end
|
152
|
+
alias_method :copy_doc, :copy
|
153
|
+
|
154
|
+
def redo_auth
|
155
|
+
File.delete @credentials if @key.nil?
|
156
|
+
do_auth
|
157
|
+
end
|
158
|
+
|
159
|
+
def do_auth
|
160
|
+
if local?
|
161
|
+
@client = Google::APIClient.new(
|
162
|
+
application_name: 'Middleman',
|
163
|
+
application_version: Middleman::GoogleDrive::VERSION
|
164
|
+
)
|
165
|
+
begin
|
166
|
+
file_storage = Google::APIClient::FileStorage.new(@credentials)
|
167
|
+
rescue URI::InvalidURIError
|
168
|
+
File.delete @credentials
|
169
|
+
file_storage = Google::APIClient::FileStorage.new(@credentials)
|
170
|
+
end
|
171
|
+
if file_storage.authorization.nil?
|
172
|
+
unless File.exist? @client_secrets
|
173
|
+
fail ConfigurationError, 'You need to create a client_secrets.json file and save it to ~/.google_client_secrets.json.'
|
174
|
+
end
|
175
|
+
puts <<-MSG
|
176
|
+
|
177
|
+
Please login via your web browser. We opened the tab for you...
|
178
|
+
|
179
|
+
MSG
|
180
|
+
client_secrets = Google::APIClient::ClientSecrets.load(@client_secrets)
|
181
|
+
flow = Google::APIClient::InstalledAppFlow.new(
|
182
|
+
client_id: client_secrets.client_id,
|
183
|
+
client_secret: client_secrets.client_secret,
|
184
|
+
scope: ['https://www.googleapis.com/auth/drive']
|
185
|
+
)
|
186
|
+
@client.authorization = flow.authorize(file_storage)
|
187
|
+
else
|
188
|
+
@client.authorization = file_storage.authorization
|
189
|
+
end
|
190
|
+
else
|
191
|
+
@client = Google::APIClient.new(
|
192
|
+
application_name: 'Middleman',
|
193
|
+
application_version: Middleman::GoogleDrive::VERSION,
|
194
|
+
authorization: Signet::OAuth2::Client.new(
|
195
|
+
token_credential_uri: 'https://accounts.google.com/o/oauth2/token',
|
196
|
+
audience: 'https://accounts.google.com/o/oauth2/token',
|
197
|
+
person: @person,
|
198
|
+
issuer: @issuer,
|
199
|
+
signing_key: @key,
|
200
|
+
scope: ['https://www.googleapis.com/auth/drive']
|
201
|
+
)
|
202
|
+
)
|
203
|
+
@client.authorization.fetch_access_token!
|
204
|
+
end
|
205
|
+
nil
|
206
|
+
end
|
207
|
+
|
208
|
+
# Returns true if we're using a private key to autheticate (like on a server).
|
209
|
+
def server?
|
210
|
+
! @key.nil?
|
211
|
+
end
|
212
|
+
|
213
|
+
# Returns true if we're using local oauth2 (like on your computer).
|
214
|
+
def local?
|
215
|
+
@key.nil?
|
216
|
+
end
|
156
217
|
|
157
|
-
class
|
158
|
-
class
|
218
|
+
class GoogleDriveError < StandardError; end
|
219
|
+
class DoesNotExist < GoogleDriveError; end
|
220
|
+
class CreateError < GoogleDriveError; end
|
221
|
+
class ConfigurationError < GoogleDriveError; end
|
159
222
|
end
|
@@ -12,9 +12,43 @@ module Middleman
|
|
12
12
|
|
13
13
|
drive = ::GoogleDrive.new
|
14
14
|
|
15
|
-
app = klass.inst
|
15
|
+
app = klass.inst
|
16
|
+
app.set :drive, drive # so you can access the drive api directly
|
16
17
|
options.load_sheets.each do |k, v|
|
17
|
-
|
18
|
+
loop do
|
19
|
+
begin
|
20
|
+
app.data.store(k, drive.prepared_spreadsheet(v))
|
21
|
+
doc = drive.find(v)
|
22
|
+
puts <<-MSG
|
23
|
+
== Loaded data.#{k} from Google Doc "#{doc['title']}"
|
24
|
+
== #{doc['alternateLink']}
|
25
|
+
MSG
|
26
|
+
break
|
27
|
+
rescue ::GoogleDrive::GoogleDriveError => exc
|
28
|
+
if drive.server?
|
29
|
+
puts "== FAILED to load Google Doc \"#{exc.message}\""
|
30
|
+
break
|
31
|
+
end
|
32
|
+
|
33
|
+
puts <<-MSG
|
34
|
+
|
35
|
+
Could not load the Google Doc.
|
36
|
+
|
37
|
+
Things to check:
|
38
|
+
- Make sure the Google Doc key is correct
|
39
|
+
- Make sure you're logging in with the correct account
|
40
|
+
- Make sure you have access to the document
|
41
|
+
|
42
|
+
Google said "#{exc.message}." It might be a lie.
|
43
|
+
|
44
|
+
Would you like to try again? [Y/n]
|
45
|
+
MSG
|
46
|
+
resp = $stdin.read 1
|
47
|
+
break unless resp.strip.empty? || resp =~ /[Yy]/
|
48
|
+
|
49
|
+
drive.redo_auth
|
50
|
+
end
|
51
|
+
end
|
18
52
|
end
|
19
53
|
end
|
20
54
|
end
|
@@ -23,5 +23,6 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_runtime_dependency 'google-api-client', '>= 0.7.1'
|
24
24
|
spec.add_runtime_dependency 'roo', '~> 1.13.2'
|
25
25
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
26
|
-
spec.add_development_dependency 'rake'
|
26
|
+
spec.add_development_dependency 'rake'
|
27
|
+
spec.add_development_dependency 'minitest'
|
27
28
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'google_drive'
|
3
|
+
|
4
|
+
# Test the client lib!
|
5
|
+
class TestChorusApiClient < MiniTest::Test
|
6
|
+
def setup
|
7
|
+
@drive = ::GoogleDrive.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_old_find
|
11
|
+
file = @drive.find '0AiOYF21HkoowdEZ4Ukkyc09nb2czQUxUYldidTB4Q1E'
|
12
|
+
assert_equal file['title'], 'Example Middleman Google Drive worksheet'
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_old_prepared_spreadsheet
|
16
|
+
file = @drive.prepared_spreadsheet '0AiOYF21HkoowdEZ4Ukkyc09nb2czQUxUYldidTB4Q1E'
|
17
|
+
assert_has_key file, 'microcopy'
|
18
|
+
assert_has_key file['microcopy'], 'help'
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_new_find
|
22
|
+
file = @drive.find '1vIICbbfHJ8lYSthiDWTNypZulrMResi9zPRjv4ePJJU'
|
23
|
+
assert_equal file['title'], 'Example Middleman Google Drive worksheet'
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_new_prepared_spreadsheet
|
27
|
+
file = @drive.prepared_spreadsheet '1vIICbbfHJ8lYSthiDWTNypZulrMResi9zPRjv4ePJJU'
|
28
|
+
assert_has_key file, 'microcopy'
|
29
|
+
assert_has_key file['microcopy'], 'help'
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_new_doc
|
33
|
+
file = @drive.doc '1lH-Nr_8UBOkvk8OdcdFoDez3OFIJxkawGVkwlMB-BjQ'
|
34
|
+
assert_not_nil file =~ /^<html>/
|
35
|
+
|
36
|
+
file = @drive.doc '1lH-Nr_8UBOkvk8OdcdFoDez3OFIJxkawGVkwlMB-BjQ', 'text'
|
37
|
+
assert_nil file =~ /^<html>/
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_copy_file
|
41
|
+
end
|
42
|
+
|
43
|
+
def assert_has_key(hash, key, msg=nil)
|
44
|
+
assert hash.key?(key), msg || "The key '#{key}' is missing from #{hash}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def assert_not_nil(thing, msg=nil)
|
48
|
+
assert !thing.nil?, msg
|
49
|
+
end
|
50
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: middleman-google_drive
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Mark
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-11-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: middleman-core
|
@@ -73,14 +73,28 @@ dependencies:
|
|
73
73
|
requirements:
|
74
74
|
- - '>='
|
75
75
|
- !ruby/object:Gem::Version
|
76
|
-
version:
|
76
|
+
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
79
|
version_requirements: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
81
|
- - '>='
|
82
82
|
- !ruby/object:Gem::Version
|
83
|
-
version:
|
83
|
+
version: '0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: minitest
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
84
98
|
description:
|
85
99
|
email:
|
86
100
|
- ryan@mrk.cc
|
@@ -100,6 +114,7 @@ files:
|
|
100
114
|
- lib/middleman-google_drive/version.rb
|
101
115
|
- lib/middleman_extension.rb
|
102
116
|
- middleman-google_drive.gemspec
|
117
|
+
- test/google_drive_test.rb
|
103
118
|
homepage: https://github.com/voxmedia/middleman-google_drive
|
104
119
|
licenses:
|
105
120
|
- BSD
|
@@ -120,8 +135,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
120
135
|
version: '0'
|
121
136
|
requirements: []
|
122
137
|
rubyforge_project:
|
123
|
-
rubygems_version: 2.
|
138
|
+
rubygems_version: 2.4.1
|
124
139
|
signing_key:
|
125
140
|
specification_version: 4
|
126
141
|
summary: Pull content from a google spreadsheet to use in your middleman site.
|
127
|
-
test_files:
|
142
|
+
test_files:
|
143
|
+
- test/google_drive_test.rb
|