zoom_launcher 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c4ca63f84f5c8da5810082955ee23f085a2e4848
4
+ data.tar.gz: 2390d29c2430bdc57809cdf326a2437c69659c46
5
+ SHA512:
6
+ metadata.gz: e4b9a62f6e889891e5d38efea74ee9aee274ea1813a95974d551930e5f626035fb961e476782f0bec6e9a3f39549967958fc1321095af5305bdd5685c4c5c4bc
7
+ data.tar.gz: 7a03a9247007aa4bdd2b366649a1dec3ccd2f7426f46aa2b6e8e38266f7009b3de3261dea56b771146c87fa1c4e0366e3a1c95a4d7cd20104cbdc98870d1f861
@@ -0,0 +1,4 @@
1
+ .env
2
+ Gemfile.lock
3
+ spec/examples.txt
4
+ *.gem
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,20 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.3
3
+
4
+ Security/Eval:
5
+ Enabled: false
6
+
7
+ Style/Documentation:
8
+ Enabled: false
9
+
10
+ Metrics/LineLength:
11
+ Enabled: false
12
+
13
+ Metrics/BlockLength:
14
+ Enabled: false
15
+
16
+ Metrics/AbcSize:
17
+ Enabled: false
18
+
19
+ Metrics/MethodLength:
20
+ Enabled: false
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Ben Balter
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,28 @@
1
+ # Zoom Launcher
2
+
3
+ A command line tool for joining your next Zoom meeting.
4
+
5
+ ## Usage
6
+
7
+ ```
8
+ $ zoom
9
+ Your next Zoom meeting is "Some important meeting".
10
+ It is scheduled to start in 3 minutes.
11
+
12
+ Opening https://github.zoom.us/j/XXX...
13
+ Oh, and here's the URL in case you need it: https://www.google.com/calendar/event?eid=XXX
14
+ ```
15
+
16
+ ## Installation
17
+
18
+ `gem install zoom_launcher`
19
+
20
+ ## Setup
21
+
22
+ In order to use Zoom Launcher, you need to create an OAuth app and authorize it to access your calendar:
23
+
24
+ 1. Go to https://console.developers.google.com and create a new project
25
+ 2. Click "Credentials on the left size and create a new credential for that project"
26
+ 3. Create a new OAuth credential, and download the resulting JSON file
27
+ 4. Move the file to `~/.config/google/client_secrets.json`
28
+ 5. Run `zoom auth` and follow the instructions to authorize the app
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../lib/zoom_launcher'
5
+
6
+ Dotenv.load
7
+ ZoomLauncher::CLI.start(ARGV)
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Google
4
+ module Apis
5
+ module CalendarV3
6
+ class Event
7
+ MEETING_URL_REGEX = %r{https://.*\.zoom\.us/j/\d+}
8
+ include ActionView::Helpers::DateHelper
9
+
10
+ def meeting_url
11
+ matches = (location + description).match(MEETING_URL_REGEX)
12
+ matches[0] if matches
13
+ end
14
+
15
+ def already_started?
16
+ start.date_time <= DateTime.now
17
+ end
18
+
19
+ def more_than_five_minutes_from_now?
20
+ start.date_time.to_time >= (DateTime.now.to_time + 5 * 60)
21
+ end
22
+
23
+ def start_time_in_words
24
+ distance = time_ago_in_words(start.date_time)
25
+ if already_started?
26
+ "#{distance} ago".bold.red
27
+ else
28
+ "in #{distance}".bold
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dotenv'
4
+ require 'google/apis/calendar_v3'
5
+ require 'action_view'
6
+ require 'action_view/helpers'
7
+ require 'colored'
8
+ require 'googleauth'
9
+ require 'googleauth/stores/file_token_store'
10
+ require 'fileutils'
11
+ require 'thor'
12
+ require 'os'
13
+
14
+ require_relative 'google/apis/calendar_v3/event'
15
+
16
+ module ZoomLauncher
17
+ autoload :CLI, 'zoom_launcher/cli'
18
+ autoload :GoogleAuth, 'zoom_launcher/google_auth'
19
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ZoomLauncher
4
+ class CLI < GoogleAuth
5
+ CALENDAR = 'primary'
6
+ ARGUMENTS = {
7
+ single_events: true,
8
+ order_by: 'startTime',
9
+ time_min: Time.now.iso8601,
10
+ q: 'zoom.us',
11
+ max_results: 5
12
+ }.freeze
13
+ default_task :launch
14
+
15
+ desc 'launch', 'Launch your next zoom meeting'
16
+ def launch
17
+ auth
18
+ if next_event.meeting_url
19
+ puts "Your next Zoom meeting is \"#{next_event.summary.bold}\"."
20
+ is_was = next_event.already_started? ? 'was' : 'is'
21
+ puts "It #{is_was} scheduled to start #{next_event.start_time_in_words}."
22
+ puts
23
+
24
+ if next_event.more_than_five_minutes_from_now?
25
+ puts "Here's the Zoom URL: #{next_event.meeting_url.bold}"
26
+ else
27
+ puts "Opening #{next_event.meeting_url.bold}..."
28
+ `open #{next_event.meeting_url}`
29
+
30
+ end
31
+ puts "Oh, and here's the URL in case you need it: #{next_event.html_link}"
32
+ else
33
+ puts "Can't find any upcomming Zoom meetings"
34
+ end
35
+ end
36
+
37
+ desc 'auth', 'authorize CLI with Google Calendar'
38
+ def auth
39
+ calendar.authorization = user_credentials_for(
40
+ Google::Apis::CalendarV3::AUTH_CALENDAR
41
+ )
42
+ end
43
+
44
+ desc 'logout', 'Deauthorize this computer from accessing your calendar'
45
+ def logout
46
+ FileUtils.rm_rf token_store_path
47
+ end
48
+
49
+ no_commands do
50
+ def calendar
51
+ @calendar ||= Google::Apis::CalendarV3::CalendarService.new
52
+ end
53
+
54
+ def events
55
+ @events ||= calendar.list_events(CALENDAR, ARGUMENTS)
56
+ end
57
+
58
+ def next_event
59
+ @next_event ||= events.items.first
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2016 Google Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ # Base command line module for samples. Provides authorization support,
18
+ # either using application default credentials or user authorization
19
+ # depending on the use case.
20
+ module ZoomLauncher
21
+ class GoogleAuth < Thor
22
+ include Thor::Actions
23
+
24
+ OOB_URI = 'urn:ietf:wg:oauth:2.0:oob'
25
+
26
+ class_option :user, type: :string
27
+ class_option :api_key, type: :string
28
+
29
+ no_commands do
30
+ # Returns the path to the client_secrets.json file.
31
+ def client_secrets_path
32
+ return ENV['GOOGLE_CLIENT_SECRETS'] if ENV.key?('GOOGLE_CLIENT_SECRETS')
33
+ well_known_path_for('client_secrets.json')
34
+ end
35
+
36
+ # Returns the path to the token store.
37
+ def token_store_path
38
+ return ENV['GOOGLE_CREDENTIAL_STORE'] if ENV.key?('GOOGLE_CREDENTIAL_STORE')
39
+ well_known_path_for('credentials.yaml')
40
+ end
41
+
42
+ # Builds a path to a file in $HOME/.config/google (or %APPDATA%/google,
43
+ # on Windows)
44
+ def well_known_path_for(file)
45
+ if OS.windows?
46
+ dir = ENV.fetch('HOME') { ENV['APPDATA'] }
47
+ File.join(dir, 'google', file)
48
+ else
49
+ File.join(ENV['HOME'], '.config', 'google', file)
50
+ end
51
+ end
52
+
53
+ # Returns application credentials for the given scope.
54
+ def application_credentials_for(scope)
55
+ Google::Auth.get_application_default(scope)
56
+ end
57
+
58
+ # Returns user credentials for the given scope. Requests authorization
59
+ # if requrired.
60
+ def user_credentials_for(scope)
61
+ FileUtils.mkdir_p(File.dirname(token_store_path))
62
+
63
+ client_id = if ENV['GOOGLE_CLIENT_ID']
64
+ Google::Auth::ClientId.new(ENV['GOOGLE_CLIENT_ID'], ENV['GOOGLE_CLIENT_SECRET'])
65
+ else
66
+ Google::Auth::ClientId.from_file(client_secrets_path)
67
+ end
68
+ token_store = Google::Auth::Stores::FileTokenStore.new(file: token_store_path)
69
+ authorizer = Google::Auth::UserAuthorizer.new(client_id, scope, token_store)
70
+
71
+ user_id = options[:user] || 'default'
72
+
73
+ credentials = authorizer.get_credentials(user_id)
74
+ if credentials.nil?
75
+ url = authorizer.get_authorization_url(base_url: OOB_URI)
76
+ `open #{url}`
77
+ code = ask 'Enter the authorization code:'
78
+ credentials = authorizer.get_and_store_credentials_from_code(
79
+ user_id: user_id, code: code, base_url: OOB_URI
80
+ )
81
+ end
82
+ credentials
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ZoomLauncher
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,3 @@
1
+ #!/bin/sh
2
+
3
+ bundle install
@@ -0,0 +1,7 @@
1
+ #!/bin/sh
2
+
3
+ set -e
4
+
5
+ bundle exec rspec
6
+ bundle exec rubocop -S -D
7
+ bundle exec gem build zoom_launcher.gemspec
@@ -0,0 +1,4 @@
1
+ #!/bin/sh
2
+
3
+ script/bootstrap
4
+ bin/zoom auth
@@ -0,0 +1,37 @@
1
+ # coding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ lib = File.expand_path('../lib', __FILE__)
5
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
+ require 'zoom_launcher/version'
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = 'zoom_launcher'
10
+ spec.version = ZoomLauncher::VERSION
11
+ spec.authors = ['Ben Balter']
12
+ spec.email = ['ben.balter@github.com']
13
+
14
+ spec.summary = 'A command line tool for joining your next Zoom meeting'
15
+ spec.homepage = "https://github.com/benbalter/zoom-launcher"
16
+ spec.license = 'MIT'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
+ f.match(%r{^(test|spec|features)/})
20
+ end
21
+ spec.bindir = 'bin'
22
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
23
+ spec.require_paths = ['lib']
24
+
25
+ spec.add_dependency 'actionview', '~> 5.0'
26
+ spec.add_dependency 'colored', '~> 1.2'
27
+ spec.add_dependency 'dotenv', '~> 2.2'
28
+ spec.add_dependency 'google-api-client', '~> 0.10'
29
+ spec.add_dependency 'os', '~> 0.9'
30
+ spec.add_dependency 'thor', '~> 0.19'
31
+ spec.add_development_dependency 'bundler', '~> 1.14'
32
+ spec.add_development_dependency 'rake', '~> 10.0'
33
+ spec.add_development_dependency 'rspec', '~> 3.0'
34
+ spec.add_development_dependency 'rubocop', '~> 0.48'
35
+ spec.add_development_dependency 'webmock', '~> 2.3'
36
+ spec.add_development_dependency 'timecop', '~> 0.8'
37
+ end
metadata ADDED
@@ -0,0 +1,229 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: zoom_launcher
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ben Balter
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-03-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: actionview
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: colored
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: dotenv
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.2'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: google-api-client
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.10'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.10'
69
+ - !ruby/object:Gem::Dependency
70
+ name: os
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.9'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.9'
83
+ - !ruby/object:Gem::Dependency
84
+ name: thor
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.19'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.19'
97
+ - !ruby/object:Gem::Dependency
98
+ name: bundler
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.14'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.14'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '10.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '10.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '3.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '3.0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rubocop
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '0.48'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '0.48'
153
+ - !ruby/object:Gem::Dependency
154
+ name: webmock
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '2.3'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '2.3'
167
+ - !ruby/object:Gem::Dependency
168
+ name: timecop
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '0.8'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '0.8'
181
+ description:
182
+ email:
183
+ - ben.balter@github.com
184
+ executables:
185
+ - zoom
186
+ extensions: []
187
+ extra_rdoc_files: []
188
+ files:
189
+ - ".gitignore"
190
+ - ".rspec"
191
+ - ".rubocop.yml"
192
+ - Gemfile
193
+ - LICENSE.md
194
+ - README.md
195
+ - bin/zoom
196
+ - lib/google/apis/calendar_v3/event.rb
197
+ - lib/zoom_launcher.rb
198
+ - lib/zoom_launcher/cli.rb
199
+ - lib/zoom_launcher/google_auth.rb
200
+ - lib/zoom_launcher/version.rb
201
+ - script/bootstrap
202
+ - script/cibuild
203
+ - script/setup
204
+ - zoom_launcher.gemspec
205
+ homepage: https://github.com/benbalter/zoom-launcher
206
+ licenses:
207
+ - MIT
208
+ metadata: {}
209
+ post_install_message:
210
+ rdoc_options: []
211
+ require_paths:
212
+ - lib
213
+ required_ruby_version: !ruby/object:Gem::Requirement
214
+ requirements:
215
+ - - ">="
216
+ - !ruby/object:Gem::Version
217
+ version: '0'
218
+ required_rubygems_version: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
223
+ requirements: []
224
+ rubyforge_project:
225
+ rubygems_version: 2.6.11
226
+ signing_key:
227
+ specification_version: 4
228
+ summary: A command line tool for joining your next Zoom meeting
229
+ test_files: []