bps-google-api 0.0.6 → 0.1.0
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/.rubocop.yml +83 -0
- data/Gemfile +3 -1
- data/Readme.md +5 -5
- data/bps-google-api.gemspec +6 -4
- data/lib/google_api/base.rb +13 -8
- data/lib/google_api/base/authorization.rb +106 -0
- data/lib/google_api/calendar.rb +29 -17
- data/lib/google_api/calendar/clear_test_calendar.rb +64 -0
- data/lib/google_api/group.rb +9 -11
- metadata +19 -19
- data/lib/google_api/concerns.rb +0 -14
- data/lib/google_api/concerns/base/authorization.rb +0 -110
- data/lib/google_api/concerns/calendar/clear_test_calendar.rb +0 -69
- data/lib/google_api/concerns/calendar/permission.rb +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5ce9cad16163eed7195522f8af72a9ade306810c5b8681fc9021e0d88a73ad09
|
4
|
+
data.tar.gz: c0a75ead0679df9029efc37af6ffcccf5d54e0bb92d7a20c074fa65ddf5e8ac6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9a1a4fc67ab0d2906af307e00f411e28dee8e958518ba8dc6aee94171d3f5532960d12ece74ca1a8cfbbdc67241803379018df3e6b0d023aef88ccf6aabc1f07
|
7
|
+
data.tar.gz: '01429a10a6c172bb06e18877d24593e12def6ca3ba130acb18db7101f0bab529e93ae9dd2585f03892547a4c75727833acee796cd3a42809fea2c253fc82d7d4'
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-rspec
|
3
|
+
- rubocop-performance
|
4
|
+
AllCops:
|
5
|
+
TargetRubyVersion: 2.5
|
6
|
+
Exclude:
|
7
|
+
- bin/**/*
|
8
|
+
- config/**/*
|
9
|
+
- db/**/*
|
10
|
+
- vendor/**/*
|
11
|
+
- tmp/**/*
|
12
|
+
|
13
|
+
Layout/IndentFirstHashElement:
|
14
|
+
EnforcedStyle: consistent
|
15
|
+
Layout/AccessModifierIndentation:
|
16
|
+
EnforcedStyle: outdent
|
17
|
+
Layout/EmptyLinesAroundAccessModifier:
|
18
|
+
Enabled: true
|
19
|
+
Layout/AlignArray:
|
20
|
+
Enabled: true
|
21
|
+
Layout/AlignHash:
|
22
|
+
Enabled: true
|
23
|
+
Layout/EmptyLineAfterGuardClause:
|
24
|
+
Enabled: true
|
25
|
+
Layout/SpaceInsideBlockBraces:
|
26
|
+
EnforcedStyle: space
|
27
|
+
EnforcedStyleForEmptyBraces: no_space
|
28
|
+
Layout/SpaceInsideHashLiteralBraces:
|
29
|
+
EnforcedStyle: space
|
30
|
+
EnforcedStyleForEmptyBraces: no_space
|
31
|
+
Layout/SpaceInsideArrayLiteralBrackets:
|
32
|
+
EnforcedStyle: no_space
|
33
|
+
|
34
|
+
Lint/UnusedMethodArgument:
|
35
|
+
Enabled: true
|
36
|
+
Lint/UselessAssignment:
|
37
|
+
Enabled: true
|
38
|
+
|
39
|
+
Metrics/LineLength:
|
40
|
+
Max: 100
|
41
|
+
Metrics/MethodLength:
|
42
|
+
Enabled: true
|
43
|
+
Metrics/ClassLength:
|
44
|
+
Enabled: true
|
45
|
+
Max: 125
|
46
|
+
Metrics/ModuleLength:
|
47
|
+
Max: 125
|
48
|
+
Metrics/ParameterLists:
|
49
|
+
Enabled: true
|
50
|
+
Metrics/CyclomaticComplexity:
|
51
|
+
Enabled: true
|
52
|
+
Metrics/AbcSize:
|
53
|
+
Enabled: true
|
54
|
+
|
55
|
+
Naming/MemoizedInstanceVariableName:
|
56
|
+
Enabled: false
|
57
|
+
Naming/UncommunicativeMethodParamName:
|
58
|
+
Enabled: false
|
59
|
+
|
60
|
+
Rails/InverseOf:
|
61
|
+
Enabled: true
|
62
|
+
|
63
|
+
Style/Documentation:
|
64
|
+
Enabled: false
|
65
|
+
Style/FrozenStringLiteralComment:
|
66
|
+
Enabled: true
|
67
|
+
Style/NumericLiterals:
|
68
|
+
Enabled: true
|
69
|
+
Style/StringLiterals:
|
70
|
+
EnforcedStyle: single_quotes
|
71
|
+
Style/AndOr:
|
72
|
+
Enabled: true
|
73
|
+
Style/ClassCheck:
|
74
|
+
Enabled: true
|
75
|
+
Style/GuardClause:
|
76
|
+
Enabled: true
|
77
|
+
|
78
|
+
Security/Eval:
|
79
|
+
Enabled: true
|
80
|
+
Security/JSONLoad:
|
81
|
+
Enabled: true
|
82
|
+
Security/YAMLLoad:
|
83
|
+
Enabled: true
|
data/Gemfile
CHANGED
data/Readme.md
CHANGED
@@ -32,16 +32,16 @@ GOOGLE_ACCESS_TOKEN
|
|
32
32
|
GOOGLE_REFRESH_TOKEN
|
33
33
|
GOOGLE_AUTH_EXP
|
34
34
|
|
35
|
-
GOOGLE_AUTH_SCOPE_CALENDAR
|
36
|
-
GOOGLE_AUTH_SCOPE_GROUP
|
37
|
-
|
38
|
-
GOOGLE_CALENDAR_ID_GEN
|
39
|
-
GOOGLE_CALENDAR_ID_EDUC
|
40
35
|
GOOGLE_CALENDAR_ID_TEST
|
36
|
+
|
37
|
+
TZ # Timezone
|
41
38
|
```
|
42
39
|
|
43
40
|
## Usage
|
44
41
|
|
42
|
+
If no configuration is available, `.new` will automatically run `.authorize!`
|
43
|
+
and return a URL to generate an authorization token.
|
44
|
+
|
45
45
|
```ruby
|
46
46
|
calendar = GoogleAPI::Calendar.new
|
47
47
|
|
data/bps-google-api.gemspec
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
Gem::Specification.new do |s|
|
2
4
|
s.name = 'bps-google-api'
|
3
|
-
s.version = '0.0
|
4
|
-
s.date = '2019-
|
5
|
+
s.version = '0.1.0'
|
6
|
+
s.date = '2019-06-15'
|
5
7
|
s.summary = 'Configured Google API'
|
6
8
|
s.description = 'A configured Google API wrapper.'
|
7
9
|
s.homepage = 'http://rubygems.org/gems/bps-google-api'
|
@@ -11,8 +13,8 @@ Gem::Specification.new do |s|
|
|
11
13
|
s.require_paths = %w[lib]
|
12
14
|
s.files = `git ls-files`.split("\n")
|
13
15
|
|
14
|
-
s.add_runtime_dependency 'google-api-client', '~> 0.23.4'
|
15
16
|
s.add_runtime_dependency 'exp_retry', '~> 0.0.8'
|
16
|
-
s.add_runtime_dependency 'ruby-progressbar', '~> 1.10'
|
17
17
|
s.add_runtime_dependency 'fileutils', '~> 1.2'
|
18
|
+
s.add_runtime_dependency 'google-api-client', '~> 0.23.4'
|
19
|
+
s.add_runtime_dependency 'ruby-progressbar', '~> 1.10'
|
18
20
|
end
|
data/lib/google_api/base.rb
CHANGED
@@ -2,26 +2,31 @@
|
|
2
2
|
|
3
3
|
module GoogleAPI
|
4
4
|
class Base
|
5
|
-
|
5
|
+
RETRIES ||= [
|
6
|
+
Google::Apis::TransmissionError, Google::Apis::ServerError,
|
7
|
+
Google::Apis::RateLimitError, Errno::ECONNRESET
|
8
|
+
].freeze
|
6
9
|
|
7
|
-
|
8
|
-
self.authorize! if auth
|
9
|
-
end
|
10
|
+
include GoogleAPI::Base::Authorization
|
10
11
|
|
11
|
-
def
|
12
|
-
|
12
|
+
def initialize(auth: true)
|
13
|
+
authorize! if auth
|
13
14
|
end
|
14
15
|
|
15
16
|
private
|
16
17
|
|
18
|
+
def service_class
|
19
|
+
self.class::SERVICE_CLASS
|
20
|
+
end
|
21
|
+
|
17
22
|
def service
|
18
23
|
raise 'No service class defined.' unless defined?(service_class)
|
19
24
|
|
20
25
|
@service ||= service_class.new
|
21
26
|
end
|
22
27
|
|
23
|
-
def
|
24
|
-
|
28
|
+
def call(method, *args)
|
29
|
+
ExpRetry.for(exception: RETRIES) { service.send(method, *args) }
|
25
30
|
end
|
26
31
|
end
|
27
32
|
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GoogleAPI
|
4
|
+
class Base
|
5
|
+
module Authorization
|
6
|
+
OOB_URI ||= 'urn:ietf:wg:oauth:2.0:oob'
|
7
|
+
AUTH_SCOPES ||= [
|
8
|
+
Google::Apis::AdminDirectoryV1::AUTH_ADMIN_DIRECTORY_GROUP,
|
9
|
+
Google::Apis::CalendarV3::AUTH_CALENDAR
|
10
|
+
].freeze
|
11
|
+
TOKEN_SCOPES ||= [
|
12
|
+
'"https://www.googleapis.com/auth/admin.directory.group"',
|
13
|
+
'"https://www.googleapis.com/auth/calendar"'
|
14
|
+
].freeze
|
15
|
+
|
16
|
+
def authorize!(refresh: false, reveal: false)
|
17
|
+
token_file
|
18
|
+
auth = authorize(refresh: refresh)
|
19
|
+
service.authorization = auth
|
20
|
+
return true unless reveal
|
21
|
+
|
22
|
+
[auth, auth_keys(auth)]
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def authorize(user_id = 'default', refresh: false)
|
28
|
+
@credentials = authorizer.get_credentials(user_id)
|
29
|
+
return @credentials unless @credentials.nil? || refresh
|
30
|
+
|
31
|
+
@credentials = authorizer.get_and_store_credentials_from_code(
|
32
|
+
user_id: user_id, code: request_authorization, base_url: OOB_URI
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
def request_authorization
|
37
|
+
url = authorizer.get_authorization_url(base_url: OOB_URI)
|
38
|
+
puts("Open this URL to authorize:\n", url)
|
39
|
+
print("\nResponse code: ")
|
40
|
+
gets
|
41
|
+
end
|
42
|
+
|
43
|
+
def authorizer
|
44
|
+
@authorizer ||= Google::Auth::UserAuthorizer.new(
|
45
|
+
auth_client_id, AUTH_SCOPES, auth_token_store
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
def auth_client_id
|
50
|
+
client_id_file
|
51
|
+
Google::Auth::ClientId.from_hash(
|
52
|
+
JSON.parse(File.read('config/keys/google_api_client.json'))
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
56
|
+
def auth_token_store
|
57
|
+
Google::Auth::Stores::FileTokenStore.new(file: 'config/keys/google_token.yaml')
|
58
|
+
end
|
59
|
+
|
60
|
+
def auth_keys(auth)
|
61
|
+
{
|
62
|
+
GOOGLE_CLIENT_ID: auth.client_id, GOOGLE_CLIENT_SECRET: auth.client_secret,
|
63
|
+
GOOGLE_ACCESS_TOKEN: auth.access_token, GOOGLE_REFRESH_TOKEN: auth.refresh_token,
|
64
|
+
GOOGLE_AUTH_SCOPES: auth.scope, GOOGLE_AUTH_EXP: expires_milli(auth.as_json['expires_at'])
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
def expires_milli(time)
|
69
|
+
DateTime.strptime(time, '%Y-%m-%dT%H:%M:%S.%L%:z').to_i * 1000
|
70
|
+
end
|
71
|
+
|
72
|
+
def store_key(path, key)
|
73
|
+
return if File.exist?(path)
|
74
|
+
|
75
|
+
File.open(path, 'w+') do |f|
|
76
|
+
File.chmod(0o600, f)
|
77
|
+
block_given? ? yield(f) : f.write(key)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def client_id_file
|
82
|
+
store_key(
|
83
|
+
File.join(Rails.root, 'config/keys/google_api_client.json'),
|
84
|
+
<<~KEY
|
85
|
+
{"installed":{"client_id":"#{ENV['GOOGLE_CLIENT_ID']}","project_id":"charming-scarab-208718",
|
86
|
+
"auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://accounts.google.com/o/oauth2/token",
|
87
|
+
"auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"#{ENV['GOOGLE_CLIENT_SECRET']}",
|
88
|
+
"redirect_uris":["#{OOB_URI}","http://localhost"]}}
|
89
|
+
KEY
|
90
|
+
)
|
91
|
+
end
|
92
|
+
|
93
|
+
def token_file
|
94
|
+
store_key(
|
95
|
+
File.join(Rails.root, 'config/keys/google_token.yaml'),
|
96
|
+
<<~KEY
|
97
|
+
---
|
98
|
+
default: '{"client_id":"#{ENV['GOOGLE_CLIENT_ID']}","access_token":"#{ENV['GOOGLE_ACCESS_TOKEN']}",
|
99
|
+
"refresh_token":"#{ENV['GOOGLE_REFRESH_TOKEN']}","scope":[#{TOKEN_SCOPES.join(',')}],
|
100
|
+
"expiration_time_millis":#{ENV['GOOGLE_AUTH_EXP']}}'
|
101
|
+
KEY
|
102
|
+
)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
data/lib/google_api/calendar.rb
CHANGED
@@ -2,54 +2,66 @@
|
|
2
2
|
|
3
3
|
module GoogleAPI
|
4
4
|
class Calendar < GoogleAPI::Base
|
5
|
-
include GoogleAPI::
|
6
|
-
include GoogleAPI::Concerns::Calendar::Permission
|
5
|
+
include GoogleAPI::Calendar::ClearTestCalendar
|
7
6
|
|
8
|
-
|
7
|
+
SERVICE_CLASS = Google::Apis::CalendarV3::CalendarService
|
8
|
+
LAST_TOKEN_PATH ||= Rails.root.join('tmp', 'run', 'last_page_token')
|
9
|
+
VALID_EVENT_KEYS ||= %i[
|
10
|
+
summary start end description location recurrence conference_data conference_data_version
|
11
|
+
].freeze
|
9
12
|
|
10
13
|
def create(calendar_id, event_options = {})
|
11
|
-
|
14
|
+
call(:insert_event, calendar_id, event(event_options), conference_data_version: 1)
|
12
15
|
end
|
13
16
|
|
14
17
|
def list(calendar_id, max_results: 2500, page_token: nil)
|
15
|
-
|
18
|
+
call(:list_events, calendar_id, max_results: max_results, page_token: page_token)
|
16
19
|
end
|
17
20
|
|
18
21
|
def get(calendar_id, event_id)
|
19
|
-
|
22
|
+
call(:get_event, calendar_id, event_id)
|
20
23
|
end
|
21
24
|
|
22
25
|
def update(calendar_id, event_id, event_options = {})
|
23
|
-
|
26
|
+
call(:update_event, calendar_id, event_id, event(event_options))
|
24
27
|
end
|
25
28
|
|
26
29
|
def delete(calendar_id, event_id)
|
27
|
-
|
30
|
+
call(:delete_event, calendar_id, event_id)
|
28
31
|
rescue Google::Apis::ClientError
|
29
32
|
:event_not_found
|
30
33
|
end
|
31
34
|
|
32
|
-
|
35
|
+
def permit(calendar, user)
|
36
|
+
rule = Google::Apis::CalendarV3::AclRule.new(
|
37
|
+
scope: { type: 'user', value: user.email }, role: 'writer'
|
38
|
+
)
|
39
|
+
|
40
|
+
result = call(:insert_acl, calendar, rule)
|
41
|
+
user.update(calendar_rule_id: result.id)
|
42
|
+
end
|
33
43
|
|
34
|
-
def
|
35
|
-
|
44
|
+
def unpermit(calendar, user)
|
45
|
+
call(:delete_acl, calendar, user&.calendar_rule_id)
|
46
|
+
rescue Google::Apis::ClientError
|
47
|
+
:permission_not_found
|
48
|
+
ensure
|
49
|
+
user.update(calendar_rule_id: nil)
|
36
50
|
end
|
37
51
|
|
52
|
+
private
|
53
|
+
|
38
54
|
def event(event_options)
|
39
|
-
event_options.assert_valid_keys(
|
55
|
+
event_options.assert_valid_keys(VALID_EVENT_KEYS)
|
40
56
|
event_options[:start] = date(event_options[:start])
|
41
57
|
event_options[:end] = date(event_options[:end])
|
42
58
|
|
43
59
|
Google::Apis::CalendarV3::Event.new(event_options.reject { |_, v| v.nil? })
|
44
60
|
end
|
45
61
|
|
46
|
-
def valid_event_keys
|
47
|
-
%i[summary start end description location recurrence conference_data conference_data_version]
|
48
|
-
end
|
49
|
-
|
50
62
|
def date(date)
|
51
63
|
key = date&.is_a?(String) ? :date : :date_time
|
52
|
-
Google::Apis::CalendarV3::EventDateTime.new(key => date, time_zone: '
|
64
|
+
Google::Apis::CalendarV3::EventDateTime.new(key => date, time_zone: ENV['TZ'])
|
53
65
|
end
|
54
66
|
end
|
55
67
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GoogleAPI
|
4
|
+
class Calendar
|
5
|
+
module ClearTestCalendar
|
6
|
+
def clear_test_calendar(page_token: nil, page_limit: 50)
|
7
|
+
Google::Apis.logger.level = Logger::WARN
|
8
|
+
choose_page_token(page_token)
|
9
|
+
loop_over_pages(ENV['GOOGLE_CALENDAR_ID_TEST'], page_limit: page_limit)
|
10
|
+
puts '*** Cleared all events!'
|
11
|
+
rescue Google::Apis::RateLimitError
|
12
|
+
puts "\n\n*** Google::Apis::RateLimitError (Rate Limit Exceeded)"
|
13
|
+
ensure
|
14
|
+
log_last_page_token unless @page_token.blank?
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def choose_page_token(page_token)
|
20
|
+
last_token = GoogleAPI::Calendar::LAST_TOKEN_PATH
|
21
|
+
@page_token ||= File.read(last_token) if File.exist?(last_token)
|
22
|
+
@page_token = page_token if page_token.present?
|
23
|
+
end
|
24
|
+
|
25
|
+
def loop_over_pages(cal_id, page_limit: 50)
|
26
|
+
puts "*** Starting with page token: #{@page_token}" if @page_token.present?
|
27
|
+
|
28
|
+
page_limit -= 1 while (@page_token = clear_page(cal_id)) && page_limit.positive?
|
29
|
+
end
|
30
|
+
|
31
|
+
def clear_page(cal_id)
|
32
|
+
response = list(cal_id, page_token: @page_token)
|
33
|
+
clear_events_from_page(cal_id, response.items) unless response.items.blank?
|
34
|
+
response.next_page_token
|
35
|
+
end
|
36
|
+
|
37
|
+
def clear_events_from_page(cal_id, items)
|
38
|
+
puts "*** Page token: #{@page_token}"
|
39
|
+
pb = progress_bar(items.count)
|
40
|
+
items&.each_with_index do |event, _index|
|
41
|
+
ExpRetry.for(exception: Calendar::RETRIES) do
|
42
|
+
delete(cal_id, event.id)
|
43
|
+
pb.increment
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def log_last_page_token
|
49
|
+
puts "\n\n*** Last page token cleared: #{@page_token}"
|
50
|
+
File.open(GoogleAPI::Calendar::LAST_TOKEN_PATH, 'w+') do |f|
|
51
|
+
f.write(@page_token)
|
52
|
+
end
|
53
|
+
puts "\n*** Token stored in #{GoogleAPI::Calendar::LAST_TOKEN_PATH}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def progress_bar(total)
|
57
|
+
ProgressBar.create(
|
58
|
+
title: 'Page cleared', starting_at: 0, total: total, progress_mark: ' ',
|
59
|
+
remainder_mark: "\u{FF65}", format: "%a [%R/sec] %E | %b\u{15E7}%i %c/%C (%P%%) %t"
|
60
|
+
)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/google_api/group.rb
CHANGED
@@ -2,37 +2,35 @@
|
|
2
2
|
|
3
3
|
module GoogleAPI
|
4
4
|
class Group < GoogleAPI::Base
|
5
|
-
|
5
|
+
SERVICE_CLASS = Google::Apis::AdminDirectoryV1::DirectoryService
|
6
|
+
|
7
|
+
def initialize(id, auth: true)
|
6
8
|
@group_id = id
|
7
9
|
super(auth: auth)
|
8
10
|
end
|
9
11
|
|
10
12
|
def get
|
11
|
-
|
13
|
+
call(:get_group, @group_id)
|
12
14
|
end
|
13
15
|
|
14
16
|
def members
|
15
|
-
|
17
|
+
call(:list_members, @group_id)
|
16
18
|
end
|
17
19
|
|
18
20
|
def add(email)
|
19
|
-
|
20
|
-
rescue Google::Apis::ClientError
|
21
|
+
call(:insert_member, @group_id, member(email))
|
22
|
+
rescue Google::Apis::ClientError
|
21
23
|
:already_exists
|
22
24
|
end
|
23
25
|
|
24
26
|
def remove(email)
|
25
|
-
|
26
|
-
rescue Google::Apis::ClientError
|
27
|
+
call(:delete_member, @group_id, email)
|
28
|
+
rescue Google::Apis::ClientError
|
27
29
|
:not_found
|
28
30
|
end
|
29
31
|
|
30
32
|
private
|
31
33
|
|
32
|
-
def service_class
|
33
|
-
Google::Apis::AdminDirectoryV1::DirectoryService
|
34
|
-
end
|
35
|
-
|
36
34
|
def member(email)
|
37
35
|
Google::Apis::AdminDirectoryV1::Member.new(email: email)
|
38
36
|
end
|
metadata
CHANGED
@@ -1,71 +1,71 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bps-google-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julian Fiander
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-06-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: exp_retry
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.0.8
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.0.8
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: fileutils
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: '1.2'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: '1.2'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: google-api-client
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 0.23.4
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: 0.23.4
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: ruby-progressbar
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '1.
|
61
|
+
version: '1.10'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '1.
|
68
|
+
version: '1.10'
|
69
69
|
description: A configured Google API wrapper.
|
70
70
|
email: julian@fiander.one
|
71
71
|
executables: []
|
@@ -73,17 +73,16 @@ extensions: []
|
|
73
73
|
extra_rdoc_files: []
|
74
74
|
files:
|
75
75
|
- ".gitignore"
|
76
|
+
- ".rubocop.yml"
|
76
77
|
- Gemfile
|
77
78
|
- Gemfile.lock
|
78
79
|
- Readme.md
|
79
80
|
- bps-google-api.gemspec
|
80
81
|
- lib/google_api.rb
|
81
82
|
- lib/google_api/base.rb
|
83
|
+
- lib/google_api/base/authorization.rb
|
82
84
|
- lib/google_api/calendar.rb
|
83
|
-
- lib/google_api/
|
84
|
-
- lib/google_api/concerns/base/authorization.rb
|
85
|
-
- lib/google_api/concerns/calendar/clear_test_calendar.rb
|
86
|
-
- lib/google_api/concerns/calendar/permission.rb
|
85
|
+
- lib/google_api/calendar/clear_test_calendar.rb
|
87
86
|
- lib/google_api/group.rb
|
88
87
|
homepage: http://rubygems.org/gems/bps-google-api
|
89
88
|
licenses:
|
@@ -104,7 +103,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
104
103
|
- !ruby/object:Gem::Version
|
105
104
|
version: '0'
|
106
105
|
requirements: []
|
107
|
-
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 2.7.6
|
108
108
|
signing_key:
|
109
109
|
specification_version: 4
|
110
110
|
summary: Configured Google API
|
data/lib/google_api/concerns.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module GoogleAPI
|
4
|
-
module Concerns
|
5
|
-
module Base
|
6
|
-
require 'google_api/concerns/base/authorization'
|
7
|
-
end
|
8
|
-
|
9
|
-
module Calendar
|
10
|
-
require 'google_api/concerns/calendar/clear_test_calendar'
|
11
|
-
require 'google_api/concerns/calendar/permission'
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
@@ -1,110 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module GoogleAPI::Concerns::Base
|
4
|
-
module Authorization
|
5
|
-
OOB_URI ||= 'urn:ietf:wg:oauth:2.0:oob'
|
6
|
-
AUTH_SCOPES ||= [
|
7
|
-
Google::Apis::AdminDirectoryV1::AUTH_ADMIN_DIRECTORY_GROUP,
|
8
|
-
Google::Apis::CalendarV3::AUTH_CALENDAR
|
9
|
-
].freeze
|
10
|
-
|
11
|
-
def authorize!(refresh: false, reveal: false)
|
12
|
-
client_id_file
|
13
|
-
token_file
|
14
|
-
|
15
|
-
auth = authorize(refresh: refresh)
|
16
|
-
service.authorization = auth
|
17
|
-
return true unless reveal
|
18
|
-
|
19
|
-
[auth, auth_keys(auth)]
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def authorize(user_id = 'default', refresh: false)
|
25
|
-
@credentials = authorizer.get_credentials(user_id)
|
26
|
-
return @credentials unless @credentials.nil? || refresh
|
27
|
-
|
28
|
-
@credentials = authorizer.get_and_store_credentials_from_code(
|
29
|
-
user_id: user_id, code: request_authorization, base_url: OOB_URI
|
30
|
-
)
|
31
|
-
end
|
32
|
-
|
33
|
-
def request_authorization
|
34
|
-
url = authorizer.get_authorization_url(base_url: OOB_URI)
|
35
|
-
puts("Open this URL to authorize:\n", url)
|
36
|
-
print("\nResponse code: ")
|
37
|
-
gets
|
38
|
-
end
|
39
|
-
|
40
|
-
def authorizer
|
41
|
-
@authorizer ||= Google::Auth::UserAuthorizer.new(auth_client_id, AUTH_SCOPES, auth_token_store)
|
42
|
-
end
|
43
|
-
|
44
|
-
def auth_client_id
|
45
|
-
client_id_file
|
46
|
-
Google::Auth::ClientId.from_hash(JSON.parse(File.read('config/keys/google_api_client.json')))
|
47
|
-
end
|
48
|
-
|
49
|
-
def auth_token_store
|
50
|
-
Google::Auth::Stores::FileTokenStore.new(file: 'config/keys/google_token.yaml')
|
51
|
-
end
|
52
|
-
|
53
|
-
def auth_keys(auth)
|
54
|
-
{
|
55
|
-
GOOGLE_CLIENT_ID: auth.client_id, GOOGLE_CLIENT_SECRET: auth.client_secret,
|
56
|
-
GOOGLE_ACCESS_TOKEN: auth.access_token, GOOGLE_REFRESH_TOKEN: auth.refresh_token,
|
57
|
-
GOOGLE_AUTH_SCOPES: auth.scope, GOOGLE_AUTH_EXP: expires_milli(auth.as_json['expires_at'])
|
58
|
-
}
|
59
|
-
end
|
60
|
-
|
61
|
-
def expires_milli(time)
|
62
|
-
DateTime.strptime(time, '%Y-%m-%dT%H:%M:%S.%L%:z').to_i * 1000
|
63
|
-
end
|
64
|
-
|
65
|
-
def store_key(path, key)
|
66
|
-
return if File.exist?(path)
|
67
|
-
|
68
|
-
ensure_file(path)
|
69
|
-
File.open(path, 'w+') do |f|
|
70
|
-
File.chmod(0600, f)
|
71
|
-
block_given? ? yield(f) : f.write(key)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def ensure_file(path)
|
76
|
-
path = path.split('/')
|
77
|
-
file = path.pop
|
78
|
-
path = path.join('/')
|
79
|
-
FileUtils.mkdir_p(path)
|
80
|
-
end
|
81
|
-
|
82
|
-
def client_id_file
|
83
|
-
store_key(
|
84
|
-
File.join(root_path, 'config/keys/google_api_client.json'),
|
85
|
-
<<~KEY
|
86
|
-
{"installed":{"client_id":"#{ENV['GOOGLE_CLIENT_ID']}","project_id":"charming-scarab-208718",
|
87
|
-
"auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://accounts.google.com/o/oauth2/token",
|
88
|
-
"auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"#{ENV['GOOGLE_CLIENT_SECRET']}",
|
89
|
-
"redirect_uris":["#{OOB_URI}","http://localhost"]}}
|
90
|
-
KEY
|
91
|
-
)
|
92
|
-
end
|
93
|
-
|
94
|
-
def token_file
|
95
|
-
store_key(
|
96
|
-
File.join(root_path, 'config/keys/google_token.yaml'),
|
97
|
-
<<~KEY
|
98
|
-
---
|
99
|
-
default: '{"client_id":"#{ENV['GOOGLE_CLIENT_ID']}","access_token":"#{ENV['GOOGLE_ACCESS_TOKEN']}",
|
100
|
-
"refresh_token":"#{ENV['GOOGLE_REFRESH_TOKEN']}","scope":[#{scopes}],
|
101
|
-
"expiration_time_millis":#{ENV['GOOGLE_AUTH_EXP']}}'
|
102
|
-
KEY
|
103
|
-
)
|
104
|
-
end
|
105
|
-
|
106
|
-
def scopes
|
107
|
-
ENV.select { |k, v| k =~ /GOOGLE_AUTH_SCOPE_/ }.values.map { |s| "\"#{s}\"" }.join(',')
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
@@ -1,69 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module GoogleAPI::Concerns::Calendar
|
4
|
-
module ClearTestCalendar
|
5
|
-
RETRIABLE_EXCEPTIONS = [
|
6
|
-
Google::Apis::RateLimitError,
|
7
|
-
Google::Apis::TransmissionError
|
8
|
-
].freeze
|
9
|
-
|
10
|
-
def clear_test_calendar(page_token: nil, page_limit: 50)
|
11
|
-
Google::Apis.logger.level = Logger::WARN
|
12
|
-
set_page_token(page_token)
|
13
|
-
loop_over_pages(ENV['GOOGLE_CALENDAR_ID_TEST'], page_limit: page_limit)
|
14
|
-
puts '*** Cleared all events!'
|
15
|
-
rescue Google::Apis::RateLimitError
|
16
|
-
puts "\n\n*** Google::Apis::RateLimitError (Rate Limit Exceeded)"
|
17
|
-
ensure
|
18
|
-
log_last_page_token unless @page_token.blank?
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
def set_page_token(page_token)
|
24
|
-
last_token = GoogleAPI::Calendar::LAST_TOKEN_PATH
|
25
|
-
@page_token ||= File.read(last_token) if File.exist?(last_token)
|
26
|
-
@page_token = page_token if page_token.present?
|
27
|
-
end
|
28
|
-
|
29
|
-
def loop_over_pages(cal_id, page_limit: 50)
|
30
|
-
puts "*** Starting with page token: #{@page_token}" if @page_token.present?
|
31
|
-
|
32
|
-
while (@page_token = clear_page(cal_id)) && page_limit.positive?
|
33
|
-
page_limit -= 1
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def clear_page(cal_id)
|
38
|
-
response = list(cal_id, page_token: @page_token)
|
39
|
-
clear_events_from_page(cal_id, response.items) unless response.items.blank?
|
40
|
-
response.next_page_token
|
41
|
-
end
|
42
|
-
|
43
|
-
def clear_events_from_page(cal_id, items)
|
44
|
-
puts "*** Page token: #{@page_token}"
|
45
|
-
pb = progress_bar(items.count)
|
46
|
-
items&.each_with_index do |event, index|
|
47
|
-
ExpRetry.for(exception: RETRIABLE_EXCEPTIONS) do
|
48
|
-
delete(cal_id, event.id)
|
49
|
-
pb.increment
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def log_last_page_token
|
55
|
-
puts "\n\n*** Last page token cleared: #{@page_token}"
|
56
|
-
File.open(GoogleAPI::Calendar::LAST_TOKEN_PATH, 'w+') do |f|
|
57
|
-
f.write(@page_token)
|
58
|
-
end
|
59
|
-
puts "\n*** Token stored in #{GoogleAPI::Calendar::LAST_TOKEN_PATH}"
|
60
|
-
end
|
61
|
-
|
62
|
-
def progress_bar(total)
|
63
|
-
ProgressBar.create(
|
64
|
-
title: 'Page cleared', starting_at: 0, total: total, progress_mark: ' ',
|
65
|
-
remainder_mark: "\u{FF65}", format: "%a [%R/sec] %E | %b\u{15E7}%i %c/%C (%P%%) %t"
|
66
|
-
)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module GoogleAPI::Concerns::Calendar
|
4
|
-
module Permission
|
5
|
-
def permit(calendar, user)
|
6
|
-
rule = Google::Apis::CalendarV3::AclRule.new(
|
7
|
-
scope: { type: 'user', value: user.email }, role: 'writer'
|
8
|
-
)
|
9
|
-
|
10
|
-
result = service.insert_acl(calendar, rule)
|
11
|
-
user.update(calendar_rule_id: result.id)
|
12
|
-
end
|
13
|
-
|
14
|
-
def unpermit(calendar, user)
|
15
|
-
service.delete_acl(calendar, user&.calendar_rule_id)
|
16
|
-
rescue Google::Apis::ClientError
|
17
|
-
:permission_not_found
|
18
|
-
ensure
|
19
|
-
user.update(calendar_rule_id: nil)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|