middleman-google_drive 0.2.1 → 0.2.2
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.
- 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
|