calendar-assistant 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +152 -67
- data/Rakefile +13 -3
- data/bin/calendar-assistant +3 -1
- data/lib/calendar_assistant.rb +0 -1
- data/lib/calendar_assistant/calendar_assistant.rb +16 -14
- data/lib/calendar_assistant/cli.rb +9 -233
- data/lib/calendar_assistant/cli/authorizer.rb +88 -0
- data/lib/calendar_assistant/cli/commands.rb +284 -0
- data/lib/calendar_assistant/cli/config.rb +51 -0
- data/lib/calendar_assistant/cli/event_presenter.rb +71 -0
- data/lib/calendar_assistant/cli/event_set_presenter.rb +69 -0
- data/lib/calendar_assistant/cli/helpers.rb +54 -0
- data/lib/calendar_assistant/cli/linter_event_presenter.rb +56 -0
- data/lib/calendar_assistant/cli/linter_event_set_presenter.rb +23 -0
- data/lib/calendar_assistant/cli/printer.rb +90 -0
- data/lib/calendar_assistant/config.rb +21 -45
- data/lib/calendar_assistant/event.rb +16 -12
- data/lib/calendar_assistant/event_repository.rb +18 -9
- data/lib/calendar_assistant/event_repository_factory.rb +2 -2
- data/lib/calendar_assistant/version.rb +1 -1
- metadata +78 -38
- data/lib/calendar_assistant/authorizer.rb +0 -86
- data/lib/calendar_assistant/cli_helpers.rb +0 -228
@@ -1,233 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
option CalendarAssistant::Config::Keys::Options::LOCAL_STORE,
|
12
|
-
type: :string,
|
13
|
-
banner: "FILENAME",
|
14
|
-
desc: "Load events from a local file instead of Google Calendar"
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.has_attendees
|
18
|
-
option CalendarAssistant::Config::Keys::Options::ATTENDEES,
|
19
|
-
type: :string,
|
20
|
-
banner: "ATTENDEE1[,ATTENDEE2[,...]]",
|
21
|
-
desc: "[default 'me'] people (email IDs) to whom this command will be applied",
|
22
|
-
aliases: ["-a"]
|
23
|
-
end
|
24
|
-
|
25
|
-
default_config = CalendarAssistant::Config.new options: options # used in option descriptions
|
26
|
-
|
27
|
-
class_option :help,
|
28
|
-
type: :boolean,
|
29
|
-
aliases: ["-h", "-?"]
|
30
|
-
class_option CalendarAssistant::Config::Keys::Options::DEBUG,
|
31
|
-
type: :boolean,
|
32
|
-
desc: "how dare you suggest there are bugs"
|
33
|
-
|
34
|
-
|
35
|
-
desc "version",
|
36
|
-
"Display the version of calendar-assistant"
|
37
|
-
def version
|
38
|
-
return if handle_help_args
|
39
|
-
out.puts CalendarAssistant::VERSION
|
40
|
-
end
|
41
|
-
|
42
|
-
|
43
|
-
desc "config",
|
44
|
-
"Dump your configuration parameters (merge of defaults and overrides from #{CalendarAssistant::Config::CONFIG_FILE_PATH})"
|
45
|
-
def config
|
46
|
-
return if handle_help_args
|
47
|
-
settings = CalendarAssistant::Config.new.settings
|
48
|
-
out.puts TOML::Generator.new({CalendarAssistant::Config::Keys::SETTINGS => settings}).body
|
49
|
-
end
|
50
|
-
|
51
|
-
|
52
|
-
desc "setup",
|
53
|
-
"Link your local calendar-assistant installation to a Google API Client"
|
54
|
-
long_desc <<~EOD
|
55
|
-
This command will walk you through setting up a Google Cloud
|
56
|
-
Project, enabling the Google Calendar API, and saving the
|
57
|
-
credentials necessary to access the API on behalf of users.
|
58
|
-
|
59
|
-
If you already have downloaded client credentials, you don't
|
60
|
-
need to run this command. Instead, rename the downloaded JSON
|
61
|
-
file to `#{CalendarAssistant::Authorizer::CREDENTIALS_PATH}`
|
62
|
-
EOD
|
63
|
-
def setup
|
64
|
-
# TODO ugh see #34 for advice on how to clean this up
|
65
|
-
return if handle_help_args
|
66
|
-
if File.exist? CalendarAssistant::Authorizer::CREDENTIALS_PATH
|
67
|
-
out.puts sprintf("Credentials already exist in %s",
|
68
|
-
CalendarAssistant::Authorizer::CREDENTIALS_PATH)
|
69
|
-
return
|
70
|
-
end
|
71
|
-
|
72
|
-
out.launch "https://developers.google.com/calendar/quickstart/ruby"
|
73
|
-
sleep 1
|
74
|
-
out.puts <<~EOT
|
75
|
-
Please click on "ENABLE THE GOOGLE CALENDAR API" and either create a new project or select an existing project.
|
76
|
-
|
77
|
-
(If you create a new project, name it something like "yourname-calendar-assistant" so you remember why it exists.)
|
78
|
-
|
79
|
-
Then click "DOWNLOAD CLIENT CONFIGURATION" to download the credentials to local disk.
|
80
|
-
|
81
|
-
Finally, paste the contents of the downloaded file here (it should be a complete JSON object):
|
82
|
-
EOT
|
83
|
-
|
84
|
-
json = out.prompt "Paste JSON here"
|
85
|
-
File.open(CalendarAssistant::Authorizer::CREDENTIALS_PATH, "w") do |f|
|
86
|
-
f.write json
|
87
|
-
end
|
88
|
-
FileUtils.chmod 0600, CalendarAssistant::Authorizer::CREDENTIALS_PATH
|
89
|
-
|
90
|
-
out.puts "\nOK! Your next step is to run `calendar-assistant authorize`."
|
91
|
-
end
|
92
|
-
|
93
|
-
|
94
|
-
desc "authorize PROFILE_NAME",
|
95
|
-
"create (or validate) a profile named NAME with calendar access"
|
96
|
-
long_desc <<~EOD
|
97
|
-
Create and authorize a named profile (e.g., "work", "home",
|
98
|
-
"flastname@company.tld") to access your calendar.
|
99
|
-
|
100
|
-
When setting up a profile, you'll be asked to visit a URL to
|
101
|
-
authenticate, grant authorization, and generate and persist an
|
102
|
-
access token.
|
103
|
-
|
104
|
-
In order for this to work, you'll need to have set up your API client
|
105
|
-
credentials. Run `calendar-assistant help setup` for instructions.
|
106
|
-
EOD
|
107
|
-
def authorize profile_name=nil
|
108
|
-
return if handle_help_args
|
109
|
-
return help! if profile_name.nil?
|
110
|
-
|
111
|
-
CalendarAssistant.authorize profile_name
|
112
|
-
puts "\nYou're authorized!\n\n"
|
113
|
-
end
|
114
|
-
|
115
|
-
|
116
|
-
desc "show [DATE | DATERANGE | TIMERANGE]",
|
117
|
-
"Show your events for a date or range of dates (default 'today')"
|
118
|
-
option CalendarAssistant::Config::Keys::Options::COMMITMENTS,
|
119
|
-
type: :boolean,
|
120
|
-
desc: "only show events that you've accepted with another person",
|
121
|
-
aliases: ["-c"]
|
122
|
-
will_create_a_service
|
123
|
-
has_attendees
|
124
|
-
def show datespec="today"
|
125
|
-
return if handle_help_args
|
126
|
-
config = CalendarAssistant::Config.new(options: options)
|
127
|
-
ca = CalendarAssistant.new config
|
128
|
-
ca.in_env do
|
129
|
-
event_set = ca.find_events CLIHelpers.parse_datespec(datespec)
|
130
|
-
out.print_events ca, event_set
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
|
135
|
-
desc "join [TIME]",
|
136
|
-
"Open the URL for a video call attached to your meeting at time TIME (default 'now')"
|
137
|
-
option CalendarAssistant::Config::Keys::Options::JOIN,
|
138
|
-
type: :boolean, default: true,
|
139
|
-
desc: "launch a browser to join the video call URL"
|
140
|
-
will_create_a_service
|
141
|
-
def join timespec="now"
|
142
|
-
return if handle_help_args
|
143
|
-
ca = CalendarAssistant.new CalendarAssistant::Config.new(options: options)
|
144
|
-
ca.in_env do
|
145
|
-
event_set, url = CLIHelpers.find_av_uri ca, timespec
|
146
|
-
if ! event_set.empty?
|
147
|
-
out.print_events ca, event_set
|
148
|
-
out.puts url
|
149
|
-
out.launch url if options[CalendarAssistant::Config::Keys::Options::JOIN]
|
150
|
-
else
|
151
|
-
out.puts "Could not find a meeting '#{timespec}' with a video call to join."
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
|
157
|
-
desc "location [DATE | DATERANGE]",
|
158
|
-
"Show your location for a date or range of dates (default 'today')"
|
159
|
-
will_create_a_service
|
160
|
-
def location datespec="today"
|
161
|
-
return if handle_help_args
|
162
|
-
ca = CalendarAssistant.new CalendarAssistant::Config.new(options: options)
|
163
|
-
ca.in_env do
|
164
|
-
event_set = ca.find_location_events CLIHelpers.parse_datespec(datespec)
|
165
|
-
out.print_events ca, event_set
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
|
170
|
-
desc "location-set LOCATION [DATE | DATERANGE]",
|
171
|
-
"Set your location to LOCATION for a date or range of dates (default 'today')"
|
172
|
-
will_create_a_service
|
173
|
-
def location_set location=nil, datespec="today"
|
174
|
-
return if handle_help_args
|
175
|
-
return help! if location.nil?
|
176
|
-
|
177
|
-
ca = CalendarAssistant.new CalendarAssistant::Config.new(options: options)
|
178
|
-
ca.in_env do
|
179
|
-
event_set = ca.create_location_event CLIHelpers.parse_datespec(datespec), location
|
180
|
-
out.print_events ca, event_set
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
|
185
|
-
desc "availability [DATE | DATERANGE | TIMERANGE]",
|
186
|
-
"Show your availability for a date or range of dates (default 'today')"
|
187
|
-
option CalendarAssistant::Config::Keys::Settings::MEETING_LENGTH,
|
188
|
-
type: :string,
|
189
|
-
banner: "LENGTH",
|
190
|
-
desc: sprintf("[default %s] find chunks of available time at least as long as LENGTH (which is a ChronicDuration string like '30m' or '2h')",
|
191
|
-
default_config.setting(CalendarAssistant::Config::Keys::Settings::MEETING_LENGTH)),
|
192
|
-
aliases: ["-l"]
|
193
|
-
option CalendarAssistant::Config::Keys::Settings::START_OF_DAY,
|
194
|
-
type: :string,
|
195
|
-
banner: "TIME",
|
196
|
-
desc: sprintf("[default %s] find chunks of available time after TIME (which is a BusinessTime string like '9am' or '14:30')",
|
197
|
-
default_config.setting(CalendarAssistant::Config::Keys::Settings::START_OF_DAY)),
|
198
|
-
aliases: ["-s"]
|
199
|
-
option CalendarAssistant::Config::Keys::Settings::END_OF_DAY,
|
200
|
-
type: :string,
|
201
|
-
banner: "TIME",
|
202
|
-
desc: sprintf("[default %s] find chunks of available time before TIME (which is a BusinessTime string like '9am' or '14:30')",
|
203
|
-
default_config.setting(CalendarAssistant::Config::Keys::Settings::END_OF_DAY)),
|
204
|
-
aliases: ["-e"]
|
205
|
-
has_attendees
|
206
|
-
will_create_a_service
|
207
|
-
def availability datespec="today"
|
208
|
-
return if handle_help_args
|
209
|
-
ca = CalendarAssistant.new CalendarAssistant::Config.new(options: options)
|
210
|
-
ca.in_env do
|
211
|
-
event_set = ca.availability CLIHelpers.parse_datespec(datespec)
|
212
|
-
out.print_available_blocks ca, event_set
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
private
|
217
|
-
|
218
|
-
def out
|
219
|
-
@out ||= CLIHelpers::Out.new
|
220
|
-
end
|
221
|
-
|
222
|
-
def help!
|
223
|
-
help(current_command_chain.first)
|
224
|
-
end
|
225
|
-
|
226
|
-
def handle_help_args
|
227
|
-
if options[:help]
|
228
|
-
help!
|
229
|
-
return true
|
230
|
-
end
|
231
|
-
end
|
232
|
-
end
|
233
|
-
end
|
1
|
+
require_relative 'cli/config'
|
2
|
+
require_relative 'cli/helpers'
|
3
|
+
require_relative 'cli/printer'
|
4
|
+
require_relative 'cli/event_presenter'
|
5
|
+
require_relative 'cli/event_set_presenter'
|
6
|
+
require_relative 'cli/linter_event_presenter'
|
7
|
+
require_relative 'cli/linter_event_set_presenter'
|
8
|
+
require_relative 'cli/authorizer'
|
9
|
+
require_relative 'cli/commands'
|
@@ -0,0 +1,88 @@
|
|
1
|
+
#
|
2
|
+
# code in this file is inspired by
|
3
|
+
#
|
4
|
+
# https://github.com/gsuitedevs/ruby-samples/blob/master/calendar/quickstart/quickstart.rb
|
5
|
+
#
|
6
|
+
# Copyright 2018 Google LLC
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
9
|
+
# you may not use this file except in compliance with the License.
|
10
|
+
# You may obtain a copy of the License at
|
11
|
+
#
|
12
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
16
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
17
|
+
# See the License for the specific language governing permissions and
|
18
|
+
# limitations under the License.
|
19
|
+
|
20
|
+
class CalendarAssistant
|
21
|
+
module CLI
|
22
|
+
class Authorizer
|
23
|
+
class NoCredentials < CalendarAssistant::BaseException ; end
|
24
|
+
class UnauthorizedError < CalendarAssistant::BaseException ; end
|
25
|
+
|
26
|
+
OOB_URI = 'urn:ietf:wg:oauth:2.0:oob'.freeze
|
27
|
+
APPLICATION_NAME = "Flavorjones Calendar Assistant".freeze
|
28
|
+
CREDENTIALS_PATH = File.join (ENV['CA_HOME'] || ENV["HOME"]), ".calendar-assistant.client"
|
29
|
+
SCOPE = Google::Apis::CalendarV3::AUTH_CALENDAR
|
30
|
+
|
31
|
+
attr_reader :profile_name, :config_token_store
|
32
|
+
|
33
|
+
def initialize profile_name, config_token_store
|
34
|
+
@profile_name = profile_name
|
35
|
+
@config_token_store = config_token_store
|
36
|
+
end
|
37
|
+
|
38
|
+
def authorize
|
39
|
+
credentials || prompt_user_for_authorization
|
40
|
+
end
|
41
|
+
|
42
|
+
def service
|
43
|
+
if credentials.nil?
|
44
|
+
raise UnauthorizedError, "Not authorized. Please run `calendar-assistant authorize #{profile_name}`"
|
45
|
+
end
|
46
|
+
|
47
|
+
Google::Apis::CalendarV3::CalendarService.new.tap do |service|
|
48
|
+
service.client_options.application_name = APPLICATION_NAME
|
49
|
+
service.authorization = credentials
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def credentials
|
56
|
+
@credentials ||= authorizer.get_credentials profile_name
|
57
|
+
end
|
58
|
+
|
59
|
+
def prompt_user_for_authorization
|
60
|
+
url = authorizer.get_authorization_url(base_url: OOB_URI)
|
61
|
+
|
62
|
+
puts Rainbow("Please open this URL in your browser:").bold
|
63
|
+
puts
|
64
|
+
puts " " + url
|
65
|
+
puts
|
66
|
+
|
67
|
+
puts Rainbow("Then authorize '#{APPLICATION_NAME}' to manage your calendar and copy/paste the resulting code here:").bold
|
68
|
+
puts
|
69
|
+
print "> "
|
70
|
+
code = STDIN.gets
|
71
|
+
|
72
|
+
authorizer.get_and_store_credentials_from_code(user_id: profile_name, code: code, base_url: OOB_URI)
|
73
|
+
end
|
74
|
+
|
75
|
+
def authorizer
|
76
|
+
@authorizer ||= begin
|
77
|
+
if ! File.exists?(CREDENTIALS_PATH)
|
78
|
+
raise NoCredentials, "No credentials found. Please run `calendar-assistant help setup` for instructions"
|
79
|
+
end
|
80
|
+
|
81
|
+
FileUtils.chmod 0600, CREDENTIALS_PATH
|
82
|
+
client_id = Google::Auth::ClientId.from_file(CREDENTIALS_PATH)
|
83
|
+
Google::Auth::UserAuthorizer.new(client_id, SCOPE, config_token_store)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,284 @@
|
|
1
|
+
require "calendar_assistant/cli/helpers"
|
2
|
+
|
3
|
+
class CalendarAssistant
|
4
|
+
module CLI
|
5
|
+
class Commands < Thor
|
6
|
+
def self.will_create_a_service
|
7
|
+
option CalendarAssistant::Config::Keys::Settings::PROFILE,
|
8
|
+
type: :string,
|
9
|
+
desc: "the profile you'd like to use (if different from default)",
|
10
|
+
aliases: ["-p"]
|
11
|
+
|
12
|
+
option CalendarAssistant::Config::Keys::Options::LOCAL_STORE,
|
13
|
+
type: :string,
|
14
|
+
banner: "FILENAME",
|
15
|
+
desc: "Load events from a local file instead of Google Calendar"
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.has_attendees
|
19
|
+
option CalendarAssistant::Config::Keys::Options::ATTENDEES,
|
20
|
+
type: :string,
|
21
|
+
banner: "ATTENDEE1[,ATTENDEE2[,...]]",
|
22
|
+
desc: "[default 'me'] people (email IDs) to whom this command will be applied",
|
23
|
+
aliases: ["-a"]
|
24
|
+
end
|
25
|
+
|
26
|
+
default_config = CalendarAssistant::CLI::Config.new options: options # used in option descriptions
|
27
|
+
|
28
|
+
class_option :help,
|
29
|
+
type: :boolean,
|
30
|
+
aliases: ["-h", "-?"]
|
31
|
+
class_option CalendarAssistant::Config::Keys::Options::DEBUG,
|
32
|
+
type: :boolean,
|
33
|
+
desc: "how dare you suggest there are bugs"
|
34
|
+
|
35
|
+
class_option CalendarAssistant::Config::Keys::Options::FORMATTING,
|
36
|
+
type: :boolean,
|
37
|
+
desc: "Enable Text Formatting",
|
38
|
+
default: CalendarAssistant::Config::DEFAULT_SETTINGS[CalendarAssistant::Config::Keys::Options::FORMATTING]
|
39
|
+
|
40
|
+
desc "version",
|
41
|
+
"Display the version of calendar-assistant"
|
42
|
+
|
43
|
+
def version
|
44
|
+
return if handle_help_args
|
45
|
+
out.puts CalendarAssistant::VERSION
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
desc "config",
|
50
|
+
"Dump your configuration parameters (merge of defaults and overrides from #{CalendarAssistant::CLI::Config::CONFIG_FILE_PATH})"
|
51
|
+
|
52
|
+
def config
|
53
|
+
return if handle_help_args
|
54
|
+
settings = CalendarAssistant::CLI::Config.new.settings
|
55
|
+
out.puts TOML::Generator.new({CalendarAssistant::Config::Keys::SETTINGS => settings}).body
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
desc "setup",
|
60
|
+
"Link your local calendar-assistant installation to a Google API Client"
|
61
|
+
long_desc <<~EOD
|
62
|
+
This command will walk you through setting up a Google Cloud
|
63
|
+
Project, enabling the Google Calendar API, and saving the
|
64
|
+
credentials necessary to access the API on behalf of users.
|
65
|
+
|
66
|
+
If you already have downloaded client credentials, you don't
|
67
|
+
need to run this command. Instead, rename the downloaded JSON
|
68
|
+
file to `#{CalendarAssistant::CLI::Authorizer::CREDENTIALS_PATH}`
|
69
|
+
EOD
|
70
|
+
|
71
|
+
def setup
|
72
|
+
# TODO ugh see #34 for advice on how to clean this up
|
73
|
+
return if handle_help_args
|
74
|
+
if File.exist? CalendarAssistant::CLI::Authorizer::CREDENTIALS_PATH
|
75
|
+
out.puts sprintf("Credentials already exist in %s",
|
76
|
+
CalendarAssistant::CLI::Authorizer::CREDENTIALS_PATH)
|
77
|
+
return
|
78
|
+
end
|
79
|
+
|
80
|
+
out.launch "https://developers.google.com/calendar/quickstart/ruby"
|
81
|
+
sleep 1
|
82
|
+
out.puts <<~EOT
|
83
|
+
Please click on "ENABLE THE GOOGLE CALENDAR API" and either create a new project or select an existing project.
|
84
|
+
|
85
|
+
(If you create a new project, name it something like "yourname-calendar-assistant" so you remember why it exists.)
|
86
|
+
|
87
|
+
Then click "DOWNLOAD CLIENT CONFIGURATION" to download the credentials to local disk.
|
88
|
+
|
89
|
+
Finally, paste the contents of the downloaded file here (it should be a complete JSON object):
|
90
|
+
EOT
|
91
|
+
|
92
|
+
json = out.prompt "Paste JSON here"
|
93
|
+
File.open(CalendarAssistant::CLI::Authorizer::CREDENTIALS_PATH, "w") do |f|
|
94
|
+
f.write json
|
95
|
+
end
|
96
|
+
FileUtils.chmod 0600, CalendarAssistant::CLI::Authorizer::CREDENTIALS_PATH
|
97
|
+
|
98
|
+
out.puts "\nOK! Your next step is to run `calendar-assistant authorize`."
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
desc "authorize PROFILE_NAME",
|
103
|
+
"create (or validate) a profile named NAME with calendar access"
|
104
|
+
long_desc <<~EOD
|
105
|
+
Create and authorize a named profile (e.g., "work", "home",
|
106
|
+
"flastname@company.tld") to access your calendar.
|
107
|
+
|
108
|
+
When setting up a profile, you'll be asked to visit a URL to
|
109
|
+
authenticate, grant authorization, and generate and persist an
|
110
|
+
access token.
|
111
|
+
|
112
|
+
In order for this to work, you'll need to have set up your API client
|
113
|
+
credentials. Run `calendar-assistant help setup` for instructions.
|
114
|
+
EOD
|
115
|
+
|
116
|
+
def authorize profile_name = nil
|
117
|
+
return if handle_help_args
|
118
|
+
return help! if profile_name.nil?
|
119
|
+
|
120
|
+
get_authorizer(profile_name: profile_name).authorize
|
121
|
+
|
122
|
+
puts "\nYou're authorized!\n\n"
|
123
|
+
end
|
124
|
+
|
125
|
+
desc "lint [DATE | DATERANGE | TIMERANGE]",
|
126
|
+
"Lint your events for a date or range of dates (default 'today')"
|
127
|
+
will_create_a_service
|
128
|
+
has_attendees
|
129
|
+
|
130
|
+
def lint datespec = "today"
|
131
|
+
calendar_assistant(datespec) do |ca, date|
|
132
|
+
event_set = ca.lint_events date
|
133
|
+
out.print_events ca, event_set, presenter_class: CalendarAssistant::CLI::LinterEventSetPresenter
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
desc "show [DATE | DATERANGE | TIMERANGE]",
|
138
|
+
"Show your events for a date or range of dates (default 'today')"
|
139
|
+
option CalendarAssistant::Config::Keys::Options::COMMITMENTS,
|
140
|
+
type: :boolean,
|
141
|
+
desc: "only show events that you've accepted with another person",
|
142
|
+
aliases: ["-c"]
|
143
|
+
will_create_a_service
|
144
|
+
has_attendees
|
145
|
+
|
146
|
+
def show datespec = "today"
|
147
|
+
calendar_assistant(datespec) do |ca, date|
|
148
|
+
event_set = ca.find_events date
|
149
|
+
out.print_events ca, event_set
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
desc "join [TIME]",
|
155
|
+
"Open the URL for a video call attached to your meeting at time TIME (default 'now')"
|
156
|
+
option CalendarAssistant::Config::Keys::Options::JOIN,
|
157
|
+
type: :boolean, default: true,
|
158
|
+
desc: "launch a browser to join the video call URL"
|
159
|
+
will_create_a_service
|
160
|
+
|
161
|
+
def join timespec = "now"
|
162
|
+
return if handle_help_args
|
163
|
+
set_formatting
|
164
|
+
ca = CalendarAssistant.new get_config, service: service
|
165
|
+
ca.in_env do
|
166
|
+
event_set, url = CalendarAssistant::CLI::Helpers.find_av_uri ca, timespec
|
167
|
+
if !event_set.empty?
|
168
|
+
out.print_events ca, event_set
|
169
|
+
out.puts url
|
170
|
+
out.launch url if options[CalendarAssistant::Config::Keys::Options::JOIN]
|
171
|
+
else
|
172
|
+
out.puts "Could not find a meeting '#{timespec}' with a video call to join."
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
|
178
|
+
desc "location [DATE | DATERANGE]",
|
179
|
+
"Show your location for a date or range of dates (default 'today')"
|
180
|
+
will_create_a_service
|
181
|
+
|
182
|
+
def location datespec = "today"
|
183
|
+
calendar_assistant(datespec) do |ca, date|
|
184
|
+
event_set = ca.find_location_events date
|
185
|
+
out.print_events ca, event_set
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
|
190
|
+
desc "location-set LOCATION [DATE | DATERANGE]",
|
191
|
+
"Set your location to LOCATION for a date or range of dates (default 'today')"
|
192
|
+
will_create_a_service
|
193
|
+
|
194
|
+
def location_set location = nil, datespec = "today"
|
195
|
+
return help! if location.nil?
|
196
|
+
|
197
|
+
calendar_assistant(datespec) do |ca, date|
|
198
|
+
event_set = ca.create_location_event date, location
|
199
|
+
out.print_events ca, event_set
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
|
204
|
+
desc "availability [DATE | DATERANGE | TIMERANGE]",
|
205
|
+
"Show your availability for a date or range of dates (default 'today')"
|
206
|
+
option CalendarAssistant::Config::Keys::Settings::MEETING_LENGTH,
|
207
|
+
type: :string,
|
208
|
+
banner: "LENGTH",
|
209
|
+
desc: sprintf("[default %s] find chunks of available time at least as long as LENGTH (which is a ChronicDuration string like '30m' or '2h')",
|
210
|
+
default_config.setting(CalendarAssistant::Config::Keys::Settings::MEETING_LENGTH)),
|
211
|
+
aliases: ["-l"]
|
212
|
+
option CalendarAssistant::Config::Keys::Settings::START_OF_DAY,
|
213
|
+
type: :string,
|
214
|
+
banner: "TIME",
|
215
|
+
desc: sprintf("[default %s] find chunks of available time after TIME (which is a BusinessTime string like '9am' or '14:30')",
|
216
|
+
default_config.setting(CalendarAssistant::Config::Keys::Settings::START_OF_DAY)),
|
217
|
+
aliases: ["-s"]
|
218
|
+
option CalendarAssistant::Config::Keys::Settings::END_OF_DAY,
|
219
|
+
type: :string,
|
220
|
+
banner: "TIME",
|
221
|
+
desc: sprintf("[default %s] find chunks of available time before TIME (which is a BusinessTime string like '9am' or '14:30')",
|
222
|
+
default_config.setting(CalendarAssistant::Config::Keys::Settings::END_OF_DAY)),
|
223
|
+
aliases: ["-e"]
|
224
|
+
has_attendees
|
225
|
+
will_create_a_service
|
226
|
+
|
227
|
+
def availability datespec = "today"
|
228
|
+
calendar_assistant(datespec) do |ca, date|
|
229
|
+
event_set = ca.availability date
|
230
|
+
out.print_available_blocks ca, event_set
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
private
|
235
|
+
|
236
|
+
def set_formatting
|
237
|
+
Rainbow.enabled = !!options[:formatting]
|
238
|
+
end
|
239
|
+
|
240
|
+
def service
|
241
|
+
@service ||= begin
|
242
|
+
if filename = get_config.setting(Config::Keys::Options::LOCAL_STORE)
|
243
|
+
CalendarAssistant::LocalService.new(file: filename)
|
244
|
+
else
|
245
|
+
get_authorizer.service
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def get_authorizer(profile_name: get_config.profile_name, token_store: get_config.token_store)
|
251
|
+
@authorizer ||= {}
|
252
|
+
@authorizer[profile_name] ||= Authorizer.new(profile_name, token_store)
|
253
|
+
end
|
254
|
+
|
255
|
+
def calendar_assistant datespec = "today"
|
256
|
+
return if handle_help_args
|
257
|
+
set_formatting
|
258
|
+
ca = CalendarAssistant.new(get_config, service: service)
|
259
|
+
ca.in_env do
|
260
|
+
yield(ca, CalendarAssistant::CLI::Helpers.parse_datespec(datespec))
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
def get_config
|
265
|
+
@config ||= CalendarAssistant::CLI::Config.new(options: options)
|
266
|
+
end
|
267
|
+
|
268
|
+
def out
|
269
|
+
@out ||= CalendarAssistant::CLI::Printer.new
|
270
|
+
end
|
271
|
+
|
272
|
+
def help!
|
273
|
+
help(current_command_chain.first)
|
274
|
+
end
|
275
|
+
|
276
|
+
def handle_help_args
|
277
|
+
if options[:help]
|
278
|
+
help!
|
279
|
+
return true
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|