bps-google-api 0.0.6 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cf5b7317c0e70c4602222332313db3921c89c60d868c87394fcbab4d1d366519
4
- data.tar.gz: 7662a0d33e7cfbcf6d0a48245ba549b14ee43cbcb9f3b0ec8808c3526482b19c
3
+ metadata.gz: 5ce9cad16163eed7195522f8af72a9ade306810c5b8681fc9021e0d88a73ad09
4
+ data.tar.gz: c0a75ead0679df9029efc37af6ffcccf5d54e0bb92d7a20c074fa65ddf5e8ac6
5
5
  SHA512:
6
- metadata.gz: a0087705245ea9279cd4d78e298273802f193dd255c74a95584875d24e65618dadd8dcf4837501ae701abbb892c9f0d814e25c17f61e2b98bc31d37a61681cd3
7
- data.tar.gz: dccc80c7769f29d7f4ab2b28255d25a4e2f80c11edd569488ad0b986d1d74c41a681dc8d4f0a6af4df6ff06545aed253a5190369ac292b8dfd685a2ddd2d10be
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
@@ -1,2 +1,4 @@
1
- source "https://rubygems.org"
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
2
4
  gemspec
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
 
@@ -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.6'
4
- s.date = '2019-04-11'
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
@@ -2,26 +2,31 @@
2
2
 
3
3
  module GoogleAPI
4
4
  class Base
5
- include GoogleAPI::Concerns::Base::Authorization
5
+ RETRIES ||= [
6
+ Google::Apis::TransmissionError, Google::Apis::ServerError,
7
+ Google::Apis::RateLimitError, Errno::ECONNRESET
8
+ ].freeze
6
9
 
7
- def initialize(auth: true)
8
- self.authorize! if auth
9
- end
10
+ include GoogleAPI::Base::Authorization
10
11
 
11
- def self.root_path
12
- defined?(Rails) ? Rails.root : './'
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 root_path
24
- self.class.root_path
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
@@ -2,54 +2,66 @@
2
2
 
3
3
  module GoogleAPI
4
4
  class Calendar < GoogleAPI::Base
5
- include GoogleAPI::Concerns::Calendar::ClearTestCalendar
6
- include GoogleAPI::Concerns::Calendar::Permission
5
+ include GoogleAPI::Calendar::ClearTestCalendar
7
6
 
8
- LAST_TOKEN_PATH ||= "#{root_path}/tmp/run/last_page_token"
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
- service.insert_event(calendar_id, event(event_options), conference_data_version: 1)
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
- service.list_events(calendar_id, max_results: max_results, page_token: page_token)
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
- service.get_event(calendar_id, event_id)
22
+ call(:get_event, calendar_id, event_id)
20
23
  end
21
24
 
22
25
  def update(calendar_id, event_id, event_options = {})
23
- service.update_event(calendar_id, event_id, event(event_options))
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
- service.delete_event(calendar_id, event_id)
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
- private
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 service_class
35
- Google::Apis::CalendarV3::CalendarService
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(valid_event_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: 'America/Detroit')
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
@@ -2,37 +2,35 @@
2
2
 
3
3
  module GoogleAPI
4
4
  class Group < GoogleAPI::Base
5
- def initialize(id, auth: false)
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
- service.get_group(@group_id)
13
+ call(:get_group, @group_id)
12
14
  end
13
15
 
14
16
  def members
15
- service.list_members(@group_id)
17
+ call(:list_members, @group_id)
16
18
  end
17
19
 
18
20
  def add(email)
19
- service.insert_member(@group_id, member(email))
20
- rescue Google::Apis::ClientError, 'duplicate: Member already exists.'
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
- service.delete_member(@group_id, email)
26
- rescue Google::Apis::ClientError, '(required: Missing required field: memberKey)'
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.6
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-04-11 00:00:00.000000000 Z
11
+ date: 2019-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: google-api-client
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.23.4
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.23.4
26
+ version: 0.0.8
27
27
  - !ruby/object:Gem::Dependency
28
- name: exp_retry
28
+ name: fileutils
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.0.8
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: 0.0.8
40
+ version: '1.2'
41
41
  - !ruby/object:Gem::Dependency
42
- name: ruby-progressbar
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: '1.10'
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: '1.10'
54
+ version: 0.23.4
55
55
  - !ruby/object:Gem::Dependency
56
- name: fileutils
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.2'
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.2'
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/concerns.rb
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
- rubygems_version: 3.0.2
106
+ rubyforge_project:
107
+ rubygems_version: 2.7.6
108
108
  signing_key:
109
109
  specification_version: 4
110
110
  summary: Configured Google API
@@ -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